Hello everyone
I have two systems: one that moves objects with MovementComponent and another that sets a new target to them when you click rightMouseButton on the terrain. So the first system (MovementSystem) uses a job in its workflow. Considering that MovementSystem only reads the MovementComponent (where target and speed values are stored) and TargetingSystem (==MouseTargetingSystem in the error) writes to that component, I put the UpdateBefore(typeof(MovementSystem)) attribute for the TargetingSystem and thought it must be okay. But when I click the rightMouseButton often (not every time, but often) there is an error:
As I understand, it says that somehow it was created a race condition between my two systems. But how if only one is writing there. Moreover it writes info there in the main thread, so MovementSystem dont update until TargetingSystem end its work. If I add a moveJobHandle.Complete() in the MovementSystem it works fine without any errors. But I still do not understand why it is the case. Moreover I thought that UnityDOTS automatically adds a state.Dependency-s things everywhere it is needed to be. Isn
t it the dependency which UnityDOTS should have processed by itself? If no, then I also do not understand this automatics (it was mentioned in official Unity sample video - 10:50 timing
Here is my code:
[BurstCompile]
public partial struct MovementSystem : ISystem
{
[BurstCompile]
public void OnCreate(ref SystemState state)
{
state.RequireForUpdate<MovementComponent>();
}
[BurstCompile]
public void OnUpdate(ref SystemState state)
{
var moveJob = new MovementJob { time = SystemAPI.Time.DeltaTime, collisionWorld = SystemAPI.GetSingleton<PhysicsWorldSingleton>().CollisionWorld };
moveJob.Schedule();
}
[BurstCompile]
public void OnDestroy(ref SystemState state)
{
}
}
[BurstCompile]
public partial struct MovementJob : IJobEntity
{
public float time;
public CollisionWorld collisionWorld;
public void Execute(ref LocalTransform transform, in MovementComponent movementComponent)
{
float3 tempDir = movementComponent.target - transform.Position;
tempDir.y = 0;
float3 dir = math.normalize(tempDir);
if (math.distancesq(movementComponent.target, transform.Position) < 1f)
return;
CollisionFilter filter = new CollisionFilter
{
BelongsTo = ~0u,
CollidesWith = 1u << 7,
GroupIndex = 0
};
float3 originPointDistance = transform.Position;
originPointDistance.y -= 1f;
var pointDistanceInput = new PointDistanceInput { Filter = filter, Position = originPointDistance, MaxDistance = 1.5f };
if (collisionWorld.CalculateDistance(pointDistanceInput, out DistanceHit closestHit))
{
transform.Position.y = closestHit.Position.y + 1;
transform.Rotation = quaternion.LookRotation(transform.Forward(), closestHit.SurfaceNormal);
}
else
{
Debug.Log("ERROR: Terrain under unit is not found");
}
transform.Position += dir * time * movementComponent.speed;
}
}
[UpdateBefore(typeof(MovementSystem))]
public partial struct MouseTargetingUnits : ISystem
{
public void OnCreate (ref SystemState state)
{
state.RequireForUpdate<MovementComponent>();
}
public void OnUpdate(ref SystemState state)
{
if (Mouse.current.rightButton.wasPressedThisFrame && CheckCursorOnTerrain(out Unity.Physics.RaycastHit newTarget))
{
foreach (var movement in SystemAPI.Query<RefRW<MovementComponent>>())
{
movement.ValueRW.target = newTarget.Position;
}
}
}
private bool CheckCursorOnTerrain(out Unity.Physics.RaycastHit newTarget)
{
var collisionWorld = SystemAPI.GetSingleton<PhysicsWorldSingleton>().CollisionWorld;
UnityEngine.Ray ray = Camera.main.ScreenPointToRay(Mouse.current.position.value);
RaycastInput raycastInput = new RaycastInput
{
Start = ray.origin,
End = ray.GetPoint(1000f),
Filter = new CollisionFilter
{
BelongsTo = ~0u,
CollidesWith = 1u << 7,
GroupIndex = 0
}
};
newTarget = new Unity.Physics.RaycastHit();
return collisionWorld.CastRay(raycastInput, out newTarget);
}
}
And also an additional small question. If I schedule the MovementJob without BurstCompiling it runs on the main thread, if I got it right in the Profiler. So does it mean that using worker threads is possible only with BurstCompiling?