Page 1 of 1

Click detection on rotating circle

Posted: Thu Jul 31, 2008 11:05 am
by Fluid Byte
I'm just woundering how you would get the RGB value for a certain position from a Sprite3D. It's easy for images since you can use Start-/StopDrawing() and using ImageOutput() with the image you want the color value from. It's all in memory, nothing's painted on screen and then you simply use Point().

But how this works for sprites and 3D sprites in particular?

Posted: Thu Jul 31, 2008 11:13 am
by Kaeru Gaman
for sprites you can also use Draw with SpriteOutput.
or direct access with pointers wich is also an alternative for Images.

for sprite3D you have to access the texture-sprite (the 2D sprite you made the sprite3D from),
there is no way to access the transformed matrix since transformation is done on-the-fly while displaying.

Posted: Thu Jul 31, 2008 1:18 pm
by Fluid Byte
there is no way to access the transformed matrix since transformation is done on-the-fly while displaying
To put this straight, you don't only mean Rotate-/Zoom/-TransformSprite() but any form of accessing a Sprite3D for color information? That would be pretty bad because thats what I want to do. I am making a "Wheel Of Fortune" for my game using Sprite3D. I rotate the sprite and when the user clicks on it I determine wich part of the wheel has been clicked by checking a color mask of the same size.

Maybe there is another, better way to acomplish this?

Posted: Thu Jul 31, 2008 1:31 pm
by djes
After the sprite's being "painted" on the screen you can test the pixel under the mouse with point and StartDrawing(ScreenOutput())

Posted: Thu Jul 31, 2008 1:36 pm
by Kaeru Gaman
you have the rotation angle of the sprite,
the click-coordinate, and the centre-coordinate of the sprite.

the two coordinates are connected with a line that has a certain angle on the screen.
this angle minus the rotation angle of the sprite is the relative angle of the click on the base-sprite.

now you can set up a table of base angles wich field is wich on your wheel.


using color-maps for click location is a good idea for such things like clicking counties on a topographic map.
for easy mathematic problems like rotation angles it's overkill. ;)

Posted: Fri Aug 01, 2008 9:13 pm
by Fluid Byte
What can I say? I suck at math. I took you sugegstions and it's almost working. The Problem is when you substract the wheel angle from the mouse angle. Sometimes the angle gets negative and sometimes the result is simply wrong.

Here's what I have put together so far:

Code: Select all

InitSprite() : InitKeyboard() : InitSprite3D() : InitMouse()

CenterX = 320 : CenterY = 240 : Angle.f = 0 : Radius = 100

