I have spend quite a bit of time today trying to find a way to calculate the rotation to get the ram to make smooth turn.
Eventually I ended up with something that is much easier to understand (for me at least), all boiled down to left or right
turn relative to the current heading.
It would be great to have a example of how this should be done in a proper way.
I have pasted the code below if anyone is interested.
I’m sure the code can be improved, but for now I have spend enough time on this little problem and will move on
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyMover : MonoBehaviour {
[SerializeField] List<Waypoint> _path = new List<Waypoint>();
[SerializeField] float _enemySpeed = 1f;
void Start() {
StartCoroutine(SmoothFollowPath());
}
enum Heading { north, east, south, west }
enum Turn { none, left, right }
private IEnumerator SmoothFollowPath() {
Heading currentHeading = 0f;
foreach (var nextPoint in _path) {
Vector3 startPosition = transform.position;
Vector3 endPosition = nextPoint.transform.position;
Vector3 headingDirection = (endPosition - startPosition).normalized;
Heading heading = getHeading(new Vector2(headingDirection.x, headingDirection.z));
if (heading != currentHeading) {
// heading has changed, so turn the object
yield return SmoothTurnObject(currentHeading, heading);
currentHeading = heading;
}
float travelPercent = 0;
// make sure we are really looking in the right direction
transform.LookAt(nextPoint.transform);
while (travelPercent < 1f) {
travelPercent += Time.deltaTime * _enemySpeed;
this.transform.position = Vector3.Lerp(startPosition, endPosition, travelPercent);
yield return new WaitForEndOfFrame();
}
}
}
private IEnumerator SmoothTurnObject(Heading from, Heading to) {
var turn = this.relativeTurn(from, to);
// Debug.Log($"old heading: {from}, hew heading: {to} ");
// Debug.Log($" turn: {turn} ");
float rotatePercent = 0;
float rotationSpeed = 2f;
float rotation = turn == Turn.left ? -90f : 90f;
while (rotatePercent < 1) {
float f = rotation * (Time.deltaTime * rotationSpeed);
rotatePercent += Time.deltaTime * rotationSpeed;
transform.Rotate(Vector3.up, f);
yield return new WaitForEndOfFrame();
}
yield return new WaitForSeconds(0.1f);
}
private Heading getHeading(Vector2 direction) {
if (direction.y > 0.1f) {
return Heading.north;
}
if (direction.y < -0.1f) {
return Heading.south;
}
if (direction.x > 0.1f) {
return Heading.east;
}
return Heading.west;
}
private Turn relativeTurn(Heading from, Heading to) {
// turn left or right relative to current heading
if (from == Heading.north) {
switch (to) {
case Heading.north: return Turn.none;
case Heading.east: return Turn.right;
case Heading.west: return Turn.left;
case Heading.south: return Turn.none;
}
}
if (from == Heading.east) {
switch (to) {
case Heading.north: return Turn.left;
case Heading.east: return Turn.none;
case Heading.west: return Turn.none;
case Heading.south: return Turn.right;
}
}
if (from == Heading.south) {
switch (to) {
case Heading.north: return Turn.left;
case Heading.east: return Turn.left;
case Heading.west: return Turn.right;
case Heading.south: return Turn.none;
}
}
if (from == Heading.west) {
switch (to) {
case Heading.north: return Turn.right;
case Heading.east: return Turn.none;
case Heading.west: return Turn.none;
case Heading.south: return Turn.left;
}
}
return Turn.none;
}
}