How to rotate within a fixed interval in Unity?

I have very recently started to learn Unity.

I'm trying to write code that will make a character swing a flag. I want to use this object and rotate the arm up and down. So I need to make it rotate up and down with within 30 degrees.

This is my attempt but it simply keeps on turning. How would I make the hand rotate in motion within the interval [-30, 30] degrees.

private GameObject myobject;
public float timeElapsed =0;
public float delay = 3.0f;
float OO = 0.0f;

void Start () {
myobject = GameObject.Find ("rightarm").gameObject;
}

void Update () {
timeElapsed += Time.deltaTime;
Debug.Log (timeElapsed);

if (timeElapsed >= delay) {
OO = 30.0f;
timeElapsed = 0;
if (myobject.renderer.enabled == false) {
myobject.renderer.enabled = true;
}

myobject.transform.Rotate (OO, 0.0f, 0.0f);
}
else
{
myobject.transform.Rotate (-OO,0.0f, 0.0f );
}
}

• instead of "myobject.transform.Rotate (OO, 0.0f, 0.0f);" you should use "myobject.transform.rotation = Quaternion.Euler (OO, 0.0f, 0.0f);" – Siddharth-Verma Sep 28 '16 at 12:49
• If you're the one who suggested an edit, you should try and go here to have your accounts merged. – Vaillancourt Oct 1 '16 at 13:35

There are two problems with your code:

• Whenever timeElapsed >= delay is true, timeElapsed is set again to zero, making the condition again false and causing it to rotate in one direction/
• Transform.Rotate adds the given rotation to it's current rotation, thus it will rotate the arm without stopping at 30°.

You could first check if timeElapsed >= delay is true and then switch between either lowering or raising the flag, so this is what the code may look like:

bool shouldRaiseFlag = true;

// [...]

timeElapsed += Time.deltaTime;
if(timeElapsed >= delay){
if(shouldRaiseFlag) myobject.transform.localEulerAngles = new Vector3( 30.0f,0f,0f);
else                myobject.transform.localEulerAngles = new Vector3(-30.0f,0f,0f);
shouldRaiseFlag = !shouldRaiseFlag;
timeElapsed = 0;
}


However, this will instantly raise/lower the flag, so if you want smooth motion you could instead use:

Vector3 armRotation = new Vector3(30,0,0);
float armDirection  = 1.0f;

// [...]

timeElapsed += Time.deltaTime;
if(timeElapsed >= delay/2){
timeElapsed  = -delay/2;
armDirection = -armDirection;
}
myobject.transform.localEulerAngles = armRotation * (timeElapsed / (delay/2)) * armDirection;


I am aware this solution is certainly not the best, so make sure to take a look at the other answers posted here.

I believe you have to make a modification in the above code because, Rotate will continuously rotate the object around the x-axis for every frame.

Instead of "myobject.transform.Rotate (OO, 0.0f, 0.0f);" you should use "myobject.transform.rotation = Quaternion.Euler (OO, 0.0f, 0.0f);".

Modification is as follows :-

void Update () {
timeElapsed += Time.deltaTime;
Debug.Log (timeElapsed);

if (timeElapsed >= delay) {
OO = 30.0f;
timeElapsed = 0;
if (myobject.renderer.enabled == false) {
myobject.renderer.enabled = true;
}

myobject.transform.rotation = Quaternion.Euler (OO, 0.0f, 0.0f);
}
else
{
myobject.transform.rotation = Quaternion.Euler (-OO, 0.0f, 0.0f);
}


}

Hope this helps you out.

For something like swinging a flag back and forth, I'd be tempted to use simple harmonic motion, like a pendulum or sine/cosine wave...

// Specify how many degrees you want to rotate from the initial orientation.
public Vector3 amplitude = new Vector3(30, 0, 0);

// Specify how many seconds a complete loop should take.
public float period = 6f;

// Cache initial orientation so we can rotate relative to that pose.
Quaternion _initialOrientation;

// Perform caching on Start.
void Start() {
_initialOrientation = transform.localRotation;
}

void Update() {
// Calculate how far along we should be in the wave.
float phase = Mathf.PI * 2f * Time.time/period;

// Calculate the angle at this part of the wave.
Vector3 angle = amplitude * Mathf.Sin(phase);

// Rotate by angle relative to our initial orientation.
transform.localRotation = _initialOrientation * Quaternion.Euler(angle);
}