LoadFont(0,"Courier New",9,#PB_Font_Bold)

OpenWindow(0,0,0,640,480,"void",#PB_Window_SystemMenu | #PB_Window_ScreenCentered)
OpenWindowedScreen(WindowID(0),0,0,640,480,0,0,0)

lpBuffer = AllocateMemory(630)
UnpackMemory(?Cursor,lpBuffer)
CatchSprite(0,lpBuffer)
TransparentSpriteColor(0,RGB(0,128,128))
FreeMemory(lpBuffer) 

Procedure.f Angle(X1.f,Y1.f,X2.f,Y2.f)
	Protected A.f, B.f, C.f, Angle.f
	
	A = X2 - X1
	B = Y2 - Y1
	C = Sqr(A * A + B * B)
	
	Angle = ACos(A/C) * 57.29577

	If Y1 < Y2 : Angle = 360 - Angle : EndIf
	
	ProcedureReturn Angle
EndProcedure

Repeat
	EventID = WindowEvent()
		
	ClearScreen($202020)
	
	ExamineKeyboard() : ExamineMouse()
	
	If Angle = 360 : Angle = 0 : EndIf
	
	StartDrawing(ScreenOutput())	
	DrawingMode(#PB_2DDrawing_Outlined | #PB_2DDrawing_Transparent)
	DrawingFont(FontID(0))
	
	For i=0 To 90 Step 4
		LX = CenterX + (Cos((-i - Angle) / 180 * #PI) * Radius)
		LY = CenterY + (Sin((-i - Angle) / 180 * #PI) * Radius)	
		LineXY(CenterX,CenterY,LX,LY,#Red)
		
		LX = CenterX + (Cos((-i - Angle - 90) / 180 * #PI) * Radius)
		LY = CenterY + (Sin((-i - Angle - 90) / 180 * #PI) * Radius)	
		LineXY(CenterX,CenterY,LX,LY,#Green)		
		
		LX = CenterX + (Cos((-i - Angle - 180) / 180 * #PI) * Radius)
		LY = CenterY + (Sin((-i - Angle - 180) / 180 * #PI) * Radius)	
		LineXY(CenterX,CenterY,LX,LY,#Blue)
		
		LX = CenterX + (Cos((-i - Angle - 270) / 180 * #PI) * Radius)
		LY = CenterY + (Sin((-i - Angle - 270) / 180 * #PI) * Radius)	
		LineXY(CenterX,CenterY,LX,LY,#Yellow)
	Next
			
	Ellipse(CenterX,CenterY,Radius,Radius,#Green)
	
	FrontColor(#White)
	For i=0 To 359 Step 90
		TX = CenterX + (Cos((-i - Angle) / 180 * #PI) * (Radius + 20))
		TY = CenterY + (Sin((-i - Angle) / 180 * #PI) * (Radius + 20))
		DrawText(TX-15,TY-5,RSet(Str(i),3) + "°")
	Next
		
	LineXY(CenterX,CenterY,MouseX(),MouseY())
	
	MouseAngle.f = Angle(CenterX,CenterY,MouseX(),MouseY())
	ClickedAngle = MouseAngle - Angle
	
	DrawText(70,80,"Circle X / Y = " + Str(CenterX) + "," + Str(CenterY))
	DrawText(70,100,"Circle Angle = " + Str(Angle) + "°")	
	DrawText(70,120,"Mouse X / Y = " + Str(MouseX()) + "," + Str(MouseY()))
	DrawText(70,140,"Mouse Angle = " + Str(Mouseangle) + "°")
	DrawText(70,160,"Clicked Angle = " + Str((ClickedAngle)) + "°")
	
	DrawText(450,80,"   0-90° = Red")
	DrawText(450,100," 90-180° = Green")
	DrawText(450,120,"180-270° = Blue")
	DrawText(450,140,"270-360° = Yellow")
	
	DrawingMode(0)
	Box(420,80,20,14,#Red)
	Box(420,100,20,14,#Green)
	Box(420,120,20,14,#Blue)
	Box(420,140,20,14,#Yellow)
	
	DrawingMode(#PB_2DDrawing_Outlined)
	Select ClickedAngle
		Case 0 To 90 : BRDY = 80
		Case 90 To 180 : BRDY = 100
		Case 180 To 270 : BRDY = 120
		Case 270 To 359 : BRDY = 140
	EndSelect	
	Box(420,BRDY,20,14,#Black) : Box(419,BRDY-1,22,16,#White)
	StopDrawing()
	
	Angle + 0.25
	
	DisplayTransparentSprite(0,MouseX(),MouseY())
	
	FlipBuffers()
Until KeyboardPushed(1) Or EventID = #WM_CLOSE

DataSection
   Cursor:
   Data.l $0276434A,$4A720000,$A9B7AACC,$146320D0,$284A6811,$01232023,$9188409D,$F3000461,$20492601,$0A0401E0
   Data.l $E00081C0,$FFC0E015,$09302024,$409C3C04,$66013801,$FE4D02B6,$91FB77FB,$B7C236B7,$BDF63086,$BFEC1EC1
   Data.l $C0F36107,$0F625EF7,$008A083D,$87FFF581,$C4592A11,$4287C926,$3EC90540,$69F6974F,$21E5E328,$DDDE6107
   Data.l $50B353C6,$0FB86C06,$0000D893
   Data.b $90,$48
EndDataSection

Posted: Fri Aug 01, 2008 10:10 pm
by Kaeru Gaman
for the subtraction, try

( alpha - beta + 360 ) % 360

the +360 makes sure it is positive, the mod reduces it to one full circle.

the other point is to make sure you work with the same angle projection for both starting angles.
the zero degrees have to be in the same direction, you can mix up this easily using a bunch full of sine and cosine.
this is a bit more math.... I know...
nothing I'm keen on that on a hot midsummer friday night, sorries.

Posted: Fri Aug 01, 2008 10:12 pm
by Derek
Try inserting this

Code: Select all

If clickedangle<0
clickedangle+360
EndIf 
after

Code: Select all

MouseAngle.f = Angle(CenterX,CenterY,MouseX(),MouseY()) 
ClickedAngle = MouseAngle - Angle 

Posted: Fri Aug 01, 2008 10:15 pm
by Kaeru Gaman
Oy, those are floats.... then MOD will not work.

Posted: Fri Aug 01, 2008 11:18 pm
by Fluid Byte
Now that bitch is working like it should!

Thanks Kaeru, thanks Bender! Image

Posted: Sat Aug 02, 2008 9:00 am
by Derek
No probs 8)

Posted: Sat Aug 02, 2008 11:58 am
by Kaeru Gaman
yer welcome 8)

Re: Click detection on rotating circle

Posted: Mon Jan 25, 2021 3:56 pm
by infratec
Since I stumpled over this old thread, I ported it to newer PB versions:

Code: Select all

InitSprite() : InitKeyboard() : InitMouse()

CenterX = 320 : CenterY = 240 : Angle.f = 0 : Radius = 100

LoadFont(0,"Courier New",9,#PB_Font_Bold)

OpenWindow(0,0,0,640,480,"void",#PB_Window_SystemMenu | #PB_Window_ScreenCentered)
OpenWindowedScreen(WindowID(0),0,0,640,480,0,0,0)

UseJCALG1Packer()

lpBuffer = AllocateMemory(630)
UncompressMemory(?Cursor, ?CursorEnd - ?Cursor, lpBuffer, MemorySize(lpBuffer), #PB_PackerPlugin_JCALG1)
CatchSprite(0, lpBuffer)
TransparentSpriteColor(0,RGB(0,128,128))
FreeMemory(lpBuffer)

Procedure.f Angle(X1.f,Y1.f,X2.f,Y2.f)
  Protected A.f, B.f, C.f, Angle.f
  
  A = X2 - X1
  B = Y2 - Y1
  C = Sqr(A * A + B * B)
  
  Angle = ACos(A/C) * 57.29577
  
  If Y1 < Y2 : Angle = 360 - Angle : EndIf
  
  ProcedureReturn Angle
EndProcedure

Repeat
  EventID = WindowEvent()
  
  ClearScreen($202020)
  
  ExamineKeyboard() : ExamineMouse()
  
  If Angle = 360 : Angle = 0 : EndIf
  
  StartDrawing(ScreenOutput())   
  DrawingMode(#PB_2DDrawing_Outlined | #PB_2DDrawing_Transparent)
  DrawingFont(FontID(0))
  
  For i=0 To 90 Step 4
    LX = CenterX + (Cos((-i - Angle) / 180 * #PI) * Radius)
    LY = CenterY + (Sin((-i - Angle) / 180 * #PI) * Radius)   
    LineXY(CenterX,CenterY,LX,LY,#Red)
    
    LX = CenterX + (Cos((-i - Angle - 90) / 180 * #PI) * Radius)
    LY = CenterY + (Sin((-i - Angle - 90) / 180 * #PI) * Radius)   
    LineXY(CenterX,CenterY,LX,LY,#Green)      
    
    LX = CenterX + (Cos((-i - Angle - 180) / 180 * #PI) * Radius)
    LY = CenterY + (Sin((-i - Angle - 180) / 180 * #PI) * Radius)   
    LineXY(CenterX,CenterY,LX,LY,#Blue)
    
    LX = CenterX + (Cos((-i - Angle - 270) / 180 * #PI) * Radius)
    LY = CenterY + (Sin((-i - Angle - 270) / 180 * #PI) * Radius)   
    LineXY(CenterX,CenterY,LX,LY,#Yellow)
  Next
  
  Ellipse(CenterX,CenterY,Radius,Radius,#Green)
  
  FrontColor(#White)
  For i=0 To 359 Step 90
    TX = CenterX + (Cos((-i - Angle) / 180 * #PI) * (Radius + 20))
    TY = CenterY + (Sin((-i - Angle) / 180 * #PI) * (Radius + 20))
    DrawText(TX-15,TY-5,RSet(Str(i),3) + "°")
  Next
  
  LineXY(CenterX,CenterY,MouseX(),MouseY())
  
  MouseAngle.f = Angle(CenterX,CenterY,MouseX(),MouseY())
  ClickedAngle = MouseAngle - Angle
  If clickedangle < 0
    clickedangle + 360
  EndIf 
  
  DrawText(70,80,"Circle X / Y = " + Str(CenterX) + "," + Str(CenterY))
  DrawText(70,100,"Circle Angle = " + Str(Angle) + "°")   
  DrawText(70,120,"Mouse X / Y = " + Str(MouseX()) + "," + Str(MouseY()))
  DrawText(70,140,"Mouse Angle = " + Str(Mouseangle) + "°")
  DrawText(70,160,"Clicked Angle = " + Str((ClickedAngle)) + "°")
  
  DrawText(450,80,"   0-90° = Red")
  DrawText(450,100," 90-180° = Green")
  DrawText(450,120,"180-270° = Blue")
  DrawText(450,140,"270-360° = Yellow")
  
  DrawingMode(0)
  Box(420,80,20,14,#Red)
  Box(420,100,20,14,#Green)
  Box(420,120,20,14,#Blue)
  Box(420,140,20,14,#Yellow)
  
  DrawingMode(#PB_2DDrawing_Outlined)
  Select ClickedAngle
    Case 0 To 90 : BRDY = 80
    Case 90 To 180 : BRDY = 100
    Case 180 To 270 : BRDY = 120
    Case 270 To 359 : BRDY = 140
  EndSelect   
  Box(420,BRDY,20,14,#Black) : Box(419,BRDY-1,22,16,#White)
  StopDrawing()
  
  Angle + 0.25
  
  DisplayTransparentSprite(0,MouseX(),MouseY())
  
  FlipBuffers()
Until KeyboardPushed(1) Or EventID = #WM_CLOSE

DataSection
  Cursor:
  Data.l $0276434A,$4A720000,$A9B7AACC,$146320D0,$284A6811,$01232023,$9188409D,$F3000461,$20492601,$0A0401E0
  Data.l $E00081C0,$FFC0E015,$09302024,$409C3C04,$66013801,$FE4D02B6,$91FB77FB,$B7C236B7,$BDF63086,$BFEC1EC1
  Data.l $C0F36107,$0F625EF7,$008A083D,$87FFF581,$C4592A11,$4287C926,$3EC90540,$69F6974F,$21E5E328,$DDDE6107
  Data.l $50B353C6,$0FB86C06,$0000D893
  Data.b $90,$48
  CursorEnd:
EndDataSection
Bugfix from Derek is included :wink: