If it needs to move in only the cardinal directions, it’s more complicated than this. You need to take the player position and the box position and sort of cut the difference into quadrants to determine a straight <= => direction and use that- if it’s exactly to the => right, that’s easy, but if it’s NE then you need to know if it’s slightly more N or slightly more E, to know which direction to use. The player’s position should not be used directly in the calculations this way, but only to determine which of the 4 preset directions to apply to the box.
A quick and easy way to do this might be to just take the relative player/box position difference to create a direction from that, compare it to the four options (left, right, forward, and back), and take the smallest absolute difference and use that. So something like:
private enum directions
{
left = 0,
right,
forward,
back
};
private Dictionary<directions, Vector3> lookupTable = new Dictionary<directions, Vector3>();
private void Awake()
{
UpdateDirectionLookup();
}
private void UpdateDirectionLookup()
{
Transform trans = GetComponent<Transform>();
lookupTable.Clear();
lookupTable.Add(directions.left, -trans.right);
lookupTable.Add(directions.right, trans.right);
lookupTable.Add(directions.forward, trans.forward);
lookupTable.Add(directions.back, -trans.forward);
}
private void OnCollisionEnter(Collision col)
{
if (col.gameObject.tag == "player")
{
directions pushDirection = DeterminePushDirection(col.transform.position - transform.position);
PushInDirection(pushDirection);
}
}
private directions DeterminePushDirection(Vector3 vectorDirection)
{
float smallestAngle = float.PositiveInfinity;
directions selectedDirection = directions.left;
float tempAngle = 0;
for (int i = 0; i < lookupTable.Count; i++)
{
tempAngle = Vector3.Angle(vectorDirection, lookupTable[(directions)i]);
if (tempAngle < smallestAngle)
{
smallestAngle = tempAngle;
selectedDirection = (directions)i;
}
}
return selectedDirection;
}
private void PushInDirection(directions pushDirection)
{
transform.position += lookupTable[pushDirection];
}
… and put that on the crate, not the player. I probably missed something stupid in there- I typed it into the response area so it may not quite compile as-is, but should give you a rough idea. I made calculating the direction and actually pushing in the direction two different functions, this way you can replace the latter with a coroutine pretty easily, and disable it from re-occurring while being moved, etc…
A slightly different approach is considering the crate as a real-world object in which the player has to be able to animate pushing on the sides. In that case, you’ll have 4 planes to push against (one on each side), and each plane needs to be a sort of independent surface so you aren’t constant running calculations every single frame about what you’re pushing against. In that case, I would actually use 4 different little trigger areas, and the math of setting up which trigger is responsible for which direction should be done once, in Start, and never again. Then, when you push on the box while in a specific trigger area, the box controller says “oh, that’s the Right side trigger” and moves left- the player isn’t used in the calculation at all except to trigger the push function.
That feels far cleaner to me.