0
\$\begingroup\$

Recently, in Unity, I tried to move a sphere along a figure-eight path. It first moves in a circle, and after completing the circle, it starts the second circle in reverse, using negative rotation. However, my plan did not work as I expected. The reason is that Unity changes negative degrees into positive degrees, so -15 degrees becomes 345 degree. Therefore, the direction of the circular movement won't change, when you flip from a positive degree to a negative degree. In other words, if the first path is clock-wise the second path (after changing the sign of the degree) will be clock-wise, too.

Is there any practical way to overcome this problem, and change the direction of rotation by changing from positive degrees to negative degrees?

Here is one of the scripts I have tried:

public class PlayerMover : MonoBehaviour  
{
    float x;
    public float speed=100.1f;
    private Transform playerTransform = null;

    void Start ()   
    {
        playerTransform = GetComponent<Transform>();
    }

    void Update () 
    {
        x=speed*Time.deltaTime;
        playerTransform.Rotate(0, 5 *funct(x) * x, 0);
        playerTransform.position += playerTransform.forward ;
    }

    public float funct(float u)
    {
        u=Mathf.Sin(u);
        return u;
    }
}

As you can see. even the function I use to flip from positive degrees to negative degrees is a smooth and continuous function, mathematically speaking.

\$\endgroup\$
  • \$\begingroup\$ This looks a bit odd. x is recalculated each frame as the speed times the seconds elapsed since the last frame, so it's likely varying between roughly 100/60 and 100/30, depending on your framerate. Sin of x is positive on almost all of this interval, so if you're running at a consistent framerate even a little over 30 fps, funct(x) will always be positive. (And if you're running with vsync at exactly 30 then funct(x) will always be negative). That sounds at odds with what you described you intended it to do though, in terms of "flipping from positive degrees to negative degrees" \$\endgroup\$ – DMGregory Jul 14 '17 at 23:23
  • \$\begingroup\$ @DMGregory: I even tried a step function with constant values +c and -c, but couldn't achive changing the direction of rotation. \$\endgroup\$ – user102669 Jul 15 '17 at 5:09
  • \$\begingroup\$ It's not the function that's the problem, it's your input. Are you intending x to increase over time? You might want Time.time rather than Time.deltaTime. The delta is just the interval since your last frame, so when your framerate is stable it doesn't increase or decrease much. \$\endgroup\$ – DMGregory Jul 15 '17 at 5:12
0
\$\begingroup\$

Your diagnosis of the problem is incorrect. Unity handles negative angles just fine, as you can see here:

Animation showing a cube in Unity wandering in a figure-8 shape.

The problem is how you're calculating your rotation increment. As described above, Time.deltaTime is the time in seconds that have elapsed since the last frame (typically 1/60 - 1/30). As long as your framerate holds steady, this value is nearly constant. It's good for scaling change over time to keep a consistent rate, but it doesn't itself progress over time.

If you want something to change over time, then you'll want to either:

Here's the code used above. You can see just like yours it rotates each frame by an increment that's scaled by a sine function. In this one though, the sine varies over Time.time, so the phase progresses from frame to frame

public class Figure8 : MonoBehaviour {

    public float secondsPerLoop = 3f;
    public float forwardSpeed = 1f;

    void Update () {
        // Sharp direction change.
        // float direction = Mathf.Sign(
        //  (Time.time / secondsPerLoop) % 1.0f - 0.5f);
        // float rotationDoubling = 2f;

        // Smooth direction change.
        float direction = Mathf.Sin(
            Time.time * 2f * Mathf.PI / secondsPerLoop);
        float rotationDoubling = 2.43f; // Eyeballed, not precise.

        float rotationIncrement = 
            rotationDoubling * Time.deltaTime * 360f / secondsPerLoop;

        transform.Rotate(0f, direction * rotationIncrement, 0f);
        transform.Translate(0f, 0f, forwardSpeed * Time.deltaTime);
    }
}
\$\endgroup\$
  • \$\begingroup\$ Thanks for your enlightening answer. Now I have a better understanding how to apply time to simulate other motions too. \$\endgroup\$ – user102669 Jul 15 '17 at 13:39
0
\$\begingroup\$

Have you tried animations instead? Not saying it should be done with animations, just an alternative. He is one way to get the figure 8 done with code:

float x;
public float speed = 100.1f;
public int otherWay = 1;
public int count = 0;
public Vector3 startingPostion;

private Transform playerTransform = null;

void Start()
{
    playerTransform = GetComponent<Transform>();
    startingPostion = playerTransform.position;
}

void Update()
{
    x = speed * Time.deltaTime;
    playerTransform.Rotate(new Vector3(0, otherWay * 5 * funct(x) * x, 0));
    playerTransform.position += playerTransform.forward;


    if (count == 43)
    {
        otherWay = otherWay * -1;
        count = 0;
        playerTransform.transform.position = startingPostion;
    }
    count++;

}

public float funct(float u)
{
    u = Mathf.Sin(u);
    return u;
}
\$\endgroup\$
  • \$\begingroup\$ Thanks for sharing your solution for moving in an 8-figure path. But my question was about how to change the direction of rotation while you are still moving. Your answer taught me how to append two movement to travel along an 8-figure path. \$\endgroup\$ – user102669 Jul 15 '17 at 13:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy