I am working on a "quick project" to get my feet wet and to put something finished in my projects. I want to make an enemy that constantly tries to be aligned with the player object, but doesn't always move directly toward it, and which only moves in 8 cardinal directions. The idea is that if the enemy is not aligned with the player on the X axis, then the enemy will attempt to rectify by moving on the X axis until the player and enemy object are on the same x axis. At that point, the enemy should not move at all on the X axis unless the player changes its own X-position.
I coded this as the following:
void OnEnable()
{
playerRef = FindObjectOfType<Player>();
}
void Update()
{
if (playerRef != null)
{
UpdatePlayerLocation();
TryMove(playerPosition);
}
else
{
playerRef = FindObjectOfType<Player>();
}
}
void UpdatePlayerLocation()
{
playerPosition = playerRef.transform.position;
}
Vector3 GetUpdatedFacing(Vector3 playerPosition)
{
Vector3 newFacing = Vector3.zero;
if (transform.position.x != playerPosition.x)
{
newFacing.x = transform.position.x < playerPosition.x ? 1 : -1;
}
else { newFacing.x = 0; }
if (transform.position.z != playerPosition.z)
{
newFacing.z = (transform.position.z < playerPosition.z ? 1 : -1);
}
else { newFacing.z = 0; }
return newFacing;
}
void TryMove(Vector3 playerPosition)
{
//update facing
transform.forward = GetUpdatedFacing(playerPosition);
MoveTowardPlayer();
}
void MoveTowardPlayer()
{
transform.position += transform.forward * movementSpeed * Time.deltaTime; //movementSpeed = 5f for now
}
This works to a point, except that as soon as the enemy becomes aligned with the player object (on either axis), rather than stop moving in the now-aligned axis, the enemy proceeds to rapidly move and rotate back and forth between the positive and negative facings of that aligned axis. For practical needs of the enemy, it is aligned and shouldn't be moving on that axis anymore. Despite this, it seems to rapidly go back and forth between being misaligned in very small increments.
I tried implementing a solution to this, namely, I expanded the check for the correction in movement to add a "buffer" of being off by 0.1f. Meaning that, if the enemy is within 0.1f in either direction of the player, then the enemy will ignore that input direction. This seems to produce the intended effect.
Vector3 GetUpdatedFacing(Vector3 playerPosition)
{
Vector3 newFacing = Vector3.zero;
if (transform.position.x != playerPosition.x)
{
newFacing.x += transform.position.x < playerPosition.x - 0.1f ? 1 : 0;
newFacing.x += transform.position.x > playerPosition.x + 0.1f ? -1 : 0;
}
else { newFacing.x = 0; }
if (transform.position.z != playerPosition.z)
{
newFacing.z += transform.position.z < playerPosition.z - 0.1f ? 1 : 0;
newFacing.z += transform.position.z > playerPosition.z + 0.1f ? -1 : 0;
}
else { newFacing.z = 0; }
return newFacing;
}
My only concerns are that:
I would prefer based on how I'm seeing it, that the enemy weights movements in cardinal directions above those in diagonal directions. At a future implementation, I intend to do that by having a "wall check" which will prevent movement in a given direction if a wall is blocking the path ahead. That said, I was looking to encourage cardinal movement more than others. Call it a peculiar desire if you want, I would like to see some ideas for how that could be done.
I am concerned about the 0.1 buffer being needed. Maybe less that the buffer is 0.1f, the real issue to me is that the buffer is needed at all. I am looking to see if any different implementation of the concept could improve the behavior so that this buffer wasn't necessary.
Maybe this is a bit more open-ended than some questions, if this is inappropriate, then I apologize for the format.