2
\$\begingroup\$

I am new to C# and new to Unity. I made a script that can turn a cube slowly one time after a mouse click but I feel like its probably wrong for using FixedUpdate. Is this OK or is there a better way? What is wrong with this way?

using UnityEngine;
using System.Collections;

public class MouseClick : MonoBehaviour {

    public float myRotationSpeed = 1.0f;
    bool flipped = false;

    //when User clicks it with mouse
    void OnMouseDown ()
    {

        if (flipped == false)
        {
        flipped = true;
        }
    }
    void FixedUpdate () 
    {

        if(flipped == true && gameObject.transform.rotation.y >=0.01)
        {

            transform.Rotate(0, myRotationSpeed * Time.deltaTime, 0);
        }
    }
}
\$\endgroup\$
0

2 Answers 2

1
\$\begingroup\$

You can use this script. Create a new script called TransformExtensions and paste this in it. Then just call RotateOverTime() on your transform. It takes the Vector3 rotation and float seconds. You can also call RotateTowardsOverTime() and pass in a Vector3 targetDirection and float seconds.

using UnityEngine;
using System.Collections;
using System;

public static class TransformExtensions
{
    /// <summary>
    /// Rotates the transform to a specified rotation over a set number of seconds.
    /// For an infinite rotation, multiply the degrees by a float to adjust the speed, and set the duration to 0 seconds.
    /// Calling RotateOverTime() or RotateTowardsOverTime() will cancel any pending rotations on this transform.
    /// </summary>
    public static void RotateTowardsOverTime(this Transform transform, Vector3 degrees, float seconds)
    {
        Vector3 rotationToBeMade = degrees - transform.rotation.eulerAngles;
        if (degrees.z > 270.0F && transform.rotation.eulerAngles.z < 90.0F)
        {
            rotationToBeMade.z = -(360.0F - degrees.z + transform.rotation.eulerAngles.z);
        }
        if (transform.rotation.eulerAngles.z > 270.0F && degrees.z < 90.0F)
        {
            rotationToBeMade.z = 360.0F - transform.rotation.eulerAngles.z + degrees.z;
        }
        RotateOverTime(transform, rotationToBeMade, seconds);
    }

    /// <summary>
    /// Rotates the transform by a specified number of degrees over a set number of seconds.
    /// For an infinite rotation, multiply the degrees by a float to adjust the speed, and set the duration to 0 seconds.
    /// Calling RotateOverTime() or RotateTowardsOverTime() will cancel any pending rotations on this transform.
    /// </summary>
    public static void RotateOverTime(this Transform transform, Vector3 degrees, float seconds)
    {
        RotateOverTime[] oldRotateOverTimeComponents = transform.gameObject.GetComponents<RotateOverTime>();
        foreach (RotateOverTime oldRotateOverTimeComponent in oldRotateOverTimeComponents)
        {
            GameObject.Destroy(oldRotateOverTimeComponent);
        }

        RotateOverTime rotateOverTimeComponent = transform.gameObject.AddComponent<RotateOverTime>();
        rotateOverTimeComponent.hideFlags = HideFlags.HideInInspector;
        rotateOverTimeComponent.Degrees = degrees;
        rotateOverTimeComponent.Seconds = seconds;
    }

class RotateOverTime : MonoBehaviour
{
    public Vector3 Degrees { get; set; }
    public float Seconds { get; set; }

    private Vector3 rotationCompleted = Vector3.zero;
    private Vector3 speed;
    private Vector3 startRotation;

    void Start()
    {
        speed = GetBalancedRotationSpeeds(Degrees, Seconds);
        startRotation = transform.eulerAngles;
    }

    void FixedUpdate()
    {
        UpdateRotation();
        if (IsRotationComplete())
        {
            Destroy(this);
        }
    }

