Author Topic: Rotating an object around a pivot point.  (Read 239 times)  Share 

Scavenger

  • Cavefish
  • In Four Glorious Colours!
    • I can help with animation
    •  
    • I can help with backgrounds
    •  
    • I can help with characters
    •  
    • I can help with scripting
    •  
  • Scavenger worked on a game that was nominated for an AGS Award!Scavenger worked on a game that won an AGS Award!
Rotating an object around a pivot point.
« on: 17 Jun 2017, 07:36 »
I'm trying to create a bell in-engine, which swings back and forth, but I'm having a little bit of trouble - I can rotate the sprite around its central point, and I can move the object in a circle, but I can't sync them up. I don't think I'm good enough at math to work it out.

The sprite is here:

It should rotate around the middle of the hole at the top, so I can get it to swing. My current code is:

Code: Adventure Game Studio
  1. DynamicSprite *bellsprite;
  2. int angle = 1;
  3. function room_Load()
  4. {
  5. bellsprite = DynamicSprite.CreateFromExistingSprite (520);
  6. }
  7.  
  8. function room_RepExec()
  9. {
  10.   angle++;
  11.   if (angle > 359) angle = 1;
  12. bellsprite = DynamicSprite.CreateFromExistingSprite (520);
  13. bellsprite.Rotate (angle, 128, 128);
  14. oBell.Graphic = bellsprite.Graphic;
  15. oBell.X = FloatToInt(((100.0-64.0) * Maths.Cos (Maths.DegreesToRadians (IntToFloat (angle)))) - ((113.0-32.0) *  Maths.Sin (Maths.DegreesToRadians (IntToFloat (angle)))))+64;
  16. oBell.Y = FloatToInt(((100.0-64.0) * Maths.Sin (Maths.DegreesToRadians (IntToFloat (angle)))) + ((113.0-32.0) *  Maths.Cos (Maths.DegreesToRadians (IntToFloat (angle)))))+32;
  17. }
  18.  

But this is incredibly wrong, I know it. I just don't know how to make it go. Can anyone give me some advice?

Snarky

  • Global Moderator
  • Mittens Earl
  • Private Insultant
    • I can help with proof reading
    •  
    • I can help with translating
    •  
Re: Rotating an object around a pivot point.
« Reply #1 on: 17 Jun 2017, 08:33 »
A rotation around an arbitrary point is usually calculated as:

-Translate the coordinate system so the pivot point is at 0,0
-Rotate
-Translate back

What you need to do is to work out the net effect of the two translations.

If the coordinates of your pivot are (pivotX,pivotY), the first translation is (-pivotX,-pivotY) and the second is (pivotX,pivotY). So we need to calculate:

Code: Adventure Game Studio
  1. // translate pivot (pivotX,pivotY) to origin, rotate, and return
  2. {
  3.   float pivotTranslation[] = new float[2];
  4.   pivotTranslation[0] = -pivotX;
  5.   pivotTranslation[1] = -pivotY;
  6.  
  7.   pivotTranslation = Rotate2D(pivotTranslation, angle);
  8.   pivotTranslation[0] = pivotTranslation[0] + pivotX;
  9.   pivotTranslation[1] = pivotTranslation[1] + pivotY;
  10. }

The formula for calculating the x and y coordinates of a point after a rotation by a certain angle is (according to the first result that came up when I googled it):

Code: Adventure Game Studio
  1. float[] Rotate2D(float[] coords, float angle)
  2. {
  3.   float newcoords[] = new float[2];
  4.   newcoords[0] = coords[1]*Maths.Sin(angle) + coords[1]*Maths.Cos(angle);  
  5.   newcoords[1] = coords[1]*Maths.Cos(angle) - coords[0]*Maths.Sin(angle);
  6.   return newcoords;
  7. }

There's a further complication in that rotating the sprite changes its dimensions, so to keep the center centered you have to adjust the position. Depending on how you're doing that currently it might look a little different.

