Disable System temporary on single gameObject

Hello World,

I’m currently trying to port my game to the ecs hybrid system.

I started by splitting my different player movement into different System, for example Dash, Gravity, Jump, Movements.

I think it’s what ecs encourage me to do. Maybe i misunderstood the concept.

The problem is the following, when i’m dashing, i want my Gravity and my Movement system to pause.

I found those solutions in the forum :

    public class ComponentSys : ComponentSystem
    {
        [Inject] private SomeSystem someSystem;
    
        protected override void OnUpdate()
        {
            if (disableSomeSystem)
                someSystem.Enabled = false;
        }
    }
    public class SomeClass : MonoBehaviour
    {
        private void SomeMethod()
        {
            World.Active.GetExistingManager<SomeSystem>().Enabled = false;
        }
    }

But i don’t think it is what i’m looking for because i don’t want all of my game Gravity system to stop but only the player’s one. If i use this, my enemies will also have there Gravity paused.

I also tried to disable components (because my components are monobehaviour, they have a enable property) but it also didn’t worked.

Thanks by advance.

What you want to do is have some kind of component that the player has while the gravity system should work on him.

You need to forget that a system works for an entity (i.e. the player). They work for everything that has the correct components. You just need to define what the correct components are.

So maybe a IsAffectedByGravity Component is what you are searching for.

Ok, so i would have to create a Gravity component with my gravity value and an IsAffectedByGravity component and remove/add the component to enable/disable my system ?

What about just adding an enabled attribute on my component ?

Here’s how I will code it: We will utilise the ECS system to do hard-lifting filtering for us… Sooo, we think of it as when we want to dash we will add the dash component to the Entity (This is basically a very cheap thing to do in ECS apparently as opposed to traditional Monobehavior AddComponent where GC gets allocated during runtime), then when we are done we will remove it from the entity.

Data defines the type in ECS, so our DashSystem will only update any entities with the Dash component.
GravitySystem on the other hand does not want to operate on entity on entities that are dashing, so we use subtractiveComponent to filter those out.

I am open for suggestions as I am also learning if there is better way to code it.
Gravity system works independently on everything with a Transform component.

MovementSystem is basically structured the same way as GravitySystem.

//===================================================
//Put this entire chunk in a new class name PlayerControllerComponent.cs to add to your game object
//To prepare the scene,
//simple create a GameObject,
//add GameObjectEntity and
//Player Controller Component

using Unity.Entities;

public struct PlayerInputController : IComponentData { }

// This wrapper component is currently necessary to add ComponentData to GameObjects.
// In the future we want to make this wrapper component automatic.
public class PlayerControllerComponent : ComponentDataWrapper<PlayerInputController> { }
//===================================================


using Unity.Entities;
using UnityEngine;
using Unity.Collections;
using Unity.Burst;
using Unity.Jobs;


public struct Dash : IComponentData
{
    public const float DASH_DURATION = 1f;
    public float timer;

    public Dash Init()
    {
        timer = DASH_DURATION;
        return this;
    }
}

class PlayerInputSystem : ComponentSystem
{
    struct Entities
    {
        public readonly int Length;
        public EntityArray entities;
        public ComponentDataArray<PlayerInputController> playerInputControllerMarker;
    }

    [Inject] private Entities _players;

    protected override void OnUpdate()
    {
        if (Input.GetKeyDown(KeyCode.D))
        {
            for (int i = 0; i < _players.Length; ++i)
            {
                Debug.Log("Dash input detected on Frame: " + Time.frameCount);
                //Add the Dash component so that the dash system handles the dash
                PostUpdateCommands.AddComponent(_players.entities[i], new Dash().Init());
            }
        }
    }
}

[UpdateAfter(typeof(PlayerInputSystem))]
class DashSystem : ComponentSystem
{
    struct Entities
    {
        public readonly int Length;
        public EntityArray entities;
        public ComponentArray<Transform> transform;
        public ComponentDataArray<Dash> dash;
    }

