# 3. Entities Authoring, Baking and ISystem Part of [[DOTS]]. Previous: [[2. Jobs and Burst for GameObject Projects]]. Next: [[4. Worked Example - Swarm Enemies]]. > [!note] Verification status > These patterns match the Entities 6.5 manual examples (`Baker<T>`, `GetEntity(TransformUsageFlags.Dynamic)`, `ISystem`, `SystemAPI.Query<RefRW<>, RefRO<>>()`, `IJobEntity` must be `partial` and isn't Burst-compiled unless marked `[BurstCompile]`). **Code not compiled.** ## 3.1 Subscenes: where baking happens 1. In your scene: **right-click in the Hierarchy > New Sub Scene > Empty Scene**. Name it `GameplayEntities`. 2. GameObjects placed **inside the subscene** are **baked** into entities: in the editor when they change, and at build time. 3. GameObjects **outside** subscenes stay normal GameObjects (cameras, UI, audio, the player rig in a hybrid game). ## 3.2 A component and its authoring ```csharp // Assets/Scripts/DOTS/Spin/Spin.cs using Unity.Entities; public struct Spin : IComponentData { public float RadiansPerSecond; } ``` ```csharp // Assets/Scripts/DOTS/Spin/SpinAuthoring.cs using Unity.Entities; using Unity.Mathematics; using UnityEngine; public class SpinAuthoring : MonoBehaviour { public float degreesPerSecond = 90f; } public class SpinBaker : Baker<SpinAuthoring> { public override void Bake(SpinAuthoring authoring) { // Dynamic: this entity moves at runtime, so it needs LocalTransform + LocalToWorld. Entity entity = GetEntity(TransformUsageFlags.Dynamic); AddComponent(entity, new Spin { RadiansPerSecond = math.radians(authoring.degreesPerSecond) }); } } ``` **TransformUsageFlags** tell the baker which transform components you need: - `None`: no transform (data-only entities such as a config singleton). - `Renderable`: rendered but static. - `Dynamic`: moved at runtime. Asking only for what you use keeps chunks small. That's Data Locality again. ## 3.3 ISystem with SystemAPI.Query (main thread) ```csharp // Assets/Scripts/DOTS/Spin/SpinSystem.cs using Unity.Burst; using Unity.Entities; using Unity.Mathematics; using Unity.Transforms; [BurstCompile] public partial struct SpinSystem : ISystem { [BurstCompile] public void OnCreate(ref SystemState state) { state.RequireForUpdate<Spin>(); // don't run until at least one Spin exists } [BurstCompile] public void OnUpdate(ref SystemState state) { float dt = SystemAPI.Time.DeltaTime; foreach (var (transform, spin) in SystemAPI.Query<RefRW<LocalTransform>, RefRO<Spin>>()) { transform.ValueRW = transform.ValueRO.RotateY(spin.ValueRO.RadiansPerSecond * dt); } } } ``` - `partial`: source generators fill in the plumbing. - `RefRW` means read-write and `RefRO` means read-only. Declare intent honestly, because it drives job dependencies. - No `OnDestroy` is needed here (the method has a default implementation in `ISystem`). ## 3.4 The same work as a parallel IJobEntity ```csharp // Assets/Scripts/DOTS/Spin/SpinJobSystem.cs using Unity.Burst; using Unity.Entities; using Unity.Transforms; [BurstCompile] public partial struct SpinJob : IJobEntity { public float DeltaTime; // The parameters define the query: entities with LocalTransform (rw) and Spin (ro). void Execute(ref LocalTransform transform, in Spin spin) { transform = transform.RotateY(spin.RadiansPerSecond * DeltaTime); } } [BurstCompile] public partial struct SpinJobSystem : ISystem { [BurstCompile] public void OnCreate(ref SystemState state) => state.RequireForUpdate<Spin>(); [BurstCompile] public void OnUpdate(ref SystemState state) { // Uses and updates state.Dependency automatically. new SpinJob { DeltaTime = SystemAPI.Time.DeltaTime }.ScheduleParallel(); } } ``` Use only **one** of the two Spin systems, or the cube spins twice as fast. Delete `SpinSystem.cs` once the job version works. > [!tip] `[BurstCompile]` on the job > `IJobEntity` isn't Burst-compiled by default. Put `[BurstCompile]` on the job struct as well as on the system methods. ## 3.5 Singletons: config data ```csharp // Assets/Scripts/DOTS/Config/GameConfigAuthoring.cs using Unity.Entities; using UnityEngine; public struct GameConfig : IComponentData { public float EnemySpeedMultiplier; } public class GameConfigAuthoring : MonoBehaviour { public float enemySpeedMultiplier = 1f; } public class GameConfigBaker : Baker<GameConfigAuthoring> { public override void Bake(GameConfigAuthoring authoring) { Entity e = GetEntity(TransformUsageFlags.None); AddComponent(e, new GameConfig { EnemySpeedMultiplier = authoring.enemySpeedMultiplier }); } } ``` In a system: `state.RequireForUpdate<GameConfig>()` in `OnCreate`, then `SystemAPI.GetSingleton<GameConfig>()` in `OnUpdate`. This is the ECS cousin of the ScriptableObject config in [[ScriptableObject Architecture]], and a tidier alternative to the **Service Locator** pattern. ## 3.6 Enableable components as state flags ```csharp // Assets/Scripts/DOTS/States/Stunned.cs using Unity.Entities; public struct Stunned : IComponentData, IEnableableComponent { public float Remaining; } ``` ```csharp // Assets/Scripts/DOTS/States/StunTimerSystem.cs using Unity.Burst; using Unity.Entities; [BurstCompile] public partial struct StunTimerSystem : ISystem { [BurstCompile] public void OnUpdate(ref SystemState state) { float dt = SystemAPI.Time.DeltaTime; // Query only matches entities whose Stunned is ENABLED. foreach (var (stun, stunEnabled) in SystemAPI.Query<RefRW<Stunned>, EnabledRefRW<Stunned>>()) { stun.ValueRW.Remaining -= dt; if (stun.ValueRO.Remaining <= 0f) stunEnabled.ValueRW = false; // no structural change } } } ``` Bake `Stunned` onto enemies and then disable it immediately in the baker with `SetComponentEnabled<Stunned>(entity, false)`. A hit re-enables it and sets `Remaining`. Movement jobs then skip stunned enemies with `[WithDisabled(typeof(Stunned))]`, or with `WithNone<Stunned>()` in a `SystemAPI.Query` (which treats disabled as absent). This is an [[Enemy AI State Machine]] state, without archetype churn. ## Sources - Baker overview: https://docs.unity3d.com/Packages/[email protected]/manual/baking-baker-overview.html - ISystem: https://docs.unity3d.com/Packages/[email protected]/manual/systems-isystem.html - SystemAPI.Query: https://docs.unity3d.com/Packages/[email protected]/manual/systems-systemapi-query.html - IJobEntity: https://docs.unity3d.com/Packages/[email protected]/manual/iterating-data-ijobentity.html - Enableable components: https://docs.unity3d.com/Packages/[email protected]/manual/components-enableable.html - Transform usage flags: https://docs.unity3d.com/Packages/[email protected]/manual/transforms-usage-flags.html