Search code examples
c#unity-game-enginespline

change the direction of rotation of the object


I'm doing some experiments in Unity with Splines. I currently have a path made, and I go through the "Spline Animate" script and the object follows the path correctly. However, I would like the object to be able to change the direction of rotation on the Spline, so that the object follows the path clockwise (going forward) and gives me the possibility that it also goes anti-clockwise (going backwards). ).

I tried to use the "Reverse Spline Flow" option but, it's not what I'm looking for. Using this option the object will rotate in the opposite direction but with two problems. The first is that it will be rotated towards the new direction of rotation (therefore not will never go backwards but still forwards), and the second is that the object, before changing the direction of rotation, is also repositioned in the starting point of the Spline.

Finally, I tried writing a C# script that allowed the object to follow the Spline without using the "Spline Animate" script. This script, by changing the speed, allows you to go forward or backward (to go backwards simply set the speed with a negative number). This script, however, also has an issue.

Following the Spline in its direction, everything works correctly. While going in the opposite direction, the object will go in the opposite direction until it reaches the first point of the Spline where it will stop and will not continue further.

For completeness, I attach the movement script and a screen to show the starting point of the Spline where the object arrives and stops. I thank everyone for the help you will give me, I hope I have been clear enough. :)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Splines;
using Unity.Mathematics;

public class Motor : MonoBehaviour
{
    public SplineContainer spline;
    public float speed = 1f;
    float distancePercentage = 0f;

    float splineLength;

    private void Start()
    {
        splineLength = spline.CalculateLength();
    }

    void Update()
    {
        distancePercentage += speed * Time.deltaTime / splineLength;

        Vector3 currentPosition = spline.EvaluatePosition(distancePercentage);
        transform.position = currentPosition;

        if (distancePercentage > 1f)
        {
            distancePercentage = 0f;
        }

        Vector3 nextPosition = spline.EvaluatePosition(distancePercentage - 0.05f);
        Vector3 direction = currentPosition - nextPosition;
        transform.rotation = Quaternion.LookRotation(direction, transform.up);
    }
}

enter image description here


Solution

  • I made a little sample project locally and from what I understand this should fix your issue:

    void Update()
    {
        distancePercentage += speed * Time.deltaTime / splineLength;
    
        //the 'fix'
        float splinePos = Mathf.Repeat(distancePercentage, 1f);
    
        Vector3 currentPosition = spline.EvaluatePosition(splinePos);
        transform.position = currentPosition;
    
        Vector3 nextPosition = spline.EvaluatePosition(splinePos - 0.05f);
        Vector3 direction = currentPosition - nextPosition;
        transform.rotation = Quaternion.LookRotation(direction, transform.up);
    }
    

    In your code when the speed is negative distancePercentage will eventually get below zero and the spline seems to clamp that value to zero. Potentially this extra if statement could solve this issue:

        if (distancePercentage < 0f)
        {
            distancePercentage = 1f;
        }
    

    However Mathf.Repeat will achieve this and in my opinion is a bit cleaner than having 2 ifs

    Finally am not sure I understood the rotational requirements - visually it my local copy seemed to work just fine