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\$
  • \$\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\$ – Siddharth-Verma Sep 28 '16 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 '16 at 13:35
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.

| improve this answer | |
\$\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.

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

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.