    [Inject] Entities _dashingEntities;

    protected override void OnUpdate()
    {
        var dt = Time.deltaTime;
        for (int i = 0; i < _dashingEntities.Length; ++i)
        {
            //Update dashing
            Debug.Log("Dashing on: " + _dashingEntities.transform[i].name + ", Frame: " + Time.frameCount);


            //Update timer
            var dash = _dashingEntities.dash[i];
            dash.timer -= dt;

            if (dash.timer <= 0)
            {
                //Time to stop dashing
                PostUpdateCommands.RemoveComponent<Dash>(_dashingEntities.entities[i]);
            }
            else
            {
                //Write
                _dashingEntities.dash[i] = dash;
            }
        }
    }
}

[UpdateAfter(typeof(PlayerInputSystem))]
class GravitySystem : ComponentSystem
{
    struct Entities
    {
        public readonly int Length;
        public ComponentArray<Transform> transform;

        //Exclude entity that are dashing
        SubtractiveComponent<Dash> dash;
    }

    [Inject] Entities _entities;

    protected override void OnUpdate()
    {
        for (int i = 0; i < _entities.Length; ++i)
        {
            //Update gravity pull
            Debug.Log("Gravity pull on: " + _entities.transform[i].name + ", Frame: " + Time.frameCount);
        }
    }
}

Use a SubtractiveComponent whose sole purpose is to declare that an entity should not be processed by some system.

For example:

The System: GravitySystem
The SubtractiveComponent: DoNotProcessGravityComponent

2 Likes

there is a VoidSystem<T> component already defined. it is used by the transform system. you can also use this as a convention.

so your gravity system can declare SubtractiveComponent<VoidSystem<GravitySystem>> in its group(s)

1 Like

We’re still working out the right convention for this, but yes - we need a standard for globally disable processing on a set of data.

2 Likes

What does adding SubtractiveComponent<VoidSystem> to a GravitySystem group does exactly? I played around with the code but couldn’t figure out what it does.

1 Like

SubtractiveComponent<T> in a group means the group will contain only the entities that don’t have that component.

VoidSystem<T> is just a tag and has no special meaning (for now). it’s available as a convention (may change) that you can use to be more clear how to explicitly exclude an entity from a system (yes you can define your own “exclude tag” for each of your systems, but then you will have to remember manually what does what (“oh I need to stop FooSystem to process this… what the corresponding tag was called?” vs “let’s try VoidSystem first. if it doesn’t work, it means that FooSystem still has no exclusion mechanism, so add it”))

(another convention you can use is: if a system support entity exclusion, define a nested “ExcludeEntity” component tag, so you AddComponent<FooSystem.ExcludeEntity>(). but that would be your convention)

1 Like

I think I got it now, meaning if I want to stop an Entity from being process by a system now I just need to AddComponent<VoidSystem> to the Entity. In this case, I will AddComponent<VoidSystem> to the entities that is dashing and when I am done, I will RemoveComponent<VoidSystem> from those entities and the GravitySystem should kick in immediately for entities without VoidSystem component. Is that right?

This way, GravitySystem don’t even need to keep track of which exact tag to exclude, it is just looking out to process any entities without VoidSystem component

1 Like

basically yes. your GravitySystem still needs to explicitly exclude VoidSystem<GravitySystem> from its group(s) though.

but as @mike_acton said, there may be an ‘official’ easier and globally consistent way soon™

1 Like

Aaaah this is the first good explanation of VoidSystem I ever found… I even read the source code and not able to grasp it until now.

Basically just that it can change a system name into an attachable component with help of C# generic mechanic so you don’t have to name a custom IComponentData, it produce a new name based on class name.

Now when you read it it would make sense : VoidSystem = Do not process this entity in the system A (I was wondering “what void?” I don’t think it is a good name)

Then in the system A you have to put SubtractiveComponent<VoidSystem> in the inject group so that it does not get processed for real.

Correct.

1 Like