Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

Question Thoughts on my ECS 1.0 character control method?

Discussion in 'Entity Component System' started by brad-bit, Oct 15, 2022.

  1. brad-bit

    brad-bit

    Joined:
    Mar 26, 2015
    Posts:
    9
    Hi! I'm new to ECS and trying to figure it out for an isometric twin stick shooter project, using ECS 1.0. I'm struggling a bit with my design and would appreciate some feedback :)

    • Is it possible to have an association between two entities? I have an entity representing a character with transform, physics, health etc, and another entity representing the character's current action, e.g. walk, dodge roll, get thrown to air by an explosion, etc. The intent is that I could cancel the current action if the character gets interrupted (by e.g. getting hit or dying) by simply destroying the action entity, without having to destroy each of the action's components individually (the action might have a bunch of components that should all be destroyed, e.g. "play particle effect after 2 seconds", "move character forward", "read input" etc). I'm adding a CharacterActionRelationship component to the character entity that stores the associated action entity in a Entity field, and a corresponding ActionCharacterRelationship component to the action entity. Is this valid at all, or do the Entity values get invalidated when the entities move to different chunks?
    • Is it possible to query for components in the two different entities? I suppose it probably isn't... The idea would be to e.g. query for HitByExplosion on the character entity and WalkingAction on the action entity, to detect if the current action is one that should be interrupted by an external stimulus to the character. (Some actions can be cancelled by different stimuli, e.g. light attack can be cancelled by getting hit, but a super armor attack can be cancelled only by getting thrown in the air by an explosion).
    • Is it possible to query for components on one entity and then edit the transform of a different entity? I'm querying for ActionCharacterRelationship which identifies the associated character entity, and MoveForward which indicates the action should be moving the associated character entity's transform forward. These components exist on the action entity. It seems fetching the character entity and modifying its LocalToWorldTransform doesn't change its position:
      Code (CSharp):
      1. public partial class MoveCharacterForwardSystem : SystemBase {
      2.   protected override void OnUpdate() {
      3.     foreach (var (actionCharacterRelationship, moveForward) in SystemAPI.Query<RefRO<ActionCharacterRelationship>, RefRO<MoveForward>>()) {
      4.       var transform = GetComponent<LocalToWorldTransform>(actionCharacterRelationship.ValueRO.character);
      5.       transform.Value = transform.Value.Translate(new float3(0, 0, 1));
      6.     }
      7.   }
      8. }
      Also tried with GetComponentLookup, but didn't help. Not sure what that one does o_O
    • If all else fails, I suppose I could create a bunch of systems that copy components on the character entity to the action entity and vice versa (e.g. copy position from action to character, or copy HitByExplosion status from character to action), so that the systems exist on the entity that needs to do the query... but that would lose the separation of concerns and muddle things up :confused:
     
  2. tgkthefirst

    tgkthefirst

    Joined:
    Dec 27, 2020
    Posts:
    13
    Hi, I might have some answers, But I suggest you to wait for others for more replies since I'm learning too ATM
    • Yes, i believe you can, you just have a component which is holding a reference to an entity, and 2 entities can hold reference to each other, and no making a structural change doesn't cause those references to be invalid, a simple test of just holding a reference to an entity, make a structural change to the entity, and check if the entity reference is still pointing to the correct entity...
    • I'm not really sure what you're trying to do, maybe you could clarify this, But my guess is that you're trying to determine what kind of things should happen based on 2 characters' interaction, my suggestion is use the physics package, cast rays towards entities from the corresponding systems (which will have the information of what's happening) and then from those rays do stuff with those entities
    • I still think component lookup should solve this kind of problem, yet I still don't understand what is going on exactly.. so I can't really answer this
    • Separation of concerns can manifest itself in many different ways, and data oriented programming in unity is relatively new, and my suggestion is just make things work (in a performant manner, we don't wanna sacrifice the point of DOTS) since we're all learning here, and then try to think about how to make things clean
    Hope this helps :)
     
  3. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    3,987
    Valid. Entity values are stable for the lifetime of the entity, no matter how many chunks it gets shuffled between.

    Not really. But you may want to look into ComponentLookup to see if that provides good performance for your problem.

    You have to set it back, using SetComponent(), or in ComponentLookup using assignment with the ComponentLookup indexing on the left side of the =.
     
    tgkthefirst likes this.
  4. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,584
    There is many ways animation problem can be approached.

    First of all, there is no character animator on 1.0, which suppose to control legs, body and hands. If that what you need.
    For that you either need to wait, roll own solution, or use one of the frameworks from ou fellow developers.

    But the way you describe your problem related to DOTS, suggest you haven been working with it before. Which maybe quite difficult for you to make such complex optimal design.

    You can reference entities one to other no problem. Usually using LinkedGroup.
    But there are other ways too. Specially if you want particles to live after character dies.

    Character animationsequencer can be stored on children entities. But you probably want to cash animation sequences on blob asset or relevant. And use entities to store the animation state.
    Consider like a baking.

    Rendering characters is another matter, when comes into bones. There is thread in DOTS Aninations sub forum. It describes animation options for characters quite well.

    https://forum.unity.com/threads/dots-animation-options-wiki.1339196/
     
  5. brad-bit

    brad-bit

    Joined:
    Mar 26, 2015
    Posts:
    9
    Thanks for the quick & helpful replies! Sounds like splitting behavior into two entities is not a problem. Forgot to set the component back to do the transform indeed, I got confused by the queried components being editable in-place!

    Thanks for the tips on animation as well! I'm currently working on game logic and since the animation package doesn't support ECS 1.0 yet (I think), I made a system that mirrors animation-related values to a GameObject where I can use my old animator :D Not performant but I'll worry about that later. I'll maybe have to write a custom skinning shader, because I think I'll try a flipbook-like animation where each entity doesn't have its own unique blended pose, instead they just have an index to a frame of animation (in a shared buffer of single-frame poses) without any blending. If it works out I'm hoping it'll have a 2D sprite animation kinda feeling despite being 3D. Sable's animation looks a bit like keypose flipbooking.

    For background on the game logic, I have "characters" which are entities that hold variables (like position and health) and tags (like "Is Grounded", which I update by raycast each frame, or "Was Hit By Explosion", which exists for a single frame when the physics engine indicates a collision with explosion collider, etc). However the character doesn't do anything by itself, it's driven by a separate "action" entity, which is usually created by player input (e.g. press up to create an entity with a "WalkComponent"), or lack of input ("Idle"), or an external stimulus ("StunnedByExplosion"). By having the action be a separate entity I can just destroy the entity, and whatever was internally going on with the action will get cleaned up - for example, when a dodge roll action is created, it first creates a bunch of components that schedule gameplay effects (move the character forward), VFX & SFX (play sound immediately, play particle effect at 2.0 seconds), and also input (my ConsumeInputComponent has a list of "allowed inputs" that the action entity manages, so a melee attack action might schedule a window of time wherein the player can press a button to do a combo attack). If the character is hit by an external stimulus such as a bullet, it might interrupt its current action - now I can just destroy the action entity and not have to be aware of everything the action might have scheduled. My VFX and SFX are handled by separate entities, so destroying an action doesn't kill the existing particles, it just stops the action from spawning any more.