1
\$\begingroup\$

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 );
    }
}
\$\endgroup\$
2
  • \$\begingroup\$ instead of "myobject.transform.Rotate (OO, 0.0f, 0.0f);" you should use "myobject.transform.rotation = Quaternion.Euler (OO, 0.0f, 0.0f);" \$\endgroup\$ Sep 28, 2016 at 12:49
  • 1
    \$\begingroup\$ If you're the one who suggested an edit, you should try and go here to have your accounts merged. \$\endgroup\$
    – Vaillancourt
    Oct 1, 2016 at 13:35

3 Answers 3

1
\$\begingroup\$

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.

\$\endgroup\$
0
\$\begingroup\$

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.

\$\endgroup\$
0
\$\begingroup\$

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);
}
\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .