#How to Enable/Disable systems in different scenes?

1 messages · Page 1 of 1 (latest)

dull dragon
#

How does one manage their systems in different scenes? I want specific systems to run in specific scenes, how does one go about doing that? I know there is a default world and it seems that all existing systems will run in all scenes by default.

Do I need to create a world for each scene in this case? or do I have monobehaviour that manages the enabling and disabling of the systems somehow, I tried the mono behaviour way and I can't seem to get the reference to the systems

public class SystemsManager : MonoBehaviour
{
    public string SceneName;

    // Start is called once before the first execution of Update after the MonoBehaviour is created
    void Start()
    {

    }

    // Update is called once per frame
    void Update()
    {
        
    }

    void UpdateSystems()
    {
        var world = World.DefaultGameObjectInjectionWorld;

        // Systems
        var systemA = world.GetExistingSystem<EntitySpawner>();
        var systemB = world.GetExistingSystem<GameObjectSpawner>();

        if (SceneManager.GetActiveScene().name == SceneName)
        {
            // Enable systems for the specified scene
            systemA.Enabled = true;
            systemB.Enabled = true;
        }
        else
        {
            // Disable systems for other scenes
            systemA.Enabled = false;
            systemB.Enabled = false;
        }
    }
}

Severity Code Description Project File Line Suppression State Details
Error (active) CS0315 The type 'EntitySpawner' cannot be used as type parameter 'T' in the generic type or method 'World.GetExistingSystem<T>()'. There is no boxing conversion from 'EntitySpawner' to 'Unity.Entities.ComponentSystemBase'. Assembly-CSharp D:\Unity Projects\URP3DTemplate\Assets\Scripts\SystemsManager.cs 26

Appreciate and thanks in advance for any help

slim notch
#

Systems operate on the world, not the scene. In the system's perspective, there is no concept of scene.

#

FYI a system only operates on the data of its interest. What you should do instead is specifying data requirements for your systems so that they will only run when their requirements are met.

#

On a side note, controlling systems via means outside of the ECS world mechanism will lead to dependency corruption.

#

You can also use the multi-worlds approach where each world has its own set of systems. But then you have to fully understand that each world exists on its own dimension with its own set of data, and there is no cross-world interaction (except operations to transfer data from one world to another).

#

You can't make entities of world A to interact with entities of world B, so to speak.

#

Because, in essence, interactions are the systems.

smoky bolt
dull dragon
#

@smoky bolt @slim notch thank you both!

  1. so what I am understanding is that, it if I don't want my systems to NOT run, in second scene or any other scene for that matter, I just do a Require for Update declaration in the OnCreate function yes?

  2. Say I have a system that does an update log but I only want to have it running on one unity scene and not any other scene. How would I go about that? Do I need to Tag the scene or a singleton entity somehow that only exist in that scene somehow or something?

  3. @smoky bolt loading scenes into created world sounds interesting, where one world == one scene, and each world doesn't interact with systems in other worlds. @slim notch I understand this is limiting as I can imagine having one world with systems interacting in multiple scenes would be a common case maybe, not sure. Regardless, is there any examples and resources that does that as a simple example on top of the official docs world concepts you sent. Asking if you know any other existing easy to follow examples. Just wondering what are the practices in managing system execution as I imagine having systems run all the time might/ maybe, idk incurr some performance hit but would be nice to know that some code in not executing when I don't need it essentially, if that makes sense, wonder if there are any good examples you can recommend.

thank you again in advance.

slim notch
#

Once again, you did not get it. There is no actual concept of "scene" in ECS. What presented in the (Entities) Hierarchy - things are grouped into "scenes" - is just for human navigation.

#

What we actually have in ECS are just data: entities, components, buffers, blob assets.

#

Systems process data. Period. No more than that.

smoky bolt
slim notch
#

Some entities have SceneTag and SceneSection components on them to signify that they are grouped together. But the "scene", as a container of entities, doesn't exist.

#

You can think of the entity storage as an excel sheet like this

#

The value of SceneTag and SceneSection help the Hierarchy window knows how to group entities and then visualizes those groups as "scenes".

#

(Note that this sheet can be very large, contains thousands of rows aka entities.)

#

What you should do now is trying to understand the concept of Archetype instead.

#

So you can instruct a specific system to only process a specific archetype.

dull dragon
#

okay gotcha thanks guys, I know that archetypes are the combination of unique set of components, I can just add and remove the tags in run time but I want to not have structural changes at runtime I guess I can add them and turn them on and off, with IComponentEnableable.

coarse mirage
#

Note you can't use enable components to stop a system running

#

They count as a filter and systems use ignore filter when using RequireForUpdate

slim notch
#

I think their usecase is not that important since they have explained in details what is the final outcome they want. Their problem is just not getting the gist of how ecs works and how it should work. 🤔

dull dragon
#

