Hello everyone
I am trying to make my entity (cylinder) to rotate depending on the terrain under it. So that cylinder is always standing perpendicular to the terrain. I tried to do this by using PointDistance collision query but as you can see on the video it doesn`t work as well as I want:
For me my code seems to be logical and right (but of course it is not true if I have such issues with it):
[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);
}
}
[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 };
JobHandle a = moveJob.Schedule(state.Dependency);
a.Complete();
}
[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;
}
}
So what is the problem here? Also if anyone knows a better solution for that problem, I will appreciate it as well. But in any case I am interested in understanding the roots of my problem