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. Dismiss Notice

ECS Advice

Discussion in 'Entity Component System' started by Shabbalaka, Sep 26, 2019.

  1. Shabbalaka

    Shabbalaka

    Joined:
    Jan 15, 2018
    Posts:
    154
    Hi Guys, Sorry I do not have any code but more of a clarification question regarding ECS.

    I have seen a lot of tutorials on the subject but they all use various types of ways of using ECS either pure or hybrid.

    I have used Monobehaviours before but this ECS is a bit confusing to me at the moment.

    Q1 : If i want to create a Entity do I need to create an Entity Manager for each one or can I create one script which is a "Root" EnetityManager for all enrtities created?

    Q2: Is it best to create an individual Entity script with a accompanying Component Script which passes to a ComponentSystem??
    Example : BulletEntity, PlayerEntity, EnemyEntity, etc...

    Q3:Instantiate or CreateEntity (After seeing multiple tutorials which use both, It kind of gets confusing)
    I am assuming the Instantiate is if you are using Hybrid Renderer to Render Gameobjects and CreateEntity basically creates an Empty Entity from which you attach Components to via SetComponentData?

    IMany thanks to any who reply
     
  2. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    3,983
    1) You have to get the EntityManager from a world or system.
    2) Entity is a struct type that is already defined. You just define your IComponentData types.
    3) Instantiate clones an entity and removes the prefab tag if one exists. CreateEntity gives you an empty entity as you suspected, but you will have to use AddComponent API rather than SetComponent API.
     
  3. Shabbalaka

    Shabbalaka

    Joined:
    Jan 15, 2018
    Posts:
    154
    Many thanks for the reply, Would you be able to post a example please?

    So for example in EntityManager.cs I would have something like

    Code (CSharp):
    1.  
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5. using Unity.Entities;
    6.  
    7. public class _EntityManager : MonoBehaviour
    8. {
    9.     public EntityManager em;
    10.     public void Start()
    11.     {
    12.          em = World.Active.EntityManager;
    13.     }
    14.     public EntityManager UseManager()
    15.     {
    16.         return em;
    17.     }
    18. }
    19.  
    20.  
    BulletEntity.cs
    Code (csharp):
    1.  
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5. using Unity.Entities;
    6. using Unity.Transforms;
    7.  
    8. public class BulletEntity : MonoBehaviour
    9. {
    10.     public void Start()
    11.     {
    12.         //This uses our already made EntityManager in the EntityManager script.
    13.        //This creates an error.
    14.         Entity Bullet = _EntityManager.UseManager().CreateEntity(
    15.             typeof(Translation)
    16.         );
    17.  
    18.         //This creates another entitymanager to use to create the bullet entity.
    19.         //But we already have one in _EntityManager script??
    20.         EntityManager entityManager = World.Active.EntityManager;
    21.         Entity Bullet1 = entityManager.CreateEntity(typeof(Translation));
    22.     }
    23. }
    24.  
    PlayerEntity.cs
    Code (csharp):
    1.  
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5. using Unity.Entities;
    6. using Unity.Transforms;
    7.  
    8. public class PlayerEntity : MonoBehaviour
    9. {
    10.     // Start is called before the first frame update
    11.     public void Start()
    12.     {
    13.         //This uses our already made EntityManager in the EntityManager script.
    14.         Entity Player = _EntityManager.UseManager().CreateEntity(
    15.             typeof(Translation)
    16.         );
    17.         //This creates another entitymanager to use to create the bullet entity.
    18.         //But we already have one in _EntityManager script??
    19.         EntityManager entityManager = World.Active.EntityManager;
    20.         Entity Player1 = entityManager.CreateEntity(typeof(Translation));
    21.     }
    22. }
    23.  
    RenderEntity.cs
    Code (csharp):
    1.  
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5. using Unity.Entities;
    6. public struct RenderEntity : IComponentData
    7. {
    8.     public Mesh mesh;
    9. }
    10.  
    SpawnEntitySystem.cs
    Code (csharp):
    1.  
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5. using Unity.Entities;
    6.  
    7.  
    8. public class SpawnEntitySystem : ComponentSystem
    9. {
    10.         protected override void OnUpdate()
    11.         {
    12.             if(Input.GetMouseButtonDown(1))
    13.             {  
    14.                 /* How do we spawn a bullet here ??
    15.                 using CreateEntity and then applying the mesh component?
    16.                 or
    17.                 using Instantiate with this script applied to a empty game object?
    18.                 */
    19.             }
    20.         }
    21. }
    22.  
    23.  
    Sorry for the long post, But I hope this clarifies what I am trying to explain and achieve?

    Or am i going about this all wrong if so can you point me in right direction of a good tutorial please, I am currently using CodeMonkeys video,s on Youtube but he writes a lot of his script in 1 script which doesnt show the Entities, Components and Systems working in conjunction with each other like how do you access the data held RenderEntity in SpawnEntitySystem and vice versa.

    I will update this post with my experience and progression for anyone else who might be struggling also as it may help others who are super new to this.

    I really appreciate anyone who takes the time out to read and even clarify/modify this post to make sense. Many many thanks to you!
     
    Last edited: Sep 27, 2019
  4. Shabbalaka

    Shabbalaka

    Joined:
    Jan 15, 2018
    Posts:
    154
    When I watch CodeMonkey tutorial he isnt using AddComponent at all, This is why I am finding this confusing at the moment as there seems to be a lot of different ways of doing things.

    Do you only need to use AddComponent if the Entity script is not attached to an empty GameObject??
     
  5. ndesy

    ndesy

    Joined:
    Jul 22, 2019
    Posts:
    20
    You need to use AddComponent or AddComponentData if the component type is not present on the Entity, otherwise you need to use SetComponentData to update the component value. You will get an error if you try to add a component twice, or if you try to update non-existent component.

    Also, you do not need to create your own EntityManager. Each world has its own EntityManager. World.Active.EntityManager just return a reference to the EntityManager of the active world.
     
  6. BanJaxe

    BanJaxe

    Joined:
    Nov 20, 2017
    Posts:
    47
    You should read the manual and look at the samples.

    Here's a simple system that spawns cubes from a prefab. Start a new project and install the Entities and Hybrid Renderer packages then put this in the assets folder. You don't need to create any gameobjects / monobevhaiours.

    Code (CSharp):
    1.  
    2. using Unity.Entities;
    3. using Unity.Mathematics;
    4. using Unity.Rendering;
    5. using Unity.Transforms;
    6. using UnityEngine;
    7.  
    8. public class CubeSpawner : ComponentSystem
    9. {
    10.     Entity prefabEntity;
    11.  
    12.     protected override void OnCreate()
    13.     {      
    14.         // Temporary gameobject just to generate a mesh and material
    15.         var goCube = GameObject.CreatePrimitive(PrimitiveType.Cube);
    16.         var cubeMesh = goCube.GetComponent<MeshFilter>().mesh;
    17.         var cubeMat = goCube.GetComponent<MeshRenderer>().material;
    18.  
    19.         prefabEntity = EntityManager.CreateEntity();
    20.         EntityManager.AddComponentData(prefabEntity, new Prefab());
    21.         EntityManager.AddComponentData(prefabEntity, new Translation());
    22.         EntityManager.AddComponentData(prefabEntity, new LocalToWorld());
    23.         EntityManager.AddSharedComponentData(prefabEntity, new RenderMesh() { mesh = cubeMesh, material = cubeMat });
    24.  
    25.         GameObject.Destroy(goCube);
    26.     }
    27.  
    28.     protected override void OnUpdate()
    29.     {
    30.         if (Input.anyKeyDown)
    31.         {
    32.             var spawnedEntity = EntityManager.Instantiate(prefabEntity);
    33.  
    34.             var randomPosition = new float3(
    35.                     UnityEngine.Random.Range(-5f, 5f),
    36.                     UnityEngine.Random.Range(-5f, 5f),
    37.                     UnityEngine.Random.Range(-5f, 5f));
    38.  
    39.             EntityManager.SetComponentData(spawnedEntity, new Translation() { Value = randomPosition });
    40.         }
    41.     }
    42. }
    43.  
     
  7. Shabbalaka

    Shabbalaka

    Joined:
    Jan 15, 2018
    Posts:
    154
    Many thanks for the replies and the links to the samples.

    I will be sure to go over the Samples and the Manual, The example you made will be very useful.

    How would you pass prefabEntity to the System in OnUpdate if it was in a seperate script?

    Code (CSharp):
    1.  protected override void OnUpdate()
    2.     {
    3.         if (Input.anyKeyDown)
    4.         {
    5.             var spawnedEntity = EntityManager.Instantiate(prefabEntity);
    6.             var randomPosition = new float3(
    7.                     UnityEngine.Random.Range(-5f, 5f),
    8.                     UnityEngine.Random.Range(-5f, 5f),
    9.                     UnityEngine.Random.Range(-5f, 5f));
    10.             EntityManager.SetComponentData(spawnedEntity, new Translation() { Value = randomPosition });
    11.         }
    12.     }

    How would "var spawnedEntity = EntityManager.Instantiate(prefabEntity);" work if this was in a seperate script so you could pass any Entity to it for it to spawn?

    Would you have to pass prefabEntity as an Entity object for it to receive the values held within prefabEntity?

    Once again Many thanks!
     
  8. BanJaxe

    BanJaxe

    Joined:
    Nov 20, 2017
    Posts:
    47
    Well you can pass Entity references around in the normal OO way, reference them in a monobehaviour, or another system, or whereever you want. However that is the OO way to do it, and it can be error prone as those Entities may be changed or destroyed at any point. ECS systems tend to avoid directly talking to one another. They can and it will work, but it's a bit of an anti-pattern to tightly couple systems together.

    You can watch this talk about converting your thinking from the old OO gameobject way of doing things to the ECS data oriented way of doing it.



    And the sample used in this talk is here.
     
    DwinTeimlon likes this.
  9. Shabbalaka

    Shabbalaka

    Joined:
    Jan 15, 2018
    Posts:
    154
    Thanks for the link and explanation,

    I will take a look at those samples and video, Just 1 final question with using ECS is it better to do

    1 : Attach a Game Entity Object Component to a Gameobject and Instantiate that as normal using a Hybrid Renderer?

    or

    2 : Create a blank entity and then attach a MeshRenderer to display said entity.

    Its only the "displaying" and assigning an entity which is causing me issues at the moment , Like for example if you create a blank entity how do you attach a mesh to it via code? or is it ok to do this via the inspector?
     
  10. thelebaron

    thelebaron

    Joined:
    Jun 2, 2013
    Posts:
    825
    3. Use ConvertToEntity & conversion workflow

    I think you should take a look at the github samples BanJaxe mentioned, Unity are pushing the conversion workflow hard, 1. is deprecated and might be removed in the future, and 2. might be jumping the gun as far as starting out. A lot of these things will become clearer once you've had a chance to dissect and analyze them.
     
  11. bugfinders

    bugfinders

    Joined:
    Jul 5, 2018
    Posts:
    738
    I can see how DOTS is really confusing, as there are a lot of videos all showing slightly different ways of it working, and even many of the unity ones seem to skip a few steps between what they start with and what they end up with. (Example the shooting one where he converts to dots for the bullets, most of the actual code for the bullet is skipped such as collisions, etc)

    As a result it can be frustrating when you cant quite make it work. To those who have cracked it properly in the had (and in my head I get the logic) the "missing" peices are probably blindingly obvious, but for those of us who havent cracked it, there are these gaps that just dont quite mean stuff works.

    The samples are great, but for example, I made a cube (yes, trying for the obligatory spinning cube), I made some IComponentData with a rotationspeed, and a job and a system.. initially nothing happened, I swore, then, I used slightly different maths and the cube instead of rotating moved, as the default script uses the transform and a read only rotation.. so despite the template for the job+data seemingly trying to rotate, it didnt.. so hence I made a data, job and system, not a data/job and system, finally i got it rotating, now, it was supposed to be around math.up().. but it actually wasnt, well it was, but even though everything was centered on 0,0,0 the cube actually was in a spiral rather than spinning on the spot.. For the life of me, I had no idea why.. It had no physics on it, so, it couldnt be blamed on centrifugal force.. The latest unity demos do look like its a lot more tied into the IDE and so might be much clearer when we get our hands on it all, but right now, it can feel a little like trying to hold onto smoke with your hands, you think you got it and then its gone..
     
    Deleted User likes this.
  12. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    3,983
    In classical MonoBehaviours, the learning curve is sort of like a smoothstep function. The steepness is at the intermediate level. With DOTS, the curve is more like a 1 - (1 - x)^2 curve, where the steepness is all at the beginning, but once you get it, it is pretty easy to transition into the advanced stuff.

    The best thing you can do is post your code and alongside the issues you are facing so we can more easily identify where the missing pieces are and help you fill in the gap.
     
    bugfinders likes this.
  13. Shabbalaka

    Shabbalaka

    Joined:
    Jan 15, 2018
    Posts:
    154
    Many thanks for the replies!,

    I will be sure to try to do a small demo and use ECS and maybe it,ll become a lot clearer with the assistance of these forums :)

    I really appreciate all the help!

    I recently found the ECS Space Shooter example which might prove helpful also!

    I will keep you guys updated on the progress.
     
  14. Shabbalaka

    Shabbalaka

    Joined:
    Jan 15, 2018
    Posts:
    154
    Ok well I am following the ECS Space Shooter thing by examining the code that they are using but still not having much luck with it as I get some errors regarding these lines.

    I thought if I copied and pasted their example code I could comment each line out and try to figure exactly whats going on, I managed to get it to create a single entity (I can see in the Entity Debugger entitys being added) but again it,s the "visual" problem where I cannot see the entitys I am struggling with I think its the "Position" component

    Code (CSharp):
    1.  
    2.  
    3. void AddShips(int amount)
    4. {
    5. //Create an array of Entities with the amount specified and the array is Temporary.
    6. NativeArray<Entity> entities = new NativeArray<Entity>(amount, Allocator.Temp);
    7.  
    8. //This will create a single entity.
    9. manager.Instantiate(enemyShipPrefab);
    10.  
    11. //Loop through all the entities and assign values to their position, Rotation and MoveSpeed components.
    12. for (int i = 0; i < amount; i++)
    13. {
    14. float xVal = UnityEngine.Random.Range(leftBound, rightBound);
    15. float zVal = UnityEngine.Random.Range(0f, 10f);
    16.  
    17. //Using the entity manager set the position component values to a new Float3().
    18. /*################################
    19. I do not see a manager.AddComponent anywhere so I assume that the Position, Rotation and MoveSpeed
    20. components below are attached directly to the EnemyShipPrefab GameObject with Monobehaviour??
    21. ################################## */
    22.  
    23. manager.SetComponentData(entities[i], new Position { Value = new float3(xVal, 0f, topBound + zVal) });
    24. manager.SetComponentData(entities[i], new Rotation { Value = new quaternion(0, 1, 0, 0) });
    25. manager.SetComponentData(entities[i], new MoveSpeed { Value = enemySpeed });
    26. }
    27. //Dispose of the entities array as creation has been completed and it is no longer needed.
    28. entities.Dispose();
    29.  
    30. //Increase count by the amount.
    31. count += amount;
    32.  
    33. }
    34.  
    35.  
    36.  
    Error : The type or namespace name 'NativeArray<>' could not be found (are you missing a using directive or an assembly reference?) (CS0246) [Assembly-CSharp]


    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using Unity.Entities;
    5. using UnityEngine.Jobs;
    6.  
    7. //Am I missing a Using for NativeArray or has it been Deprecated already ?
    8.  
    Many thanks for all the replys and help and I feel I am getting a step closer to understanding how this works. :)
     
  15. Lurking-Ninja

    Lurking-Ninja

    Joined:
    Jan 20, 2015
    Posts:
    9,903
    Try adding
    Code (CSharp):
    1. using Unity.Collections;
     
    herlon214 likes this.
  16. Shabbalaka

    Shabbalaka

    Joined:
    Jan 15, 2018
    Posts:
    154
    Thanks!, I didn,t realise NativeArray was in Unity.Collections and thought it was implemented from System.Collections.
     
  17. Shabbalaka

    Shabbalaka

    Joined:
    Jan 15, 2018
    Posts:
    154
    Sorry if this is a really basic question but what exactly does this mean ??

    public void AddComponent<T>(Entity entity)

    so if I want to add a Component to an entity I call

    entitymanager.AddComponent<MyComponentName> (entity)?
    or
    entitymanager.AddComponent (Mycomponent, Myentity);


    I am self taught in programming so spent a lot of time reading tutorials and forums and the such so sometimes a lot of the manuals are not really coherent for me.
     
    ippdev likes this.
  18. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,574
    @Shabbalaka
    there are multiple ways of adding components to entity.
    You need of course some components on entity, to hold the data.
    So EntityManager is one way. EntityCommandBuffer (ECB) is other.
    You can also generate entities with group of components via archetype.
    And finally via entity conversion workflow, from GameObject.

    If I missed anything, someone please let me know please.

    there are few ways.
    Primarly, not
    Code (CSharp):
    1. entitymanager.AddComponent (Mycomponent, Myentity);
    but rather
    Code (CSharp):
    1. em.AddComponentData ( entity, new MyComponent () { i = 0 } ) ;
    2. em.AddComponent ( entity, typeof ( MyComponent ) ) ;
    3. em.AddComponent <MyComponent> ( entity ) ;
    1. Where you add component with data.
    2. and 3. work same way, as far I am aware.
     
    Last edited: Oct 11, 2019
  19. Shabbalaka

    Shabbalaka

    Joined:
    Jan 15, 2018
    Posts:
    154
    Many thanks for all the replies! I will post my progress :)
     
  20. Shabbalaka

    Shabbalaka

    Joined:
    Jan 15, 2018
    Posts:
    154
    Code (CSharp):
    1. public class ECS_MultipleTemplate : MonoBehaviour
    2. {
    3.  
    4.     [SerializeField]
    5.     public Mesh mesh;
    6.  
    7.     [SerializeField]
    8.     public Material material;
    9.  
    10.       private EntityManager em;
    11.  
    12.       public int NumToCreate;
    13.  
    14.     public void Start()
    15.     {
    16.  
    17.         em = World.Active.EntityManager;
    18.  
    19.         EntityArchetype ea = em.CreateArchetype(
    20.             typeof (Translation),
    21.             typeof (LocalToWorld),
    22.             typeof (HealthComponent),
    23.             typeof (RenderMesh)
    24.      
    25.         );
    26.         NativeArray<Entity> entityArray = new NativeArray<Entity>(NumToCreate, Allocator.Temp);
    27.         em.CreateEntity(ea, entityArray);
    28.         for(int i = 0; i < entityArray.Length; i++)
    29.         {
    30.          
    31.             Entity entity = entityArray[i];
    32.  
    33.             em.SetComponentData(entity, new HealthComponent { Health = Random.Range(0f,1000f)});
    34.             em.SetSharedComponentData(entity, new RenderMesh {
    35.              
    36.                 mesh = mesh,
    37.                 material = material
    38.  
    39.             });
    40.             em.SetComponentData(entity, new Translation{Value = new Unity.Mathematics.float3(Random.Range(-10f,10f),9f,0f) });
    41.         }
    42.  
    43.         //Clean up the array as we do not need to keep it in memeory anymore.
    44.         entityArray.Dispose();
    45.     }
    46. }
    47.  
    Righto, I have made some progress with ECS but now encountered another hurdle which I am not sure that I can use

    Is it possible to use Coroutines in ECS??

    I have created a ECS script to just move some objects down the screen but as expected they are all on top of each other and spawn in a fixed line instead of spawning all at the same time??

    I designed this as a "Template" style srcipt that I can always refer to when i need a refresher.
     
    Last edited: Oct 14, 2019
  21. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,574
    Can you show screenshot, what you exactly mean?
    They should spawn at initialization, as executed in Start.
    What you mean exactly?
    Do you mean, they spawning longer than Initialization?
     
  22. Shabbalaka

    Shabbalaka

    Joined:
    Jan 15, 2018
    Posts:
    154
    I have posted an image now detailing what I am trying to achieve, Once again many thnaks!

    Am dreading trying to find out how to use Physics, Rigidbodys and Colliders to detect collisions using ECS...

    Eventually I want to place a Ground that when the blood rain hits it , it then creates a splash effect much like rain does in the real world.

    I thought if I post what I am aiming to achieve as a final goal it may give some insight into the directions and good tutorials I can look at.

    Using the Monobehaviour way I would know how to do this xD
     

    Attached Files:

    Last edited: Oct 14, 2019
  23. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,574
    There is multiple ways I can think of, of doing rain spawn staggering.
    If you want all rain drops spawn at single frame, then you would need some offset vertical position as well, to achieve sensible effect. You got only horizontal random position atm.

    But perhaps you want continuous rain?
    Then you would need run entities instantiating every frame and destroy, when hitting ground (below some y position), or when collide. I am not touching collision at the moment. But there are good examples.

    Achieving nice staggering would be first thing.

    Also, while you can run in entities creation in mono behaviour, you would be better start utilizing systems, as ECS should do.
     
  24. Shabbalaka

    Shabbalaka

    Joined:
    Jan 15, 2018
    Posts:
    154
    Yes I was looking to try and do continuous rain so when the rain drops collide with the ground they would destroy themselves and then instantiate a particle effect system to provide the "splash" effect.

    This is why I am looking to try and spawn X number of rain drops every 2 seconds or something.

    Code (CSharp):
    1.  IEnumerator SpawnRainDrops
    2.     {
    3.         NativeArray<Entity> entityArray = new NativeArray<Entity>(NumToCreate, Allocator.Temp);
    4.         em.CreateEntity(ea, entityArray);
    5.         for(int i = 0; i < entityArray.Length; i++)
    6.         {
    7.            
    8.             Entity entity = entityArray[i];
    9.  
    10.             em.SetComponentData(entity, new HealthComponent { Health = Random.Range(0f,1000f)});
    11.             em.SetSharedComponentData(entity, new RenderMesh {
    12.                
    13.                 mesh = mesh,
    14.                 material = material
    15.  
    16.             });
    17.             em.SetComponentData(entity, new Translation{Value = new Unity.Mathematics.float3(Random.Range(-10f,10f),9f,0f) });
    18.         }
    19.  
    20.         //Clean up the array as we do not need to keep it in memeory anymore.
    21.         entityArray.Dispose();
    22.        
    23.  
    24.        
    25.         yield return new WaitForSeconds(2);
    26.        
    27.        
    28.     }

    Although I am not sure I can use Coroutines in ECS.?
     
  25. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,574
    You don't need coroutines in ECS.
    Not sure why this idea is in your mind. Can you elaborate a bit more?

    If you use DOTS system, which typically is just runtime speed execution, you can have timer, which checks, how often new entities can be spawned.

    Mind, correctly execute DOTS systems, are insanely fast. But even withouth systems, you could use jobs with burst, and you would see massive improvement. But first, you need some working references :)

    The principle is pretty much the same, as if you would spawn GameObjects in Update, or FixedUpdate.

    I suggest look into DOTS samples and see how systems are organised, for simple case scenarios.
    And forget about coroutines at this stage.
     
    bugfinders likes this.
  26. bugfinders

    bugfinders

    Joined:
    Jul 5, 2018
    Posts:
    738
    I would expect to create rain you only create a small percentage of the required at anyone job, so that way they are staggered
     
  27. Shabbalaka

    Shabbalaka

    Joined:
    Jan 15, 2018
    Posts:
    154
    I really appreciate all the feedback and assistance everyone!

    I have started to make some slow progress with ECS now, I am trying to recreate Missile Command style of game (I made a version of this using GameObjects before, So I figured it would be a good place to start a ECS project)

    I am trying to recreate a script which basically took the players location and then fed that to all the enemies so the enemies can decide to attack the player or a base.

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using Unity.Transforms;
    5. using Unity.Entities;
    6. using Unity.Mathematics;
    7. using Unity.Collections;
    8.  
    9. public class LookToPlayerSystem : ComponentSystem
    10. {
    11.     public Translation playerPosition;
    12.     protected override void OnUpdate()
    13.     {
    14.         //Return the players position every frame so the units which chase the player know where the player is located.
    15.         Entity entity = Entities.ForEach((ref PlayerComponent player) =>
    16.         {    
    17.            playerPosition = entity.transform.position;
    18.         });
    19.  
    20.         //All the units with Translation and MoveSpeedComponents move towards the player.
    21.         Entities.ForEach ((ref Translation translation, ref MoveSpeedComponent movespeed) =>
    22.         {
    23.             //Slowly move the units towards the player.
    24.             Transform.MoveTowards(Transform.position, playerPosition.position);
    25.         });
    26.     }
    27. }
    28.  
    This is as far as I got with it, I know the coding is wrong but I hope that someone can point me in the right dirction for this.

    I can see the potential of using ECS and I like the idea of it but due to the lack of decent tutorials or "understandable" content at the moment it feels like walking through a field of land mines, But with forums like these to help and some nice people who are willing to lend their time and experience I feel I will get it eventually it,ll just "CLICK!", So I would just like to put out a big THANK YOU to all the people who spend their time replying to my posts!

    Thanks!
     
    Last edited: Oct 15, 2019
    bugfinders likes this.
  28. BanJaxe

    BanJaxe

    Joined:
    Nov 20, 2017
    Posts:
    47
    The basic idea is this:

    Code (csharp):
    1. protected override void OnUpdate()
    2.     {
    3.         var playerEntity = GetSingletonEntity<PlayerTag>();
    4.         var playerTranslation = EntityManager.GetComponentData<Translation>(playerEntity);
    5.  
    6.         Entities.WithAll<EnemyTag>().ForEach((ref Translation enemyTranslation, ref MoveSpeed moveSpeed) =>
    7.         {
    8.             var dirToPlayer = math.normalize(playerTranslation.Value - enemyTranslation.Value);
    9.             enemyTranslation.Value += dirToPlayer * moveSpeed.Value * Time.deltaTime;
    10.         });
    11.     }
    Components:

    Code (CSharp):
    1. public struct PlayerTag : IComponentData { }
    2.  
    3. public struct EnemyTag : IComponentData { }
    4.  
    5. public struct MoveSpeed : IComponentData
    6. {
    7.     public float Value;
    8. }
     
  29. Shabbalaka

    Shabbalaka

    Joined:
    Jan 15, 2018
    Posts:
    154
    Thanks so much BanJaxe!!

    I guess next step is Collisions, Do you know of a good tutorial or video that I can watch / read to understand how the Physics system works, As usual I will try to make working code myself and post my progress / attempts.

    I feel that I am slowly grasping the idea of the ECS system at the moment that I can create the entity and attach components and make use of the components within.

    My assumption for collisions is to attach Rigidbodys and Colliders and then use a System to detect collisions with other Colliders much like you do with GameObjects.

    But as usual back to Scouring the internet to find advice/help.

    Once agian thanks all to who replied!
     
  30. BanJaxe

    BanJaxe

    Joined:
    Nov 20, 2017
    Posts:
    47
  31. Shabbalaka

    Shabbalaka

    Joined:
    Jan 15, 2018
    Posts:
    154
    Thanks for the reply Banjaxe i,ll make an attempt at this collision/ distance querys and get back to you. xD

    Once again thanks!
     
  32. Shabbalaka

    Shabbalaka

    Joined:
    Jan 15, 2018
    Posts:
    154
    Just a update on my progress at the moment.

    I have developed a System to detect a radius around an entity and then change the color of all entities within a desired radius (This will emulate a collision with an object)

    The problem I.m having is that all of the enemys are changing their material color, Do i need to create a new color material in script and then assign that to the enemy ??

    Here is the current iteration of my radius detection script.

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using Unity.Entities;
    5. using Unity.Collections;
    6. using Unity.Transforms;
    7. using Unity.Rendering;
    8.  
    9. public class DistanceSystem : ComponentSystem
    10. {
    11.     public Entity Player;
    12.  
    13.     protected override void OnUpdate()
    14.     {
    15.  
    16.         Player = GetSingletonEntity<Player.PlayerTag>();
    17.        
    18.         //For each enemy in the game.
    19.         Entities.WithAll<Enemy.Unit>().ForEach((Entity entity, ref Translation enemyPos, ref MoveSpeedComponent msc) =>
    20.         {
    21.             if(Vector3.Distance(enemyPos.Value,  EntityManager.GetComponentData<Translation>(Player).Value) < EntityManager.GetComponentData<DistanceComponent>(Player).Radius)
    22.             {
    23.                 EntityManager.GetSharedComponentData<RenderMesh>(entity).material.SetColor("_Color",Color.white);
    24.             }
    25.  
    26.              Debug.Log("Distance between the 2 is " + Vector3.Distance(enemyPos.Value,  EntityManager.GetComponentData<Translation>(Player).Value));
    27.             Debug.Log("Distance allowed is " + EntityManager.GetComponentData<DistanceComponent>(Player).Radius);
    28.         });
    29.        
    30.        
    31.     }
    32. }
    33.  
    I have posted the Debug.Log information to the console.

    Thanks to all who might reply!
     

    Attached Files:

  33. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,574
    I suggest you look into forum topics around keywords
    DrawMesh, DrawMeshInstanced, DrawMeshInstancedIndirect.
    There are few more.
     
  34. Shabbalaka

    Shabbalaka

    Joined:
    Jan 15, 2018
    Posts:
    154
    Thanks for the reply, But that does not really help me as to why the "enemys" why the material is being changed for all of the enemys and not only the ones within the radius.

    The distance seems to be correct and some of them appear within the radius of detection so why is it not only being applied to those ?

    If you could explain a little better please it would be appreciated! :)

    Like this does not make much sense to me.

    I am quite new to C# (only been messing for about a year) so the "Manual" sometimes does not make much sense to me as most of my learning has been tutorials and guides.

    "
    Description
    Draw the same mesh multiple times using GPU instancing.

    Similar to Graphics.DrawMeshInstanced, this function draws many instances of the same mesh, but unlike that method, the arguments for how many instances to draw come from bufferWithArgs.

    Use this function in situations where you want to draw the same mesh for a particular amount of times using an instanced shader. Meshes are not further culled by the view frustum or baked occluders, nor sorted for transparency or z efficiency.

    Buffer with arguments, bufferWithArgs, has to have five integer numbers at given argsOffset offset: index count per instance, instance count, start index location, base vertex location, start instance location.
    "

    And in Laymans terms this means what exactly ? Why do I want to draw the same mesh multiple times??? or even many instances??

    Im not sure how this function assists me in what seems to be a simple Material.SetColor ??
     
    Last edited: Oct 22, 2019
  35. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,574
    Materials work a bit different in DOTS than with classic GameObjects.
    You want to use same mesh and same material, with slightly different property on it.
    It is way how things are efficiently rendered. GPU instancing is part of it.
    That why some of options are Graphics with DawMesh.

    Here is one of the thread, I was discussing that matter recently.
    Entity highlighting in jobs : material UV / Atlas / Shader

    But also please check other DOTS threads, which use above mentioned keywords.
    We have few discussions in that area, with a bit different approaches. And there are few examples as well.
    All may feel a bit scattered however.
     
  36. sngdan

    sngdan

    Joined:
    Feb 7, 2014
    Posts:
    1,131
    The simplest way to do this is to create two rendermeshes 1) with normal color and 2) with hit color - instead of setting color you change the render mesh depending on distance - this should work out of the box as you do this on the main thread

    This does not scale well and gets worse the more colors you have. Con: structural changes - sync point, not fully burstable, needs rendermesh per color,....
     
  37. Shabbalaka

    Shabbalaka

    Joined:
    Jan 15, 2018
    Posts:
    154
    Thanks for the replys!

    Ok i had a look at the MaterialPropertyBlock and this is what I came up with but I do not think it is correct. ]

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using Unity.Entities;
    5. using Unity.Collections;
    6. using Unity.Transforms;
    7. using Unity.Rendering;
    8.  
    9. public class DistanceSystem : ComponentSystem
    10. {
    11.     public Entity Player;
    12.     public MaterialPropertyBlock block;
    13.     public int ColorID;
    14.  
    15.     protected override void OnUpdate()
    16.     {
    17.  
    18.         Player = GetSingletonEntity<Player.PlayerTag>();
    19.      
    20.         //For each enemy in the game.
    21.         Entities.WithAll<Enemy.Unit>().ForEach((Entity entity, ref Translation enemyPos, ref MoveSpeedComponent msc) =>
    22.         {
    23.              if(Vector3.Distance(enemyPos.Value,  EntityManager.GetComponentData<Translation>(Player).Value) < EntityManager.GetComponentData<DistanceComponent>(Player).Radius)
    24.             {
    25.                     block = new MaterialPropertyBlock();
    26.                     block.SetColor(ColorID, Color.red);
    27.                     Graphics.DrawMesh(EntityManager.GetSharedComponentData<RenderMesh>(entity).mesh, new Vector3(0,0,0),Quaternion.identity,
    28.                     EntityManager.GetSharedComponentData<RenderMesh>(entity).material,0,null,0, block);
    29.              
    30.        
    31.             }
    32.  
    33.          
    34.         });
    35.      
    36.      
    37.     }
    38.  
    39. }
    40.  
    Im not sure if creating a new MaterialPropertyBlock() within the Update method is a good idea as everytime an Entity is within radius range we get a new instance of that Type(Class) created??

    But can you create a instance of the class outside of the OnUpdate loop just like whne you use the Start or Awake methods?

    Code (csharp):
    1.  
    2.                     Graphics.DrawMesh(EntityManager.GetSharedComponentData<RenderMesh>(entity).mesh, new Vector3(0,0,0),Quaternion.identity,
    3.                     EntityManager.GetSharedComponentData<RenderMesh>(entity).material,0,null,0, block);
    4.  
    Access the mesh property of the entitys mesh and material used within RenderMesh and
    change it to the color assigned to the variable block?

    Or am i thinking wrong?
     
    Last edited: Oct 25, 2019
  38. Shabbalaka

    Shabbalaka

    Joined:
    Jan 15, 2018
    Posts:
    154
    Ok this is working now but only changing the color and mesh of the Player entity... :S
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using Unity.Entities;
    5. using Unity.Collections;
    6. using Unity.Transforms;
    7. using Unity.Rendering;
    8.  
    9. public class DistanceSystem : ComponentSystem
    10. {
    11.     public Entity Player;
    12.  
    13.     public MaterialPropertyBlock block = new MaterialPropertyBlock();
    14.     public int ColorID = Shader.PropertyToID("_Color");
    15.  
    16.     protected override void OnUpdate()
    17.     {
    18.  
    19.         Player = GetSingletonEntity<Player.PlayerTag>();
    20.      
    21.         //For each enemy in the game.
    22.         Entities.WithAll<Enemy.Unit>().ForEach((Entity entity, ref Translation enemyPos, ref MoveSpeedComponent msc) =>
    23.         {
    24.              if(Vector3.Distance(enemyPos.Value,  EntityManager.GetComponentData<Translation>(Player).Value) < EntityManager.GetComponentData<DistanceComponent>(Player).Radius)
    25.             {
    26.                  
    27.                     block.SetColor(ColorID, Color.green);
    28.                     Graphics.DrawMesh(EntityManager.GetSharedComponentData<RenderMesh>(entity).mesh, new Vector3(0,0,0),Quaternion.identity,
    29.                     EntityManager.GetSharedComponentData<RenderMesh>(entity).material,0,null,0, block);
    30.                      Debug.Log("Distance between the 2 is " + Vector3.Distance(enemyPos.Value,  EntityManager.GetComponentData<Translation>(Player).Value));
    31.                     Debug.Log("Distance allowed is " + EntityManager.GetComponentData<DistanceComponent>(Player).Radius);
    32.                      Debug.Log(entity.Index);
    33.                      Debug.Log("----------------------------------------");
    34.          
    35.             }
    36.  
    37.          
    38.         });
    39.      
    40.      
    41.     }
    Any idea why this is happening please??

    Also when this runs it also changes the Mesh of Player from a Sphere to a Cube and turns it green ?? (As shown in the image (Left = DistanceSystem disabled, Right = DistanceSystem enabled)....
     

    Attached Files:

  39. sngdan

    sngdan

    Joined:
    Feb 7, 2014
    Posts:
    1,131
    why don't you start with the simplest way and just use two RenderMeshes, each with an individual material for the two different colors?

    Code (CSharp):
    1. if (condition)
    2.    em.SetSharedComponentData(entity, renderMeshRed);
    3. else
    4.    em.SetSharedComponentData(entity, renderMeshGreen);
     
  40. Shabbalaka

    Shabbalaka

    Joined:
    Jan 15, 2018
    Posts:
    154
    Thanks for the reply,

    I will give that way a try, But I still would like to understand why that code is not working. ;)
     
  41. Enoch

    Enoch

    Joined:
    Mar 19, 2013
    Posts:
    198
    sngDan is right that is the way to accomplish what you are trying to do.

    The reason why your current DrawMesh method is likely not working is because you are drawing all enemy entities that meet the criteria (are within the distance) at 0,0,0 so that is probably right overtop of the player entity. the player sphere is likely still there just being covered up by the DrawMesh call. Note that DrawMesh doesn't prevent your enemy entities from being rendered normally since they have a RenderMesh attached. All it does is make an extra drawmesh somewhere else that you specify (0,0,0 in this case).

    Hope this helps.
     
  42. Shabbalaka

    Shabbalaka

    Joined:
    Jan 15, 2018
    Posts:
    154
    Many thanks for the replies,

    Ahh that makes sense Enoch, Sorry I am really new to doing everything in code, I am too used to using GameObjects and using the Inspector view to add materials, particle effects and other things, and then doing the logic side with things like OverLapSphere, and Raycasts.

    Maybe I can update that code to use the entitys current position, I am not at my main PC so cannot access the project but something along the lines of entity.transform.position(I know I cannot use Transform.Position as Entitys use Translation for positional information but you get the idea.

    I can understand that I could use 2 RenderMeshes but then how do I assign the values of these meshes, Because I would normally create the Material and then drag that material into the inspector to assign it.

    I am guessing that I would have to create a New Material object and then assign various properties and then use RenderMesh.Material = my New Material or something to this effect??

    Also if anyone has a tutorial for how to apply nested meshes to entitys, It would be super useful as I downloaded a spaceship model from the store but it was a modular spaceship so had several children objects and creating entitys of this seemed difficult.

    I am keeping this thread alive with these posts/queries as I am hoping that all of this information will help others also.
     
  43. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,574
    My initial highlight system was simply replacing shared renderMesh. renderMesh had assigned relevant material, which was simply predefined prefab.

    Not ideal for highlighting, or changing many materials at once, but worked well, for fewer meshes.
     
  44. Shabbalaka

    Shabbalaka

    Joined:
    Jan 15, 2018
    Posts:
    154
    How do you reassign the material value in RenderMesh though as when I use SetSharedComponentData it asks me to create a new one also like I cannot modify the existing value held within material ? ?

    Upon creation I set the material to a "default" one which is OutOfRange and then how do you access the InRange material hel within the enemy script??

    Also using ECS does all the values in the Enemy script pass through the entity so you can access all the values held within the Enemy script??

    Or Can ECS systems only change values held within Components?

    For example if i do Debug.Log(EntityManager.GetSharedComponentData<RenderMesh>(entity).material) this does print out OutOfRnage but how do i access the value within the InRange

    Sorry if this is a really simple thing which I am failing to understand for some reason.
     

    Attached Files:

    Last edited: Oct 26, 2019
  45. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,574
    I created materials and required meshes at initialization. Then populated prefab component with available render meshes, which I could load at runtime at later time.

    Simpler example used in my Octree.
    https://github.com/Antypodish/ECS-Octree/tree/master/ECS-Octree/Assets/Scripts/ECS/Highlight
    While it works well, for what I needed, this of has own flows. This highlight approach, of swaping render mesh is not very callable.

    Now I am shifting away from this method, as I need more materials properties to be modified at runtime using shaders.
     
  46. sngdan

    sngdan

    Joined:
    Feb 7, 2014
    Posts:
    1,131
    In this 200k thread linked here earlier, I left a proof of concept that is quite simple and highly optimized. It should work for your use case - it works with any mesh (not only quad), sends local to world to shader (works in 3d) and has color as an individual attribute (icomponentdata)

    but as mentioned earlier start simple with two rendermeshes- is your problem that you cannot set them as member variables for your highlight system?
     
  47. Shabbalaka

    Shabbalaka

    Joined:
    Jan 15, 2018
    Posts:
    154
    Yes I am struggling to understand how you can assign 2 Materials to 1 RenderMesh so you can switch them in and out alternatively.

    Or

    Do I need to assign 2 RenderMeshes both with the same Mesh model and the 2 different Materials, Sorry if this is me being really stupid.
     
  48. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,574
    For simplicity, create just another messh with its designated material.
     
    Last edited: Oct 27, 2019
  49. sngdan

    sngdan

    Joined:
    Feb 7, 2014
    Posts:
    1,131
    Yes

    ps: try to avoid creating another mess ;)
     
    Antypodish likes this.
  50. Shabbalaka

    Shabbalaka

    Joined:
    Jan 15, 2018
    Posts:
    154

    lol thanks for the reply, I feel so stupid trying to learn this it almost feels like I have gone back about a year or so when learning unity. xD
     
    bugfinders and MNNoxMortem like this.