Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Question Is ECS a good fit for this open world roguelike?

Discussion in 'Entity Component System' started by bitHussar, Jan 25, 2023.

  1. bitHussar

    bitHussar

    Joined:
    Jan 9, 2016
    Posts:
    33
    I'm making an open world roguelike with a large proc gen map with a bunch of enemies and other objects on it (let's call them entities). For performance reasons the world is split into chunks and only the chunks near the player are loaded (including the level geometry and all entities in that chunk). For chunks that are farther away only the data is stored for entities (POCO classes containing the id of the prefab that needs to be instantiated when the player gets close, and a separate class for every MonoBehaviour attached to the entity that needs to be persistent through the game like hp and etc.). So it's kind of like a very simple ECS system (or at least the EC part) that represent entities when they are far. Then when the player gets close the appropriate prefab is instantiated and the MonoBeahaviour-s set their state based on the component data they represent. In the long run there will be a couple of entities that needs to be updated even when they are far, but most of the stuff is just for storing data.

    As I tried to optimize performance (cache component lookup on entities, etc) I was wondering if using Unitys ECS would be a good fit here as it looks somewhat similar but already in a better shape. However I have some concerns:
    - Currently entities are stored in a spatial grid so I can get the entities in a given chunk with O(1), would it be possible to do with ECS or I would need to do iterate through all entities returned by World.GetAllEntities and check their position? Wouldn't it be too slow?
    - Instead of saving and loading data from MonoBehaviour to components MonoBehaviours direcly use the component instance to store data. So for example the Health monobehaviour doesn't have an int hp property but gets the current health value from the HealthComponent it is bound to and observes changes in the HealthComponent via an Action. For that I need to have a reference to the original component to make sure that I modify the same instance and not just a copy of it, however AFAIK in ECS components are value types so writing data to them directly would not make sense. Or am I missing something?
    - Would I actually benefit from the optimizations in the ECS system if I constantly add / remove entities as the player move around the map?

    Thanks in advance
     
  2. desper0s

    desper0s

    Joined:
    Aug 4, 2021
    Posts:
    15
    You don't need to iterate over entities to do that. What you can do is to store them in other container and have separated system which will automatically put/remove entities from this container - you can use "ICleanupComponent" to do that.
    Only one limit here is that this container should be implemented as value type - easiest way is to have pre-allocated NativeArray<Entity> - this will allow you to use this container in jobs. Of course there are better ways to implement such container.
    Also nice thing is to have this spatial container as singleton entity, so in every system that you want to access it you can just call `SystemAPI.GetSingleton<SpatialGrid.Singleton>()`

    I don't know your case exactly, but general rule is that systems should write/update to this HealthComponent. If you want show it somewhere in UI, you can write system, which will synchronise UI with entity data. If you want to send events reacting to HealthComponent changes I am afraid that you need to write your own implementation, or use great tool from tertle https://forum.unity.com/threads/event-system.779711/

    Again it depends on your case, but ECS have something like "subscene" workflow which is designed to work with fast load/unload scene chunks so you can check that
     
    bitHussar likes this.
  3. mgear

    mgear

    Joined:
    Aug 3, 2010
    Posts:
    9,350
  4. bitHussar

    bitHussar

    Joined:
    Jan 9, 2016
    Posts:
    33
    Sorry, I probably was confusing: 99% of the times I plan to update the component values from the MonoBeahviours. For example I have a MonoBehaviour called EntityBehaviour that has a reference to the Entity in the ECS system and sets that components position and rotation to match transform.position and transform.rotation in the Update loop for example (similar fashion as in CopyTransformFromGameObject, but running on the main thread). I plan to go with that approach because the enemies and other entity prefabs are so complex with a lot of different packages used for AI, etc that porting all that to systems would be just too much work. Also for 99% of the systems I don't need to simulate the whole world (at least not every frame), just the chunks that are close to the player and that is not that many.