I apologize for responding late, my use case is to not run a system in another scene. Say I have 2 scenes, scene and scene B and 2 systems, system A and system B. I want system A to only run in scene A and system B to only run in scene B. since there is no concept of scenes in ECS and only worlds I guess I kind of have to tag the entity and do a filter WithAll<RunInSomeSceneOnlyTag> it seems.

Also I apologize if my question and responses are trivial or naive I am still learning this space and appreciate everyone's time and help.

#

when I make 2 system it seems that both systems will run regardless of the scene, which makes sense. It gets tricky especially if I do a getsingleton as if I have another new scene without the baking authoring script on it gives me errors in another scene

#

and I thought that dang if this system is running even when I don't need it how do I like not let it run? Do I just wrap the logic in a if statement and the updatefunction is still called but nothing runs, is that good enough? there must be a way to not invoke the update function at all right? Is it just a matter of the query not satisfying the archetype? if that makes sense

those are my thoughts.

#

for example here I have a new scene open but the systems are running but I expect the plug icon on the left would be slashed and greyed out like the multiplayer server...system at the bottom but its not so I wondered if the correct way ways somehow disable them but also wondering if its suppose to be like this.

coarse mirage
#

Enable = false is how they can actually be disabled

#

But tbh this is weird to do outside of initialization systems that only need to run once or even just call OnCreate

dull dragon
coarse mirage
#

state.Enable = false for ISystem
or
this.Enable = false for SystemBase

dull dragon
#

This is my OneShotEntitySpawnerSystem, one shot as in its just spawns everything in one shot, but if I put my code in on create nothing happens. Side not if I use enitity manger, it spawns things one by one and when I use a ECB it spawns all the entities at once and even then the logic lives in on update.

partial struct OneShotEntitySpawnerSystem : ISystem
{

    [BurstCompile]
    public void OnUpdate(ref SystemState state)
    {
        var ecb = new EntityCommandBuffer(Allocator.Temp);
        var random = new Unity.Mathematics.Random((uint)UnityEngine.Random.Range(1, uint.MaxValue));

        foreach (var (spawner, entity) in SystemAPI.Query<OneShotEntitySpawner>().WithEntityAccess())
        {
            for (int i = 0; i < spawner.amountToSpawn; i++)
            {
                float3 randomPosition = GenerateRandomPosition(spawner, ref random);
                Entity newEntity = ecb.Instantiate(spawner.prefab);
                ecb.SetComponent(newEntity, LocalTransform.FromPosition(randomPosition));
                ecb.AddComponent(newEntity, new SpinComponent
                {
                    spinRate = 100f,
                    isClockwise = random.NextBool(),
                });
                ecb.AddComponent(newEntity, new OrbitComponent
                {
                    orbitSpeed = 10f,
                    isClockwise = random.NextBool(),
                });
                ecb.AddComponent(newEntity, new SineTranslationComponent
                {
                    sineWaveHeight = 1f,
                    sineWaveSpeed = 2f,
                    initialY = randomPosition.y,
                });
            }

            // Remove the spawner component to ensure it runs only once
            ecb.RemoveComponent<OneShotEntitySpawner>(entity);
        }

        ecb.Playback(state.EntityManager);
        ecb.Dispose();
    }
}
coarse mirage
#

state.Enable = false;
would stop it updating again

#

To answer your actual original question of, how to disable a system

#

but removing OneShotEntitySpawner is a very valid solution here

#

makes it reusable if you load a new scene with another OneShotEntitySpawner for example

#

in OnCreate you can add a
state.RequireForUpdate<OneShotEntitySpawner>();

#

to stop the system updating unless an entity with OneShotEntitySpawner exists

dull dragon
#

Hmm I see

coarse mirage
#

no need to disable it, it'll just run when there is data to process

#

(remember that subscenes load asynchronously and may take multiple frames, so if you're OneShotEntitySpawner is in a subscene you can't just run Update once)

dull dragon
#

so basically if the logic lives in oncreate its less reusable I imagine

coarse mirage
#

not sure what you mean?

#

you're only adding state.RequireForUpdate<OneShotEntitySpawner>() to OnCreate

#

just telling hte system not to update unless it has data to operate one

dull dragon
# coarse mirage not sure what you mean?

is it better to have code to run once in oncreate or is the removing the component more "correct", I know both are probably valid but just curious on when to do what and what the pros and cons are, if what I am saying makes sense

coarse mirage
#

you can't run the SystemAPI.Query in OnCreate because the OneShotEntitySpawner won't exist yet

dull dragon
#

ooohh I see cuz the subscene loads async nd takes some time

coarse mirage
#

even if it was synchronous

#

it still wouldn't exist yet

#

because it won't exist until the SubSceneResolvingSystem Update has run once to actually load it

dull dragon
#

hmm I see gotcha thanks for explaining.

slim notch
#

OnCreate is called when the system is created. So it only runs once in its entire lifetime. But systems are created on the very beginning of the runtime, right after you open the game or enter play mode.