#System reading from a MonoBehaviour

1 messages · Page 1 of 1 (latest)

peak flower
#

I have part of my game/simulation running managed code and part ECS. The managed part is only some UI with user interaction.

The UIManager (MonoBehaviour) listens for changes in the input controls (sliders, input fields, etc). These are parameters that my ECS part rely on for calculations, so any changes in the UI results in some change to the data in the ECS world.

Normally, and my first approach was to expose event Action<MyData> and then have the System register those events and then modify the ECS data when events gets Invoked.

I'm still kinda new to ECS so i've sought help here before, but i wanted to make sure that i'm not making it harder that it needs to be. These are the guides/suggestions i got so far (or rather how i interpreted it) and i would really like to know if i misunderstood something.

  1. The System that reads from the UIManager should be a SystemBase and not an ISystem
  2. I should not register for event callbacks in a System (i figure because we only want that system to do anything in its Update loop, and events would fire from the UIManager's OnUpdate since that obviously won't automatically correspond to the specific Systems Update loop.
  3. I should poll the UIManager from the Update in my System and somehow keep track of any changes to any data i read off the UIManager.

All my current code revolves around those three constraints (or two 1, 2+3). I even made a wrapper class for any data in my UIManager that keeps track of wether the current data has been read or not (so the System only needs to change the ECS data if the data in the UIManager changed).

Is this the right approach? Can i simplify this? Whenever changes happen in the UI i can live with a lag spike.

clear stump
#

since MonoB Scene is static, all your managers are probably singletons as well

#

so public static field to access your manager should be fine

#

just ensure your static fields are managed properly, since ECS requires disabled domain reload

peak flower
#

So on top of the 3 points i need to add that my fields should be static instead of class variables - i guess that is easy (requires no extra work) - but am i right in the assumption that i need to keep track of changes instead of using events?

clear stump
#

no no

#

just instance of manager

#

public static UIManager Instance {get; private set;}

#

which you assign in Awake

#

and then you just access it and work with instance isntead

peak flower
#

currently i have that manager on a GameObject in the scene like i would normally do in a non-ecs world

#

i really, really hate that singleton pattern - why does it need to be a static instance? what is the difference from only adding one UIManager script to one GameObject in the scene?

clear stump
#

unless you have multiple UIManagers

#

static field is fine

#

if it's not

#

there are multiple ways to obtain reference to it

peak flower
#

i only have one manager

clear stump
#
  1. Instntiate it from World System
  2. Object.Find
peak flower
#

and my SystemBase finds that one instance of UIManager in the Create method

#

is that ok - the static Instance is not a requirement for ECS - it's just convivence?

clear stump
#

There's no point doing tricky stuff to avoid static fields when you work with MonoB Scene

#

Scene can only be 1 per Unity instance

#

which is definition of static

peak flower
#

i'm not trying to avoid static - it's extra work to make it static - or atleast i don't see any benefit, except if it's important for some reason i don't get

#

my system can cache the reference in the Start and use that reference in the Update - the alternative, i get it, i would just access the static Instance in the Update and not have to cache the reference - but i don't mind - it's how i always code... so i'm just making sure, since ecs is a new world to me, that i'm not breaking anything by doing this

clear stump
#

I think we misunderstood each other

#

I was only relevant to obtaining reference

#

As for you actual question - my suggestion not to try and tie ECS with events

#

they are like fire and water 😅

peak flower
#

ah ok 🙂 so it's ok for me to not use static instance - but what about the fields on that class - should those be marked static?

clear stump
#

it's really up to your design

peak flower
#

ok thanks 🙂 got my assumption confirmed - dont use events for communication - but then i need some other way to let the System know that there is new data waiting in the UIManager to read

clear stump
#

but when it comes to tying ECS world with something from OOP world, like UI

#

you need a bridge

#

and layer inbetween

peak flower
#

i actually called my System ManagedCodeBridge

#

and it derrives from SystemBase because i was told to use that for the bridge instead of an ISystem

#

but then that bridge is still accessing IComponentData and changing the data when it finds data in the UIManager changed

#

that's the right approach, right?

clear stump
#

bridge is not really just 1 class, it could be whole framework. Really up to how you design it

#

One way I see it (don't take it as best or good)

#

Whenever UI has some callbacks (for example button click)

#

it creates an entity with event and details on this event

#

and then some system processed it and creates all proper entities/changes to world and etc

peak flower
#

right now my bridge is just a SystemBase that holds a reference to UIManager - then when it finds user data changed it will find the components (mostly singleton components) and modify the data

#

i actually started out having the bridge create Buffer data and then a "real" ISystem read that buffer (like eventsourcing) execute the actions and clearing the buffer - but it seems like extra work - the bridge was still accessing ecs data that was being used (to process) by the ecs world

#

and my scenario is kinda small, so for bigger systems that might be a good idea - for me i didn't feel like i gained anything

clear stump
#

that's also fine

#

at least you avoid structural changes this way

#

which is actually leaving less footprint on perfomance

#

(allthough, it's probably just 0.01ms vs 0.005ms 😅 )

peak flower
#

ok thanks - then my final question - do you have a good pattern to detecting changes and acting upon them - before ecs my goto was events - right? it's what they were created for - but now i poll the changes, but i need to know if the values are changed values (since last time i checked)

clear stump
#

ECS only has chunk based change filters

#

I haven't played around much with it

peak flower
#

hehe yeah - and those changes doesn't matter much to me, because they are only supposed to happen when the user interacts - which is seldom and they expect minor lag (single frameskips perhaps) when they change the parameters of the simulation

clear stump
#

but my guess would be - just check all bound values manually if they are changed

#

and if they are

#

pass them to UI

#

which leaves you with another constrain - you have to keep amount of bindings low

peak flower
#

the changes goes from UI -> ecs world - nothing updates the UI except the user....

clear stump
#

what about situation when some NPC attacks player and it changes HP bar? (just example)

#

all changes happened fully from ECS

peak flower
#

the thing is - the user can change the number of a specific cell or a relation between two cells... for x number of cells that is x*x+x variables

#

for now i put a constraint to x being maximum 32 - which makes my ecs data easier - i can have fix sized NativeArrays

#

so i have reserved a NativeArray<float>(size: 32 * 32), for the relations, and i just index the array with cell1*32+cell2

#

yes right now the simulation is easy, the "npc's" are really just cells with a location and a velocity so the UI won't need to show anything

#

for this simulation i won't need the UI updated from the ecs world - but perhaps my next project - i will keep that in mind