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

Design questions

Discussion in 'Scripting' started by Teknoman, Sep 2, 2017.

  1. Teknoman

    Teknoman

    Joined:
    May 7, 2017
    Posts:
    22
    Hi,

    I'm pretty much still a noob concerning game development, and I'm currently trying to make a tower defense game as a means to get familiar with unity and to learn how to more or less organize a game with many units.

    So far I managed to create a mesh tile map with UV mapping and random terrain generation. I recently started trying to add units and buildings and read about ECS (entity component system). I've started implementing one, but as I'm starting to get deeper into the code, I'm starting to have questions about how to organize some things and how certain parts of the code should interact with each other.

    So far, I've created 3 systems/engines in my ECS: rendering, combat and movement.
    * Rendering: takes care of the GameObjects for the units and visualizing them. In the future I would like to expand on this and optimize it so that only entities which are within the screen bounds have game objects attached to them, by dynamically loading and unloading game objects for entities to achieve this.
    * Movement: takes care of moving entities from one position to another, keeping in mind the different speeds of different units, what terrain they can traverse, etc. (I still have to implement this part).
    * Combat: takes care of targetting and attacking entities, as well as taking care of the weapons these entities have (taking into account things like rate of fire, min and max range, damage, etc).

    My ECS even creates nodes which are collections of components which are used by the different systems. If I remember correctly, there is an ECS implementation out there called Ash which does this too (amongst others). I got it working and that part works flawlessly.

    Here are the questions I've got so far;

    - The 3 systems I described are the ones I found were usually mentioned, but what other types do games like RTS based games have?
    - How does the map fit into the ECS? Right now it's an external class and I'm going to have to access it from my movement system to do pathfinding amongst other things. Should it be an entity in the ECS somehow? It feels to me that it shouldn't because it is a different kind of object and there will only ever be 1 map active at the same time.
    - Having game objects with scripts for every single unit is bad for performance, but isn't having many components (or nodes) for every entity, which you'll have to iterate over equally as bad?
    - Entities (units and buildings) will not have game objects assigned to them if they are outside the field of view (screen bounds), which will them not have a mesh, collider, etc. What's the best way to implement collision detection then?
    - How to implement AI for entities owned by the computer? Another system where only computer controlled entities have the necessary components/nodes or a different way altogether?
    - As mentioned, I have a tilemap where tiles have a position (integer values), how do you handle units that occupy multiple tiles at once (because they are moving between tiles), so that collision detection works? Likewise, how to handle buildings that spawn several tiles.
    - Where do visual overlays fit into the ECS? For example, a white overlay 1 tile big on top of the map wherever the mouse moves if you're in "build mode".
    - In the combat system, how should entities acquire a target? For now I've the systems unaware of the ECS itself and unaware of the other entities, they live by themselves and components only hold data.
    - How to implement remappable units? I've seen suggestions about fixing it with shaders, but what about having models have at least one extra material for the remappable areas? Would there be any difference in performance?
    - How would you handle different GUI menus depending on the type of unit and its' components values?
    - How do you implement cliffs in a tilemap? Would it be another "map" with data about overlays where the cliffs are that, just visible overlays?
     
  2. GroZZleR

    GroZZleR

    Joined:
    Feb 1, 2015
    Posts:
    3,201
    I'm a little confused because you said you created three systems but I still think you're missing the system part of an ECS: entities contain components and those components are manipulated by the systems. You create a fixed amount of systems that inspect every entity as its created and add it to its own internal list to update and manage. Components are nothing but data.

    Create an abstract GameSystem class with three methods: OnEntityCreated(Entity entity), OnEntityDestroyed(Entity entity), OnUpdate(). EntityCreated and EntityDestroyed are called every time an entity is created or destroyed and where the system inspects the entity. Update is called every frame.

    So for example, your question about how AI should work:

    Code (csharp):
    1.  
    2. class EnemyAiSystem : GameSystem
    3. {
    4.    private List<Entity> entities = new List<Entity>();
    5.  
    6.    public override void OnEntityCreated(Entity entity)
    7.    {
    8.        if(entity.HasComponent<AiComponent>() == false)
    9.            return;
    10.        if(entity.HasComponent<HealthComponent>() == false)
    11.            return;
    12.        if(entity.HasComponent<VelocityComponent>() == false)
    13.            return;
    14.        if(entity.HasComponent<TransformComponent>() == false)
    15.            return;
    16.  
    17.        // we're interested
    18.        entities.Add(entity);
    19.    }
    20.  
    21.    public override void OnEntityDestroyed(Entity entity)
    22.    {
    23.        if(entities.Contains(entity) == true)
    24.            entities.Remove(entity);
    25.    }
    26.  
    27.    public override void Update()
    28.    {
    29.        foreach(Entity entity in entities)
    30.        {
    31.            TransformComponent transform = entity.GetComponent<TransformComponent>();
    32.            VelocityComponent velocity = entity.GetComponent<VelocityComponent>();
    33.            HealthComponent health = entity.GetComponent<HealthComponent>();
    34.            AiComponent ai = entity.GetComponent<TransformComponent>();
    35.  
    36.            if(health.current > 0)
    37.            {
    38.                if(ai.state == "moving")
    39.                {
    40.                    transform.position += velocity.direction * ai.speed * Time.deltaTime;
    41.                }
    42.                // etc. etc.
    43.            }
    44.        }
    45.    }
    46. }
    47.  
    By using systems like this, you can control order of operations quite easily:

    Code (csharp):
    1.  
    2. gameSystems = new List<GameSystem>();
    3.  
    4. // input first
    5. gameSystems.Add(new PlayerInputSystem());
    6.  
    7. // ai
    8. gameSystems.Add(new AiTargetingSystem());
    9. gameSystems.Add(new AiLogicSystem());
    10.  
    11. // physics
    12. gameSystems.Add(new MovementSystem());
    13.  
    14. // combat resolution
    15. gameSystems.Add(new DamageSystem());
    16.  
    17. // update UI
    18. gameSystems.Add(new HealthbarSystem());
    19. gameSystems.Add(new HudSystem());
    20. gameSystems.Add(new BuildUiSystem());
    21.  
    Once you understand this concept, the rest of your questions are fairly straight forward.

    The hardest part of another ECS layer ontop of Unity is bridging the two. You can accomplish this in a variety of ways, but the easiest way I've found is to attach your data components to actual Unity GameObjects and a few bridge scripts to pool events like OnCollisionEnter when necessary.
     
    Last edited: Sep 22, 2017
  3. Teknoman

    Teknoman

    Joined:
    May 7, 2017
    Posts:
    22
    Sorry for the delay, I was gone on holidays for a few weeks :)

    The systems I have are implemented the way you describe, so that part was already been taken care of. I understand what systems, components and entities are. I've used the following links as reference from the start:
    http://merwanachibet.net/blog/switching-our-rts-to-the-entity-component-system-pattern-ecs/
    http://www.richardlord.net/blog/ecs/what-is-an-entity-framework.html

    One of the things I didn't know how to solve was how to access the map from certain systems, this I solved by passing it into the constructor of the systems.

    It was interesting to see what systems you have, it helps to get an idea of the bigger picture.

    Most of my answers are still not answered though...

    I'm also wondering about the best way to store all the entities, are they usually stored in lists? don't they have bad performance when deleting items (when units get destroyed). You normally can't remove items from a collection when iteration on the collection...

    Finally, how are projectiles handled? The combat/targeting system must access the ECS to create a new entity for the projectile when a unit attacks. The projectile will then move (linear, arcing, ..) towards a position or another entity. This movement however is different from normal unit movement, as it does not have pathfinding. The movement has to be halted as well when a target or the map is hit or a certain time has passed, this is not true for other moving units. How is this detected and how does this result in the projectile exploding/dealing damage in what probably is a different system?