Note that because the pivot may not lie on an integer coordinate after rotation, you're probably going to get a bit of "wobbling" around it when you eventually convert the floats back to ints.
« Last Edit: 17 Jun 2017, 08:36 by Snarky »

Mandle

  • NO PIXEL LEFT BEHIND!!!
  • Mandle worked on a game that was nominated for an AGS Award!
Re: Rotating an object around a pivot point.
« Reply #2 on: 17 Jun 2017, 15:46 »
Couldn't you just extend the top of the sprite as a purple transparent area so that the hole in the ring becomes the center of the sprite?

Khris

    • Lifetime Achievement Award Winner
    •  
    • I can help with play testing
    •  
    • I can help with scripting
    •  
    • I can help with translating
    •  
  • Khris worked on a game that was nominated for an AGS Award!
Re: Rotating an object around a pivot point.
« Reply #3 on: 19 Jun 2017, 11:38 »
Here's working code:
Code: Adventure Game Studio
  1. DynamicSprite *bellsprite;
  2. int angle = 0;
  3. int bellSlot = 520;
  4.  
  5. function room_Load()
  6. {
  7.   bellsprite = DynamicSprite.CreateFromExistingSprite(bellSlot);
  8. }
  9.  
  10. int bellX = 100, bellY = 113; // lower left corner coords (angle 0)
  11. int px = 63, py = 23; // sprite's pivot cords
  12.  
  13. function room_RepExec()
  14. {
  15.   angle = (angle + 1) % 360;
  16.  
  17.   // set sprite and store dimensions
  18.   bellsprite = DynamicSprite.CreateFromExistingSprite(bellSlot);
  19.   int w = bellsprite.Width;
  20.   int h = bellsprite.Height;
  21.  
  22.   // rotate if necessary
  23.   if (angle > 0) bellsprite.Rotate (angle);
  24.   oBell.Graphic = bellsprite.Graphic;
  25.  
  26.   // calculate sprite dimension change offset
  27.   float xOff = IntToFloat(w - bellsprite.Width) / 2.0;
  28.   float yOff = IntToFloat(bellsprite.Height - h) / 2.0;
  29.  
  30.   // calculate vector from pivot to center
  31.   float vx = IntToFloat(w) / 2.0 - IntToFloat(px);
  32.   float vy = IntToFloat(h) / 2.0 - IntToFloat(py);
  33.   // rotate vector
  34.   float rad = Maths.DegreesToRadians (IntToFloat (angle));
  35.   float cos = Maths.Cos(rad);
  36.   float sin = Maths.Sin(rad);
  37.   float vrx = vx * cos - vy * sin;
  38.   float vry = vx * sin + vy * cos;
  39.    
  40.   oBell.X = bellX + FloatToInt(xOff - vx + vrx, eRoundNearest);
  41.   oBell.Y = bellY + FloatToInt(yOff - vy + vry, eRoundNearest);
  42. }

There are two offsets:
1) the rotation increases the sprite, so that has to be corrected
2) moving the pivot away from the center, like Snarky explained

Mandle

  • NO PIXEL LEFT BEHIND!!!
  • Mandle worked on a game that was nominated for an AGS Award!
Re: Rotating an object around a pivot point.
« Reply #4 on: 19 Jun 2017, 14:50 »
Amazing! But couldn't you just extend the top of the sprite as a... (see above)

Or was I wrong about how that might work?

Snarky

  • Global Moderator
  • Mittens Earl
  • Private Insultant
    • I can help with proof reading
    •  
    • I can help with translating
    •  
Re: Rotating an object around a pivot point.
« Reply #5 on: 19 Jun 2017, 16:00 »
Yeah, you could, but code gives you more flexibility (e.g. if you want to rotate around different pivots). Also, if the pivot is far from the center, the sprite will have to be a lot bigger, and this will probably slow it down further.

Mandle

  • NO PIXEL LEFT BEHIND!!!
  • Mandle worked on a game that was nominated for an AGS Award!