    private Vector3 GetBalancedRotationSpeeds(Vector3 degrees, float seconds)
    {
        if (seconds == 0)
        {
            seconds = 1;
        }
        float degreesWeight = (Degrees.x + Degrees.y + Degrees.z) / 3;
        float speedModifier = degreesWeight / seconds;
        float totalChangeInDegrees = Math.Abs(degrees.x) + Math.Abs(degrees.y) + Math.Abs(degrees.z);
        float xWeight = Math.Abs(degrees.x) / totalChangeInDegrees;
        float yWeight = Math.Abs(degrees.y) / totalChangeInDegrees;
        float zWeight = Math.Abs(degrees.z) / totalChangeInDegrees;
        float xSpeed = xWeight * speedModifier * 3;
        float ySpeed = yWeight * speedModifier * 3;
        float zSpeed = zWeight * speedModifier * 3;
        return new Vector3(xSpeed, ySpeed, zSpeed);
    }

    private void UpdateRotation()
    {
        rotationCompleted += Time.deltaTime * speed;
        Vector3 rotation = Quaternion.Euler(rotationCompleted + startRotation).eulerAngles;
        bool rotationIsValid = !(float.IsNaN(rotationCompleted.x) || float.IsNaN(rotationCompleted.y) || float.IsNaN(rotationCompleted.z) && float.IsNaN(startRotation.x) || float.IsNaN(startRotation.y) || float.IsNaN(startRotation.z) || float.IsNaN(rotation.x) || float.IsNaN(rotation.y) || float.IsNaN(rotation.z));
        if (!rotationIsValid)
        {
            Destroy(this);
        }
        transform.eulerAngles = rotation;
    }

    private bool IsRotationComplete()
    {
        bool xRotationIsComplete = Math.Abs(rotationCompleted.x) >= Math.Abs(Degrees.x);
        bool yRotationIsComplete = Math.Abs(rotationCompleted.y) >= Math.Abs(Degrees.y);
        bool zRotationIsComplete = Math.Abs(rotationCompleted.z) >= Math.Abs(Degrees.z);
        return xRotationIsComplete && yRotationIsComplete && zRotationIsComplete && Seconds != 0;
    }
}
\$\endgroup\$
5
  • \$\begingroup\$ Thanks for this, it is a little overwhelming though :). I will go through it and look up all the stuff I don't understand. IS there something wrong with using FixedUpdate the way I am? \$\endgroup\$ Commented Mar 18, 2015 at 2:36
  • \$\begingroup\$ No need to read it. Just create a new script called TransformExtensions and paste it in there. \$\endgroup\$ Commented Mar 18, 2015 at 2:37
  • \$\begingroup\$ I am getting an error saying that class RotateOverTime : MonoBehaviour "The Type 'TransformExtensions' already contains a definition for RotateOverTime" \$\endgroup\$ Commented Mar 18, 2015 at 2:48
  • \$\begingroup\$ Sounds like you pasted code in two places? \$\endgroup\$ Commented Mar 18, 2015 at 3:27
  • \$\begingroup\$ @JacobJones the issue with yours is that it is hard coded. If it works, great. But you can't really reuse it on other rotations without a bunch of copy pasting. But I believe FixedUpdate is the correct place for your rotation \$\endgroup\$ Commented Mar 18, 2015 at 4:14
0
\$\begingroup\$

I think Update() is better in this case. Try to change your code like below:

public float myRotationSpeed = 1.0f;
bool flipped = false;
 Vector3 targetDir;

void OnMouseDown ()
{

    if (flipped == false)
    {
    flipped = true;
    targetDir = -1 * transform.forward; 
    }
}
void Update () 
{

    if(flipped == true )
    {
        float angle = Vector3.Angle(targetDir, forward);
        if (angle > 0.01F) //stop condition
        {
         transform.Rotate(Vector3.up * myRotationSpeed * Time.deltaTime, Space.World);
        } else {
         flipped = false;
        }
    }

}
\$\endgroup\$
2
  • \$\begingroup\$ I think FixedUpdate is used for physics, while Update is used for non-physics. Assuming a rotation counts as physics, I think FixedUpdate is the best place for it. \$\endgroup\$ Commented Mar 18, 2015 at 18:11
  • \$\begingroup\$ Thanks for the response. I was trying to find different kinds of stop conditions. \$\endgroup\$ Commented Mar 19, 2015 at 5:27

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.