Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to rotate a parent object while rotating a child object to a certain angle using coroutines

Tags:

c#

unity3d

I have a semicircle like game object which I made by putting two arcs in an empty game object (SCircle) and rotating the 15° (for left arc) and -15° (for right arc) as seen below.

enter image description here

SCircle has an Orientation enum with two valuesLeft (rotates SCircle to 45°) and Right (rotates SCircle to -45°) as seen in the image below.

enter image description here

I use the following coroutine to move SCircle between orientations.

IEnumerator RotateLeftOrRight(Vector3 byAngles, float inTime)
{
   Quaternion fromAngle = gameObject.transform.rotation ;
   Quaternion toAngle = Quaternion.Euler (transform.eulerAngles);


   if (circOrientation == Orientation.Left) {
       toAngle = Quaternion.Euler (gameObject.transform.eulerAngles - byAngles);
       circOrientation = Orientation.Right;

   }
   else if (circOrientation == Orientation.Right) {

       toAngle = Quaternion.Euler (gameObject.transform.eulerAngles + byAngles);
       circOrientation = Orientation.Left;
   }


   for(float t = 0f ; t <= 1f ; t += Time.deltaTime/inTime)
   {
       gameObject.transform.rotation = Quaternion.Lerp(fromAngle, toAngle, t) ;
       yield return null ;

   }
    gameObject.transform.rotation = Quaternion.Lerp(fromAngle, toAngle, 1);
}  

I also used a very similar coroutine to move the individual arcs by 30° (in opposite directions) from say, Orientation Left, as seen below in the coroutine and image:

IEnumerator RotateArc(GameObject arcGO, Vector3 byAngles, float inTime)
{
    Quaternion fromAngle = arcGO.transform.rotation ;
    Quaternion toAngle = Quaternion.Euler (arcGO.transform.eulerAngles);

    if (rightArc.arcOrientation == Arc.Orientation.Down) {
        toAngle = Quaternion.Euler (arcGO.transform.eulerAngles + byAngles);
        rightArc.arcOrientation = Arc.Orientation.Up;

    }
    else if (rightArc.arcOrientation == Arc.Orientation.Down) {

        toAngle = Quaternion.Euler (arcGO.transform.eulerAngles - byAngles);
        rightArc.arcOrientation = Arc.Orientation.Up;
    }


    for(float t = 0f ; t <= 1f ; t += Time.deltaTime/inTime)
    {
        arcGO.transform.rotation = Quaternion.Lerp(fromAngle, toAngle, t) ;
        yield return null ;

    }
    arcGO.transform.rotation = Quaternion.Lerp(fromAngle, toAngle, 1);

}

enter image description here

Since SCircle Coroutine is activated by a mouse click, I have the case where the individual arcs coroutine is run and before it is complete the parent SCircle coroutine is also run. In this case the arcs end up moving from Left to A, which is not the behavior I need. I would want the behavior of them ending up at B when moving from the Left. Likewise, from B, when the SCircle coroutine is run while the arcs coroutine is in progress the orientation will return to the Left.

Please note that the blue arrow represents the movement of the left Arc, the red represents the right Arc and the black represents movement of SCircle - the parent object.

enter image description here

like image 384
Bane Avatar asked Oct 05 '17 20:10

Bane


People also ask

How to make child rotate with parent unity?

Child objects automatically rotate with parents. You shouldn't need, or have, to set the child rotation at all.


1 Answers

I believe the issue you're having is caused by the fact that as you rotate the individual arcs, what they're rotating around is also rotating itself.

In other words, your SCircle's axes are rotating, and your arcs are using those same axes to determine their own rotations. So if you look at your example A, you tell it to rotate in world space by -90, then immediately tell to rotate in world space by 30. To solve this, you want to get the arcs to rotate locally, not in world space.

I think you can solve this by setting up this structure:

Empty GameObject SCircle

------Empty gameObject BlueArcCenter -> position 0,0,0

-----------blue arc -> change position here to make it offset from zero ex:(radius, 0, 0)

------Empty gameObject RedArcCenter -> position (0,0,0)

-----------red arc -> change position here to make it offset from zero ex:(-radius, 0, 0)

Now alter your code so that:

To rotate the blue and red arcs individually you rotate their arcCenters,

To rotate the whole configuration, rotate SCircle. This will in turn rotate both ArcCenters, which will in turn rotate both the arcs irrespective of how they are oriented relative to each other, or whether they are rotating themselves.

Note: Also, I've read that people are using Quaternions a lot less these days since they don't really make sense when you read the code. You might want to change your code to normal rotations to make it more readable.

If you have the setup listed above, use something like:

to spin circle:

thisSCircle.transform.Rotate(0, -90, 0, Space.Self);

to rotate arcs around their common center:

blueArcCenter.transform.Rotate(0, -30, 0, Space.Self)
redArcCemter.transform.Rotate(0, 30, 0, Space.Self)

(you'd need to add lerps in and stuff but this should get you started).

like image 92
Adam B Avatar answered Oct 16 '22 11:10

Adam B