Re: Rotating an object around a pivot point.
« Reply #6 on: 19 Jun 2017, 23:35 »
Yeah, you could, but code gives you more flexibility (e.g. if you want to rotate around different pivots). Also, if the pivot is far from the center, the sprite will have to be a lot bigger, and this will probably slow it down further.

I see... What I was really after was that feeling of finding the keys in the sun-visor while you guys were trying to  hotwire the car... (laugh):P

Snarky

  • Global Moderator
  • Mittens Earl
  • Private Insultant
    • I can help with proof reading
    •  
    • I can help with translating
    •  
Re: Rotating an object around a pivot point.
« Reply #7 on: 20 Jun 2017, 00:05 »
Yeah, it's definitely a clever workaround. When you mentioned it I was annoyed that I overlooked such a simple alternative.

Mandle

  • NO PIXEL LEFT BEHIND!!!
  • Mandle worked on a game that was nominated for an AGS Award!
Re: Rotating an object around a pivot point.
« Reply #8 on: 20 Jun 2017, 05:15 »
Yeah, it's definitely a clever workaround. When you mentioned it I was annoyed that I overlooked such a simple alternative.

I always follow the path of least work first if possible... :-D

Scavenger

  • Cavefish
  • In Four Glorious Colours!
    • I can help with animation
    •  
    • I can help with backgrounds
    •  
    • I can help with characters
    •  
    • I can help with scripting
    •  
  • Scavenger worked on a game that was nominated for an AGS Award!Scavenger worked on a game that won an AGS Award!
Re: Rotating an object around a pivot point.
« Reply #9 on: 20 Jun 2017, 20:01 »
I tried both methods, both Khris' code and expanding the sprite so that the pivot point was in the center. The latter method was a lot smoother, the code made the bell jitter around very unpleasantly, which I guess is the problem when you've got a lot of integer math going on.

Snarky

  • Global Moderator
  • Mittens Earl
  • Private Insultant
    • I can help with proof reading
    •  
    • I can help with translating
    •  
Re: Rotating an object around a pivot point.
« Reply #10 on: 20 Jun 2017, 22:05 »
Well, Khris's code is all in floats, but the problem is in the rounding.

The issue is that when you rotate the sprite, the corners go outside the original region, and therefore the new sprite has to be bigger to fit it. Even if it's only a tiny fraction of a pixel outside your "canvas", you of course have to add a whole row or column of pixels. This can shift the whole sprite almost a whole pixel right or down, leading to jittering.

When your pivot is at the center of the sprite, symmetry ensures that you add equally many pixels on each side in the rotated sprite, so by re-centering it the pivot stays in the same position, and you avoid any jittering. But when your pivot is not at the center this does not hold, so the sprite will jump around by about a pixel.

Given that AGS doesn't allow sub-pixel positioning of sprites, I really can't think of any way around it.

Khris

    • Lifetime Achievement Award Winner
    •  
    • I can help with play testing
    •  
    • I can help with scripting
    •  
    • I can help with translating
    •  
  • Khris worked on a game that was nominated for an AGS Award!
Re: Rotating an object around a pivot point.
« Reply #11 on: 20 Jun 2017, 22:26 »
The only way to create smooth and custom rotations is to calculate the rotated sprite yourself. That's actually what I did for my MarioKart demo, since the built in Rotate function causes jittering for large sprites due to rounding errors.
Unfortunately, doing it in real-time is pretty slow.

Mandle

  • NO PIXEL LEFT BEHIND!!!
  • Mandle worked on a game that was nominated for an AGS Award!
Re: Rotating an object around a pivot point.
« Reply #12 on: 21 Jun 2017, 01:38 »
I tried both methods, both Khris' code and expanding the sprite so that the pivot point was in the center. The latter method was a lot smoother, the code made the bell jitter around very unpleasantly, which I guess is the problem when you've got a lot of integer math going on.

Hehe, there's those keys! :P 8-)

Glad to hear my stop-gap solution helped out! A very nice feeling indeed!

Can't wait to play the game now even if just to see the bell in action... (laugh)