- Home /
ECS follow entity
I was playing around with the new entity component system and I came across a problem I was not able to solve. I try to make an entity follow another entity. I want to do it in a job and not on the main thread. I already wrote some code in order to accomplish that:
FollowEntityComponent.cs
using Unity.Entities;
using Unity.Mathematics;
public struct FollowEntityComponent : IComponentData
{
public Entity entityToFollow;
public float3 offset;
}
FollowEntitySystem.cs
using Unity.Entities;
using Unity.Mathematics;
using Unity.Transforms;
using Unity.Jobs;
using Unity.Burst;
using Unity.Collections;
public class FollowEntitySystem : JobComponentSystem
{
struct FollowEntityJob : IJobForEach<Translation, FollowEntityComponent>
{
[ReadOnly] public ComponentDataFromEntity<Translation> translationComponentFromEntityToFollow;
public void Execute(ref Translation translationComponent, ref FollowEntityComponent followEntityComponent)
{
if (!translationComponentFromEntityToFollow.Exists(followEntityComponent.entityToFollow))
{
return;
}
float3 entityToFollowPosition = translationComponentFromEntityToFollow[followEntityComponent.entityToFollow].Value;
translationComponent.Value = entityToFollowPosition + followEntityComponent.offset;
}
}
protected override JobHandle OnUpdate(JobHandle inputDeps)
{
FollowEntityJob followEntityJob = new FollowEntityJob()
{
translationComponentFromEntityToFollow = GetComponentDataFromEntity<Translation>(true)
};
return followEntityJob.Schedule(this, inputDeps);
}
}
The code does actually compile, however, I get the following error when I hit play:
InvalidOperationException: The writable NativeArray FollowEntityJob.Iterator is the same NativeArray as FollowEntityJob.Data.translationComponentFromEntityToFollow, two NativeArrays may not be the same (aliasing).
I already figured out why I am getting this error message. It is because I am having a Translation component in IJobForEach<Translation, FollowEntityComponent>
and in [ReadOnly] public ComponentDataFromEntity<Translation> translationComponentFromEntityToFollow;
this seems to cause the error. (See: https://www.youtube.com/watch?v=KuGRkC6wzMY , minute: 21:53). However, even when I know the reason I can not figure out a better way of accomplishing what I want to do. I would be very thankful if somebody could provide me a solution to my problem.
Answer by Metalar · Feb 05, 2020 at 04:44 PM
Hello @FelixKahle ,
not sure if you already figured it out, but I found a solution: The problem is, as @Igarczyn already stated, the aliasation. However, you can avoid that by not depending on the Translation
component, but the LocalToWorld
component instead.
So you can adjust your code like this:
public class FollowEntitySystem : JobComponentSystem
{
struct FollowEntityJob : IJobForEach<Translation, FollowEntityComponent>
{
[ReadOnly] public ComponentDataFromEntity<LocalToWorld> localToWorldFromEntityToFollow;
public void Execute(ref Translation translationComponent, ref FollowEntityComponent followEntityComponent)
{
if (!localToWorldFromEntityToFollow.Exists(followEntityComponent.entityToFollow))
{
return;
}
float3 entityToFollowPosition = localToWorldFromEntityToFollow[followEntityComponent.entityToFollow].Position;
translationComponent.Value = entityToFollowPosition + followEntityComponent.offset;
}
}
protected override JobHandle OnUpdate(JobHandle inputDeps)
{
FollowEntityJob followEntityJob = new FollowEntityJob()
{
localToWorldFromEntityToFollow = GetComponentDataFromEntity<LocalToWorld>(true)
};
return followEntityJob.Schedule(this, inputDeps);
}
}
Answer by lgarczyn · Jan 11, 2020 at 11:45 AM
The problem is not in this code, you are passing overlapping pointers (in that case likely the same array) to both arguments of the function to run your entities.
Passing the same array (aliazation error) is likely an error, but also extremely dangerous for a number of reasons regarding optimization and memory safety.
Answer by FelixKahle · Jan 11, 2020 at 04:17 PM
But how would you overcome the problem that you have to read the position (translation) of the entity to follow as well as write to the position (translation as well) from the entity, which should follow the other one. I cant figure out how I should design a solution for that problem.
Taking a shot in the dark but have you considered using Archetypes to distinguish entities in memory? for example, using a Follower Component for followers and a $$anonymous$$er Component for leaders? This could be done at runtime (Spawn Ghost... add leader component, spawn goat, add follower component) as Unity will update archetypes dynamically based on their components.
But then I would still have the problem that I need to write and read from translation components (gain translation from leader by using ComponentDataFromEntity and write to the translation from the follower in the job). This would cause the same error I think.
@Felix$$anonymous$$ahle I'm not sure it would? If they are different archetypes then you should be able to read/write to both of them without worrying as Unity stores then in separate memory chunks. I'm still getting my head around ECS so I could be totally wrong. $$anonymous$$aybe two iterations? Iterate through all entities with the leader component (and get the position of a single or multiple entities) and then iterate through all entities with a follower component, and update their position.
Your answer

Follow this Question
Related Questions
Multiple Cars not working 1 Answer
Distribute terrain in zones 3 Answers
I am having a problem with the following script 1 Answer
rigidbody AddForce(transform.left) error 1 Answer
[Answered] Error CS0019: Operator `==' cannot be applied 1 Answer