6
\$\begingroup\$

I have a pretty straightforward task, but I find it hard to figure out how to improve it. The code is pretty straightforward, but rather bad. There are some clarifications / extra details at the bottom. Let's assume the direction of the positive Z axis is (from the screen) towards you, the reader. Let's say I have this character:

enter image description here

Its angle / rotation along the Z axis is 0 initially. What I want it to do is rotate (say anticlockwise) around the Z axis with a particular speed (adjusted by RotationRate). When it reaches a (cumulated/total) rotation of 180, the rotation should stop. At this point the character will be upside down. If I now tap the screen again, the rotation should start again, but in the opposite direction, until it reaches an angle of 0. Now the character will look again like in the original photo above.

private bool Rotating = false;
private bool IsNormalPosition = true;
private float CharacterTargetAngle = 0;
private float RotationRate = 180 * 5;
private float Threshold = 30;

private IEnumerator Rotate()
{
    while (Rotating)
    {
        var angle = transform.eulerAngles;

        if (Mathf.Abs(CharacterTargetAngle - angle.z) < Threshold)
        {
            angle.z = CharacterTargetAngle;
            Rotating = false;

            transform.eulerAngles = angle;
        }
        else
        {
            transform.Rotate(0, 0, RotationRate * Time.deltaTime);
        }

        yield return new WaitForFixedUpdate();
    }
}

// called when user taps screen
public void OnTap()
{
    if (IsNormalPosition)
    {
        CharacterTargetAngle = 180;
    }
    else
    {
        CharacterTargetAngle = 0;
    }

    IsNormalPosition = !IsNormalPosition;
    RotationRate *= -1;

    if (!Rotating)
    {
        Rotating = true;

        StartCoroutine("Rotate");
    }
    else
    {
        StopCoroutine("Rotate");
        StartCoroutine("Rotate");
    }
}

Other details / clarifications:

Note that if the character is still rotating and I tap the screen again, I want its current rotation to stop and change direction immediately. For this I am setting a Rotating flag. If this is false, then it means the character is either upside down or sitting normally, so I only have to start the Rotate() coroutine. If, however, Rotating is true, I need to stop the previously started coroutine before starting the new rotation coroutine.

CharacterTargetAngle represents the angle I am aiming at: either 0 or 180.

IsNormalPosition represents whether the character has an angle of 0 (true) or 180 (false).

RotationRate represents the speed of rotation. Currently the character can rotate at a speed of 180 * 5 degrees per second. I reached this value after trying many others.

\$\endgroup\$

2 Answers 2

3
\$\begingroup\$

Your code seems to be quite clear to me. The only thing I can offer as a suggestion is as follows:

if (IsNormalPosition)
{
    CharacterTargetAngle = 180;
}
else
{
    CharacterTargetAngle = 0;
}

This is a little more concise.

CharacterTargetAngle = IsNormalPosition ? 180 : 0;
\$\endgroup\$
1
  • 1
    \$\begingroup\$ Ah, ternaries, of course! \$\endgroup\$
    – async
    Oct 29, 2014 at 10:35
2
\$\begingroup\$
if (Mathf.Abs(CharacterTargetAngle - angle.z) < Threshold)
{
    angle.z = CharacterTargetAngle;
    Rotating = false;

    transform.eulerAngles = angle;
}
else
{
    transform.Rotate(0, 0, RotationRate * Time.deltaTime);
}

Why are you comparing the angle difference with some fixed Threshold? Shouldn't you instead compare it based on RotationRate?


StopCoroutine("Rotate");
StartCoroutine("Rotate");

Why are you doing this? Wouldn't keeping the old coroutine work too?

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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