Page 1 of 1

Rotate Sprite around another's midpoint [SOLVED]

Posted: Fri Mar 08, 2024 9:18 pm
by tikidays
Hi, I have a spinning ship sprite (source) that has a light set at an offset, with Purebasic there appears to be no way to set the spin origin, so my routine below only rotates lights on the upper left XY of the ship's sprite and not the centre of the sprite.

Ive tried many ways to add XY offsets for the light to move it to the correct origin with DisplayTransparentSprite but nothing works. Im hoping I have missed something obvious.

Code: Select all

Procedure lights(*source.sprite)
   updateXY(*source\lights()\offsetX,*source\lights()\offsetY, *source\rotate)
   DisplayTransparentSprite(*source\lights()\image,  source\x + tempX , source\y + tempY ,255,*source\lights()\colour)
EndProcedure

Procedure updateXY(offsetX.f, offsetY.f, direction.f)
  directionRadian.f =  Radian(direction) ; convert angle from degree to radian
  tempX = ((offsetX)*Cos(directionRadian))-((offsetY)*Sin(directionRadian))
  tempY = ((offsetY)*Cos(directionRadian))+((offsetX)*Sin(directionRadian))
  EndProcedure
I think its a math problem, but one I cant seem to get my head around. As you can see I couldn't see an easy way to return the updated XY from the procedure as Purebasic only supports one variable to be returned?

Re: Rotate Sprite around another's midpoint

Posted: Fri Mar 08, 2024 10:15 pm
by STARGĂ…TE
The math of the rotation looks fine.
To return multiple values from a procedure you can use Pointers and additional parameters:

Code: Select all

Procedure lights(*source.sprite)
	Protected tempX.f, tempY.f
	updateXY(*source\lights()\offsetX,*source\lights()\offsetY, *source\rotate, @tempX, @tempY) ; pass pointer of tempX and tempY
	DisplayTransparentSprite(*source\lights()\image,  source\x + tempX , source\y + tempY ,255,*source\lights()\colour)
EndProcedure

Procedure updateXY(offsetX.f, offsetY.f, direction.f, *tempX.Float, *tempY.Float)
	directionRadian.f =  Radian(direction) ; convert angle from degree to radian
	*tempX\f = ((offsetX)*Cos(directionRadian))-((offsetY)*Sin(directionRadian))  ; Store the values at the passed pointer
	*tempY\f = ((offsetY)*Cos(directionRadian))+((offsetX)*Sin(directionRadian))
EndProcedure
You can also try my HyperTransformSprite().
It has two additional parameter for the rotation origin.

Re: Rotate Sprite around another's midpoint

Posted: Sat Mar 09, 2024 2:48 pm
by marc_256
@tikidays,

Hi, for my 2D applications I use my way to calculate some stuff ...
If I understand your problem well ...
You want to rotate a light around the center of a sprite (ship) in an 2D space.

Your solution

Code: Select all

Procedure lights(*source.sprite)
   updateXY(*source\lights()\offsetX,*source\lights()\offsetY, *source\rotate)
   DisplayTransparentSprite(*source\lights()\image,  source\x + tempX , source\y + tempY ,255,*source\lights()\colour)
EndProcedure

Procedure updateXY(offsetX.f, offsetY.f, direction.f)
  directionRadian.f =  Radian(direction) ; convert angle from degree to radian
  tempX = ((offsetX)*Cos(directionRadian))-((offsetY)*Sin(directionRadian))
  tempY = ((offsetY)*Cos(directionRadian))+((offsetX)*Sin(directionRadian))
  EndProcedure
I work with longer variable names, sorry but for an old guy and very complex 2D/3D drawing programs it is better for me.
Please adapt for your needs ...

Code: Select all

;- GLOBAL ZONE
Global ShipSprite_PosX.w
Global ShipSprite_PosY.w
Global ShipSprite_Width.w
Global ShipSprite_Height.w
Global ShipSprite_CenterX.w
Global ShipSprite_CenterY.w

Global Light_PosX.w
Global Light_PosY.w
Global Light_OffsetX.w
Global Light_OffsetY.w
Global Light_Distance.w
Global Light_Angle.f

;- INIT ZONE
ShipSprite_PosX = 400
ShipSprite_PosY = 300
ShipSprite_Width = 101
ShipSprite_Height = 101
ShipSprite_CenterX = ShipSprite_PosX + Round (ShipSprite_Width/2, #PB_Round_Up)
ShipSprite_CenterY = ShipSprite_PosY + Round (ShipSprite_Height/2, #PB_Round_Up)

Light_Distance = 200				; this is the distance in px between center of sprite and the light
Light_Angle = Radian (90.0)			; this is an example angle use for next loop for 0...360 deg
Light_OffsetX = Cos (Light_Angle) * Light_Distance
Light_OffsetY = Sin (Light_Angle) * Light_Distance
Light_PosX = ShipSprite_CenterX + Light_OffsetX
Light_PosY = ShipSprite_CenterY + Light_OffsetY


Marc,

Re: Rotate Sprite around another's midpoint

Posted: Sun Mar 10, 2024 4:26 am
by tikidays
@Stargate

Thanks so much for your feedback, cleared up my understanding around pointers, most appreciated.

@marc_256

Awesome example, rotating around the ship will come in handy later on!



But these lights I want to stay in a fixed position as the ship rotates. My code appears to keep the lights in the right position, but appear to be rotating around some other point than the midpoint.

Re: Rotate Sprite around another's midpoint [SOLVED]

Posted: Fri Mar 15, 2024 6:51 pm
by tikidays
Discovered the issue, when I was setting up the lights I was placing them from the upper left x,y of the sprite, not from the mid point, I then pass the mid point of the main ship sprite to the DRAW command and this resolved the issue. I also had to take into account the mid points of the lights. Hope this helps someone else. :D