YE old rotate (Dynamic Sprite Rotate)

Started by Dualnames, Wed 06/03/2019 20:10:00

Previous topic - Next topic

Dualnames

Is there a way I can rotate a dynamic sprite from it's bottom part around a specific coordinate? Example like a clock.
Worked on Strangeland, Primordia, Hob's Barrow, The Cat Lady, Mage's Initiation, Until I Have You, Downfall, Hunie Pop, and every game in the Wadjet Eye Games catalogue (porting)

Snarky

#1
Rotate around the center (well, you have no choice), but use trigonometry to calculate where the point you really want to rotate around ends up, and then just translate the rotated sprite to keep that point fixed.

Unfortunately, due to rounding errors and low resolution I fear you will see some jittering.

Alternative 2: Just pad the sprite so that the coordinate you want to stay fixed is in the center.

Khris

Here you go:

Code: ags
int[] GetRotationOffset(int slot, float pivotX, float pivotY, int angle) {
  float w = IntToFloat(Game.SpriteWidth[slot]), h = IntToFloat(Game.SpriteHeight[slot]);
  float a = Maths.DegreesToRadians(IntToFloat(angle));
  float c = Maths.Cos(a), s = Maths.Sin(a);
  // vector from pivot to top left corner, rotated by angle
  float pxr = c * -pivotX - s * -pivotY;
  float pyr = s * -pivotX + c * -pivotY;
  // add bounding box offset
  if (angle < 90) pxr -= s * h;
  else if (angle < 180) { pxr += c * w - s * h; pyr += c * h; }
  else if (angle < 270) { pxr += c * w; pyr += s * w + c * h; }
  else if (angle < 360) pyr += s * w;
  int r[] = new int[2];
  r[0] = FloatToInt(pxr, eRoundNearest);
  r[1] = FloatToInt(pyr, eRoundNearest);
  return r;
}


Use like this:

Code: ags
  // calculate offset for Sprite #1 rotated around center of its (15, 30) pixel by a degrees
  int offset[] = GetRotationOffset(1, 15.5, 30.5, a);   // a is 0-359!
  DynamicSprite* temp = DynamicSprite.CreateFromExistingSprite(1);
  if (a) temp.Rotate(a);
  // draw sprite so its (15, 30) pixels appears at (50, 80)
  ds.DrawImage(50 + offset[0], 80 + offset[1], temp.Graphic);

Gurok

Might be nice to wrap these up as an extender method for DynamicSprites. RotatePivoted maybe?
[img]http://7d4iqnx.gif;rWRLUuw.gi

Dualnames

Yep, been already using Khris fantastic module, only to look at the code and realize it's legit 3 lines
Worked on Strangeland, Primordia, Hob's Barrow, The Cat Lady, Mage's Initiation, Until I Have You, Downfall, Hunie Pop, and every game in the Wadjet Eye Games catalogue (porting)

Dualnames

That is not what I'm looking for, I have misexplained I think, so you see when we have a clock, right, doesn't one of the thingamabobs move clockwise, with its base staying in the middle and its top goiing 12 1 2 3 4 5 6, etc, that's how I'm trying to rotate.
Worked on Strangeland, Primordia, Hob's Barrow, The Cat Lady, Mage's Initiation, Until I Have You, Downfall, Hunie Pop, and every game in the Wadjet Eye Games catalogue (porting)

Khris

#6
That's exactly what the function does :)

I have used this "clock hand" to test it:

[imgzoom]https://i.imgur.com/SvlmmbL.png[/imgzoom]

The red cross is at 15, 30 and was at screen coordinates 50, 80 at all times, regardless of the angle. I tried to post a gif but HyperCam is refusing to store video right now.

Snarky

#7
Quote from: Gurok on Thu 07/03/2019 07:00:34
Might be nice to wrap these up as an extender method for DynamicSprites. RotatePivoted maybe?

The problem is that DynamicSprites have no notion of where they're placed: to perform rotation around a pivot anywhere other than the center of the sprite, you have to reposition whatever thing the sprite is displayed on. (In fact, you probably need to do this even if you do rotate around the center, since the dimensions of the resulting sprite is different â€" unless you crop it, of course.)

Quote from: Khris on Thu 07/03/2019 00:57:31
Code: ags
  // calculate offset for Sprite #1 rotated around center of its (15, 30) pixel by a degrees
  int offset[] = GetRotationOffset(1, 15.5, 30.5, a);   // a is 0-359!
  DynamicSprite* temp = DynamicSprite.CreateFromExistingSprite(1);
  if (a) temp.Rotate(a);
  // draw sprite so its (15, 30) pixels appears at (50, 80)
  ds.DrawImage(50 + offset[0], 80 + offset[1], temp.Graphic);


Seems to me like this code will pretty soon end up with the DrawImage() outside of the ds dimensions. Why not just draw directly to ds and reposition it, thereby avoiding the rotated sprite being cut off?

If you don't want to reposition (maybe things like baselines are an issue), your original sprite needs to be padded big enough to display the whole image through any relevant rotation. That means you're pretty much back to my Alternative 2: just pad the sprite so that the pivot point you want is in the center (and the bits furthest out aren't cut off by the sprite edges when rotated: i.e., pad the width and height to 2*sqrt(2) of the max x/y distance from the pivot point).

Khris

The  ds  in that example code is the room's background drawing surface.

Regarding possible extender functions, I guess the most sensible would be DrawingSurface.DrawImageRotated(), at least in theory. In practice, rotating sprites has to be optimized as far as possible to avoid slowdowns, and I don't think that a single extender functions offers the necessary flexibility.

SMF spam blocked by CleanTalk