Like a few others I want to explore the idea of cell dynamics within DOTS.
I am trying to create at runtime a list of neighbors per cell for later analysis.
The neighboring entities should live in a Dynamic buffer as I wanted an iteratable collection and had been lead to believe Lists, Dictionaries and their native counterparts are unavailable on entities.
using Unity.Entities;
using Unity.Mathematics;
[GenerateAuthoringComponent]
public struct NeighborhoodData : IComponentData
{
public DynamicBuffer<EntityAddresseBuffer> neighborhood;
}
public struct EntityAddresseBuffer : IBufferElementData
{
public int3 address; //-1,-1,-1 bottom, left, back - 1,1,1 top, right, front
public Entity entity;
}
The following should, when the cell spawns, raycast the 8 2d nearest neighbor directions and then add any hits to the dynamic buffer.
using Unity.Entities;
using Unity.Jobs;
using Unity.Transforms;
using Unity.Physics;
using Unity.Mathematics;
using Unity.Collections;
[AlwaysSynchronizeSystem]
public class BlockSystem : JobComponentSystem
{
protected override JobHandle OnUpdate(JobHandle inputDeps)
{
return default;
}
protected override void OnStartRunning()
{
base.OnStartRunning();
NativeArray<int3> neighborhoodAddresses = new NativeArray<int3>(new int3[]
{
new int3(-1, -1, 0), new int3(0, -1, 0), new int3(1, -1, 0),
new int3(-1, 0, 0), new int3(1, 0, 0),
new int3(-1, 1, 0), new int3(0, 1, 0), new int3(1, 1, 0),
}, Allocator.Temp);
Entities.WithoutBurst().ForEach
(
(ref NeighborhoodData neighborhood, ref Translation translation) =>
{
foreach(int3 address in neighborhoodAddresses)
{
float3 dir = translation.Value + new float3(address);
Entity hit = Raycast(translation.Value, dir);
EntityAddresseBuffer eab = new EntityAddresseBuffer();
eab.address = address;
eab.entity = hit;
neighborhood.neighborhood.Add(eab);
}
}
).Run();
neighborhoodAddresses.Dispose();
}
//mostly Copied from the DOTS physics raycast docs
public Entity Raycast(float3 RayFrom, float3 RayTo)
{
var physicsWorldSystem = GameManager.main.physicsWorld;
var collisionWorld = physicsWorldSystem.PhysicsWorld.CollisionWorld;
RaycastInput input = new RaycastInput()
{
Start = RayFrom,
End = RayTo,
Filter = new CollisionFilter()
{
BelongsTo = ~0u,
CollidesWith = ~0u, // all 1s, so all layers, collide with everything
GroupIndex = 0
}
};
RaycastHit hit = new RaycastHit();
bool haveHit = collisionWorld.CastRay(input, out hit);
if (haveHit)
{
// see hit.Position
// see hit.SurfaceNormal
Entity e = physicsWorldSystem.PhysicsWorld.Bodies[hit.RigidBodyIndex].Entity;
return e;
}
return Entity.Null;
}
}
but I get the following error:
InvalidOperationException: NeighborhoodData used in NativeArray must be unmanaged (contain no managed types) and cannot itself be a native container type.
Unity.Collections.NativeArray`1[T].IsUnmanagedAndThrow () (at <0d01204b437e47c1a78b600b597a89f4>:0)
Obviously I need to remove the managed type from this script, but am unsure what part it could be other than the DynamicBuffer and can’t think of an alternative that wouldn’t just be hard coding each neighbor.