Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 13 Next capture
2021 2022 2023
1 capture
13 Jun 22 - 13 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
1
Question by Hawaii_Dev · May 27 at 03:51 PM · gameplaydots

How to organize interactions between entities on a grid? (ecs/dots)


I have an entity representing a plant. The entity has some components such as Grow, Age, GridCoord, Spread. When the Spread component timer reaches a threshold the plant should spread to nearby cells. The cells are 32 x 32 entities with their own logic.


How can I communicate between the Spread component and the cell at the Spread coordinate to mark that cell as "occupied" so that no more than one plant can occupy a single cell?


I have tried keeping a NativeArray of a component on the cells and changing that NativeArray at the correct index but that doesn't work as the entity connected to that component doesn't update.


Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

1 Reply

· Add your reply
  • Sort: 
avatar image
2

Answer by andrew-lukasik · May 28 at 01:14 AM


dots grid system ISystemStateComponentData


 // src: https://gist.github.com/andrew-raphael-lukasik/19170443b976582f97404f6da9875b4c
 using UnityEngine;
 using Unity.Entities;
 using Unity.Mathematics;
 using Unity.Collections;
 using Unity.Jobs;
 
 namespace Sandbox
 {
     public class Planted : MonoBehaviour
     {
         [SerializeField] int _numPlantsOnStart = 5;
         [SerializeField] int2 _coordMinOnStart = -10, _coordMaxnOnStart = 10;
         EntityManager _entityManager;
         EntityQuery _query;
 
         void Start ()
         {
             var world = World.DefaultGameObjectInjectionWorld;
             _entityManager = world.EntityManager;
             _query = _entityManager.CreateEntityQuery( ComponentType.ReadOnly<Coord>() , ComponentType.ReadOnly<Spread>() , ComponentType.ReadOnly<Gene>() );
             var prefabs = world.GetOrCreateSystem<PrefabSystem>();
             var rnd = new Unity.Mathematics.Random( (uint) System.DateTime.Now.GetHashCode() );
             for( int i=0 ; i<_numPlantsOnStart ; i++ )
             {
                 Entity plantInstance = _entityManager.Instantiate( prefabs.Plant );
                 _entityManager.SetComponentData( plantInstance , new Coord{
                     Value = rnd.NextInt2( _coordMinOnStart , _coordMaxnOnStart )
                 } );
                 _entityManager.SetComponentData( plantInstance , new Age{
                     Value = rnd.NextFloat( 0f , rnd.NextFloat(Age.limit*0.1f) )
                 } );
 
                 var genes = _entityManager.GetBuffer<Gene>( plantInstance );
                 Color32 colorBytes = Color.HSVToRGB( rnd.NextFloat(1f) , 1f , 1f );
                 genes.Add( colorBytes.r );
                 genes.Add( colorBytes.g );
                 genes.Add( colorBytes.b );
             }
         }
         #if UNITY_EDITOR
         void OnDrawGizmos ()
         {
             if( !Application.isPlaying ) return;
             
             int len = _query.CalculateEntityCount();
             var entities = _query.ToEntityArray(Allocator.Temp).ToArray();
             var coords = _query.ToComponentDataArray<Coord>(Allocator.Temp).ToArray();
             for( int i=0 ; i<len ; i++ )
             {
                 var genes = _entityManager.GetBuffer<Gene>( entities[i] );
                 Gizmos.color = new Color32( genes[0] , genes[1] , genes[2] , 255 );
                 
                 int2 coord = coords[i].Value;
                 Gizmos.DrawSphere( new Vector3( coord.x , coord.y , 0 ) , 0.5f );
             }
         }
         #endif
     }
 
     public struct Coord : IComponentData
     {
         public int2 Value;
     }
     public struct Age : IComponentData
     {
         public float Value;
         public const float limit = 10f;
     }
     public struct Spread : IComponentData
     {
         public float Value;
         public const float spread_threshold = 2f;
     }
     [InternalBufferCapacity(5)]
     public struct Gene : IBufferElementData
     {
         public byte Value;
         public static implicit operator byte ( Gene value ) => value.Value;
         public static implicit operator Gene ( byte value ) => new Gene{ Value=value };
     }
 
     [UpdateInGroup( typeof(SimulationSystemGroup) )]
     public partial class SpreadSystem : SystemBase
     {
         EntityCommandBufferSystem _ecbSystem;
         GridSystem _gridSystem;
         PrefabSystem _prefabs;
         protected override void OnCreate ()
         {
             base.OnCreate();
             _ecbSystem = World.GetOrCreateSystem<EndSimulationEntityCommandBufferSystem>();
             _gridSystem = World.GetOrCreateSystem<GridSystem>();
             _prefabs = World.GetOrCreateSystem<PrefabSystem>();
         }
         protected override void OnUpdate ()
         {
             float deltaTime = Time.DeltaTime;
             uint rndHash = (uint) Time.ElapsedTime.GetHashCode();
             var grid = _gridSystem.Lookup;
             var plantPrefab = _prefabs.Plant;
             var geneBuffers = GetBufferFromEntity<Gene>( isReadOnly:false );
             var cmd = _ecbSystem.CreateCommandBuffer().AsParallelWriter();
 
             this.Dependency = JobHandle.CombineDependencies( Dependency , _gridSystem.LookupDependency );
 
             Entities
                 .WithReadOnly( grid )
                 .WithAll<Gene>()
                 .ForEach( ( ref Spread spread , in Coord coord , in Entity e , in int nativeThreadIndex ) =>
                 {
                     spread.Value += deltaTime;
 
                     if( spread.Value>Spread.spread_threshold )
                     {
                         var rnd = new Unity.Mathematics.Random( rndHash + (uint)e.GetHashCode() + (uint)nativeThreadIndex.GetHashCode() );
                         var myGenes = geneBuffers[e];
 
                         int2 spreadAttemptCoord = coord.Value + rnd.NextInt2( -2 , 2 );
                         if( !grid.ContainsKey(spreadAttemptCoord) )// is this spot free
                         {
                             var newPlant = cmd.Instantiate( nativeThreadIndex , plantPrefab );
                             cmd.SetComponent( nativeThreadIndex , newPlant , new Coord{ Value=spreadAttemptCoord } );
                             cmd.SetComponent( nativeThreadIndex , newPlant , new Spread{ Value=rnd.NextFloat(0f,Spread.spread_threshold*0.5f) } );
                             cmd.SetComponent( nativeThreadIndex , newPlant , new Age{ Value=rnd.NextFloat(0f,Age.limit*0.1f) } );
                             // propagate genes with slight mutation:
                             const byte mutation_range_half = 30;
                             cmd.AppendToBuffer<Gene>( nativeThreadIndex , newPlant , (byte)math.clamp( myGenes[0] + rnd.NextInt(-mutation_range_half,mutation_range_half+1) , 0 , 255 ) );
                             cmd.AppendToBuffer<Gene>( nativeThreadIndex , newPlant , (byte)math.clamp( myGenes[1] + rnd.NextInt(-mutation_range_half,mutation_range_half+1) , 0 , 255 ) );
                             cmd.AppendToBuffer<Gene>( nativeThreadIndex , newPlant , (byte)math.clamp( myGenes[2] + rnd.NextInt(-mutation_range_half,mutation_range_half+1) , 0 , 255 ) );
                         }
                         else// it's taken so lets attempt cross-pollination
                         {
                             foreach( var other in grid.GetValuesForKey(spreadAttemptCoord) )
                             if( geneBuffers.HasComponent(other) )
                             {
                                 var otherGenes = geneBuffers[other];
                                 otherGenes[0] = rnd.NextBool() ? otherGenes[0] : myGenes[0];
                                 otherGenes[1] = rnd.NextBool() ? otherGenes[1] : myGenes[1];
                                 otherGenes[2] = rnd.NextBool() ? otherGenes[2] : myGenes[2];
                             }
                         }
 
                         spread.Value = 0;
                     }
                 } )
                 .WithBurst()
                 .Schedule();
 
             _ecbSystem.AddJobHandleForProducer( Dependency );
         }
     }
 
     [UpdateInGroup( typeof(SimulationSystemGroup) )]
     public partial class AgeSystem : SystemBase
     {
         EntityCommandBufferSystem _ecbSystem;
         protected override void OnCreate ()
         {
             base.OnCreate();
             _ecbSystem = World.GetOrCreateSystem<EndSimulationEntityCommandBufferSystem>();
         }
         protected override void OnUpdate ()
         {
             float deltaTime = Time.DeltaTime;
             var cmd = _ecbSystem.CreateCommandBuffer().AsParallelWriter();
 
             Entities
                 .ForEach( ( ref Age age , in Entity e , in int nativeThreadIndex ) =>
                 {
                     age.Value += deltaTime;
                     
                     if( age.Value>Age.limit )
                         cmd.DestroyEntity( nativeThreadIndex , e );
                 } )
                 .WithBurst()
                 .ScheduleParallel();
             
             _ecbSystem.AddJobHandleForProducer( Dependency );
         }
     }
 
     [UpdateInGroup( typeof(SimulationSystemGroup) , OrderFirst=true )]
     public partial class GridSystem : SystemBase
     {
         /// <summary> Read-Only </summary>
         public NativeMultiHashMap<int2,Entity> Lookup { get; private set; }
         public JobHandle LookupDependency => base.Dependency;
         EntityCommandBufferSystem _ecbSystem;
         EntityQuery _queryNew;
         protected override void OnCreate ()
         {
             base.OnCreate();
             _ecbSystem = World.GetOrCreateSystem<EndSimulationEntityCommandBufferSystem>();
             _queryNew = EntityManager.CreateEntityQuery( new EntityQueryDesc{
                 None = new ComponentType[]{ ComponentType.ReadOnly<Tracked>() } ,
                 All = new ComponentType[]{ ComponentType.ReadOnly<Coord>() }
             } );
             Lookup = new NativeMultiHashMap<int2,Entity>( 1024 , Allocator.Persistent );
         }
         protected override void OnDestroy ()
         {
             base.OnDestroy();
             Lookup.Dispose();
         }
         protected override void OnUpdate ()
         {
             var cmd = _ecbSystem.CreateCommandBuffer().AsParallelWriter();
             var lookup = Lookup;
             var lookupPW = Lookup.AsParallelWriter();
 
             int countNewToLookup = _queryNew.CalculateEntityCount();
             if( countNewToLookup!=0 && (lookup.Count()+countNewToLookup)>lookup.Capacity/2 )
             {
                 lookup.Capacity = Mathf.Max( lookup.Count()+countNewToLookup , lookup.Capacity*2 );
                 Debug.Log($"{nameof(GridSystem)}.{nameof(Lookup)} capacity increased to {lookup.Capacity}");
             }
 
             Entities
                 .WithName("coord_created_job")
                 .WithNone<Tracked>()
                 .ForEach( ( in Coord coord , in Entity e , in int nativeThreadIndex ) =>
                 {
                     lookupPW.Add( coord.Value , e );
                     cmd.AddComponent<Tracked>( nativeThreadIndex , e , new Tracked{ Value=coord.Value } );
                 } )
                 .WithBurst()
                 .ScheduleParallel();
             
             Entities
                 .WithName("coord_destroyed_job")
                 .WithNone<Coord>()
                 .ForEach( ( in Tracked tracked , in Entity e , in int nativeThreadIndex ) =>
                 {
                     lookup.Remove( tracked.Value , e );
                     cmd.RemoveComponent<Tracked>( nativeThreadIndex , e );
                 } )
                 .WithBurst()
                 .Schedule();
             
             _ecbSystem.AddJobHandleForProducer( Dependency );
         }
         struct Tracked : ISystemStateComponentData { public int2 Value; }
     }
 
     [DisableAutoCreation]
     [UpdateInGroup( typeof(InitializationSystemGroup) )]
     public partial class PrefabSystem : SystemBase
     {
         public Entity Plant { get; private set; }
         protected override void OnCreate ()
         {
             base.OnCreate();
             this.Enabled = false;
             Plant = EntityManager.CreateEntity( typeof(Prefab) , typeof(Coord) , typeof(Age) , typeof(Spread) , typeof(Gene) );
         }
         protected override void OnUpdate () {}
     }
 
 }



gif-28052022-13-46-06v2.gif (514.6 kB)
Comment
Add comment · Show 1 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Llama_w_2Ls · May 29 at 10:05 AM 1
Share

Beautiful answer as always..

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

802 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

My Skybox Stopped Working... 3 Answers

Is it possible to use a map editor like Tiled with Unity3D? 0 Answers

Mouse input feels sketchy. Any way to fix? 1 Answer

loading screen usage 2 Answers

Is there a better way for randomization for triggering a percentage of the time 1 Answer


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges