As a bit of extracurricular activity, I’m not extra happy about how we signal that a player cannot move to a certain place if it’s too far, because I feel using the no activity cursor might tell a player that an area is unreachable tout court, while in fact it’s just a matter of indicating some waypoints.
So I added a second out parameter in RaycastNavMesh, which now looks like this:
private bool RaycastNavMesh(out Vector3 target, out bool isPathTooLong)
{
isPathTooLong = false;
target = new Vector3();
RaycastHit raycastHit;
bool hasHit = Physics.Raycast(GetMouseRay(), out raycastHit);
if (!hasHit) { return false; }
NavMeshHit navMeshHit;
bool hasCastToNavMesh = NavMesh.SamplePosition(raycastHit.point, out navMeshHit, _maxNavMeshProjectionDistance, NavMesh.AllAreas);
if (!hasCastToNavMesh) { return false; }
target = navMeshHit.position;
NavMeshPath path = new NavMeshPath();
bool hasPath = NavMesh.CalculatePath(transform.position, target, NavMesh.AllAreas, path);
if (!hasPath) { return false; }
if (path.status != NavMeshPathStatus.PathComplete) { return false; }
if (GetPathLength(path) > _maxNavPathLength)
{
isPathTooLong = true;
return false;
}
return true;
}
and then I check it to assign the correct cursor in InteractWithMovement like this:
private bool InteractWithMovement()
{
bool isPathTooLong;
Vector3 target;
bool hasHit = RaycastNavMesh(out target, out isPathTooLong);
if (hasHit)
{
if (Input.GetMouseButton(0))
{
float speedModifier = 1f;
if (_isWalking)
{
speedModifier = _walkingSpeedFraction;
}
_mover.StartMoveAction(target, speedModifier);
}
SetCursor(CursorType.Movement);
return true;
}
if (isPathTooLong)
{
SetCursor(CursorType.PathTooLong);
}
else
{
SetCursor(CursorType.None);
}
return false;
}
Finally, I removed the last SetCursor(CursorType.None) from Update, because it’s now reduntant (RaycastNavMesh already covers the case when the cursor is over nothing) and interferes with this new cursor setting (from what I could debug, if RaycastNavMesh() returns false, InteractWithMovement() returns false too, which means that Updates does not return after calling it and moves on to that one last cursor set, overwriting whatever InteractWithMovement did, which causes flickering):
private void Update()
{
if (Input.GetKeyDown(KeyCode.CapsLock))
{
_isWalking = !_isWalking;
}
if (InteractWithUI()) { return; }
if (_health.IsDead())
{
SetCursor(CursorType.None);
return;
}
if (InteractWithComponent()) { return; }
if (InteractWithMovement()) { return; }
}
I tested it, and it all seems to work fine, new and old cursor types displaying correctly, including showing the none cursor if we’re pointing over unreachable areas or outside the map.
I don’t know if anyone could find this interesting, but I thought I could share. Also, it would be interesting to know if I did more or less the right thing, or if this is a kludge and there’s a better way to do it.