Devlog #1129 – Destroy Walls On Level Finish 2/2


In my last posts we have end up with Unity ECS System responsible for detection that all player tasks are done. Now let’s continue with our jurney to reward player at the end of level and we would need to create system that will destroy all level walls and spawn some reward on their positions.

Systems

We will create for that purpose new system GameWonKillSystem. Purpose of this system will be to destroy all level walls.

    /**
     * System that checks if the game is won (all pellets collected within defined time) and if yes, it will kill all entities with GameWonKill component
     * without Kill component 
     */
    public partial struct GameWonKillSystem : ISystem
    {
        private EntityQuery query_GameWonKill;

Here is the OnCreate function of this system where is the place to define our queries to find entities this system is build for.

 query_GameWonKill = SystemAPI.QueryBuilder()
         .WithAll<GameWonKill, LocalTransform>()
         .WithNone<Kill>().Build();
  • Find Entities with GameWonKill component and LocalTransform. GameWonKill is attached to all walls to let them know that they should be killed (destroyed) at player won the level. LocalTransform is needed to get information about the Position of the wall to be killed, and then used to spawn some rewards.
  • WithNone<Kill> to exclude entities that are already prepared to be killed(destroyed).

all OnCreate function look like this:

OnCreate() method
        [BurstCompile]
        public void OnCreate(ref SystemState state)
        {
            query_GameWonKill = SystemAPI.QueryBuilder()
                .WithAll<GameWonKill, LocalTransform>()
                .WithNone<Kill>().Build();
            
            lookup_PolarOffset = SystemAPI.GetComponentLookup<TransformPolarOffset>();
            
            state.RequireForUpdate(query_GameWonKill);
            state.RequireForUpdate<EndSimulationEntityCommandBufferSystem.Singleton>();
            state.RequireForUpdate<CollectedAllPelletsWithinTimeLimitTag>();
        }
state.RequireForUpdate<CollectedAllPelletsWithinTimeLimitTag>();

We would need for Update also to have within game World also this special tag CollectedAllPelletsWithinTimeLimitTag that was created by GameWonSystem described in previous post. Now we can analyse OnUpdate() method. Here is the source code:

        [BurstCompile]
        public void OnUpdate(ref SystemState state)
        {
            if (!SystemAPI.TryGetSingleton<EndSimulationEntityCommandBufferSystem.Singleton>(out var ecb)) return;
            var ecp = ecb.CreateCommandBuffer(state.WorldUnmanaged).AsParallelWriter();
            
            lookup_PolarOffset.Update(ref state);
            new GameWonKillJob()
            {
                ecp = ecp,
                lookup_PolarOffset = lookup_PolarOffset,
            }.ScheduleParallel(query_GameWonKill, state.Dependency).Complete();


        }
  • EndSimulationEntityCommandBufferSystem.Singleton – This singleton entity is needed to schedule world modification like destroy entities, or attach components to them or update components.
  • lookup_PolarOffset.Update(ref state); – to update lookup to PolarOffset component list. We would need to use this to calculate where is the center of the wall and because walls in my game have circular maze so it is in Polar coordinates.
  • new GameWonKillJob(){} – this is the main Job to execute all the logic inside the system for each entity that is returned by query_GameWonKill.

GameWonKillJob

Now we need to create Unity Job that will be executed for each wall we need to destroy and execute destroy logic for each wall. In my case it is very easy we just need to add KillComponent to each wall we need to destroy and then other system responsible for killing entities will do its work. So here is the Job:

    [BurstCompile]
    public partial struct GameWonKillJob : IJobEntity 
    {
        public EntityCommandBuffer.ParallelWriter ecp;
        
        // Must be readonly, otherwise it will not compile
        [ReadOnly] public ComponentLookup<TransformPolarOffset> lookup_PolarOffset;

        
        public void Execute(in GameWonKill gameWonKill, in LocalTransform t, in Entity e,  [EntityIndexInChunk] int id)
        {
            var eventPosition = t.Position;
            if (lookup_PolarOffset.TryGetComponent(e, out var polarOffset))
                eventPosition = polarOffset.OffsetPosition(t);

            // Spawn reward spawner
            if (gameWonKill.RewardSpawner.IsValid)
            {
                 // here should be code to spawn reward spawner ...
            }

            ecp.AddComponent(id, e, gameWonKill.KillComponentDefinition);
        }
    }

ecp.AddComponent(id, e, gameWonKill.KillComponentDefinition); This command will schedule to addComponent to our Entity (Walls) and the definition of this component was define on gameWonKill.KillComponentDefinition but can be also specified directly like this:

ecp.AddComponent(id, e, new Kill());

Conclusion

Hope this helps you with your jurney with Unity Entity Component System to have better ideas about how to design systems and jobs.

, , ,