rotation/direction

BlitzPlus Forums/BlitzPlus Beginners Area/rotation/direction

Hi blitzcoders, can some one help me with an "rotation, direction" question.
Let's say i have created some 8, 16 or 36 or whatever rotated images(that part i allready understand). I need to know how to get the correct direction (the correct image out of, for example "36" images), when i got an angle from then mouse position or another object.
I know how to get the angle ( Atan2(y1-y2,x1-x2)) and the distance ,TotalDist# = Sqr#((XDist# * XDist#) + (YDist * YDist)). There is an example of it in the book "Learn to Program 2D games in Blitz Basic", but that function i so complex with "hundreds of variables ;)".
I only want to get an correct "direction number" out of an angle.
It should work with an Static object or an moving object, the moving part i should try to fix myself.

Get the angle and make sure it's in the range 0-359, the divide it by 360 (same principle applies if you are using radians, just the range is 0 - 2*PI). This will give you a number in the range 0-0.999999. Then multiply this number by the number of frames you are using e.g. 36. This will give you a frame number from 0 to 35. You may want to work out how to round it properly so that a frame number result of <.5 goes to the lower frame and >= 0.5 goes to the higher frame. Hope this makes sense.

Hi Grey Alien! thanks for your reply.
Ehh could you show me the code for this, please :).
I measure the angle between the mouse position and an object with atan2(my-y,mx-x), that's the only way i know it. That gives me an angle between -180 and 180, and every attempt in making an solution ends with an scream.

Too learn an programming language is not so hard, the difficulties is in all the other stuff ;).

Try this, I haven't tested it:

Const ANIM_FRAMES = 36
angle# = ATan2(my-y,mx-x) + 180 ;makes it in the range >0 to 360
unit# = angle#/360 ;get in the range >0 to 1 as a float
finalframe% = Ceil(unit*ANIM_FRAMES)-1 ;round up and subtract 1 to get in range 0 to ANIM_FRAMES-1


note that it's not ideal as the first frame will be shown for degrees 0 to 10 instead of -5 to 5 and so on. See if you can figure out how to make it more accurate ;-)

Super thanks, Grey Alien

I have not figured it out how to make it correct, would you mind helping me??
I hope you have the strength with me.
Here is what i achieved so far...well the images is a problem. Look in the Function "UpdateTank1(t.Tank)" there the problem is ???.

 
Graphics 640,480
SetBuffer BackBuffer()

Type Tank
	Field x#,y#,rot%
	Field speed%, moveable
End Type

Global tTank1.Tank = CreateTank.Tank(True,200,200)
Global tTank2.Tank = CreateTank.Tank(False,320,240)

Global iNumRotation = 36, fAngle#

Dim fXSinTable#(iNumRotation), fYCosTable#(iNumRotation)
Dim hImages(iNumRotation)

CreateImages("Bitmaps\tank1.bmp",iNumRotation)
PrecomputeSinCosTables()

; Main.^^^^^^^^^^^^^^^^^^^^^^
While Not KeyHit(1)
	Cls
	
	UpdateTank1(tTank1)
	UpdateTank1(tTank2)
	Flip
	
Wend
CleanUpImages()
EndGraphics()
End
;**************************************************************
;**** Functions ***********************************************
Function CreateTank.Tank(bMove, iX, iY)
	
	t.Tank = New Tank
	t\moveable = bMove
	t\x# = iX
	t\y# = iY
	
	Return t
End Function

Function PrecomputeSinCosTables()
   	
	Local iAngle = 0
   	; run through the full rotation cycle, and use Sin and Cos
   	; at Multiplyer increments, ie. 360/iNumRotation = 10
	Local iMultiplyer = 360 / iNumRotation
   	For iAngle = 0 To iNumRotation - 1
         
		fXSinTable#(iAngle) = Sin(iAngle * iMultiplyer)
        fYCosTable#(iAngle) = -Cos(iAngle * iMultiplyer)
   
	Next
	
End Function
;******************************************************************
Function CreateImages(sImage$,iNumRotation)
	AutoMidHandle True
	Local hTemp = LoadImage(sImage$)
		If hTemp = 0 Then RuntimeError "Can't find image - load error!!"
	MaskImage hTemp,255,0,255
	Local iMultiplyer = 360 / iNumRotation
	
	; rotate image to generate all directions
	For iLoop = 0 To iNumRotation - 1
	
        ; first copy the original image into the current frame
    	hImages(iLoop)=CopyImage( hTemp )
        ; rotate the frame the appropriate number of degrees
        RotateImage hImages(iLoop), iLoop * iMultiplyer 
    	 
	Next
	
	FreeImage hTemp : hTemp = 0
	
End Function
;**********************************************************************
Function UpdateTank1(t.Tank)
	If t\moveable Then
		If KeyDown(205) Then t\rot = t\rot + 1 ; Right
		If KeyDown(203) Then t\rot = t\rot - 1 ; Left 
	
		If t\rot > 35 Then t\rot = 0
		If t\rot < 0 Then t\rot = 35
	
		t\x# = t\x# + (fXSinTable#(t\rot)); * Speed) 
   		t\y# = t\y# + (fYCosTable#(t\rot)); * Speed)
		
		If t\x# <= 0 Then t\x# = 0
		If t\y# <= 0 Then t\y# = 0
		If t\x# > 620 Then t\x# = 620
		If t\y# > 460 Then t\y# = 460
		Text 10,60,"Tank1 rotation: " + t\rot
		DrawImage hImages(t\rot),t\x#, t\y#
	Else 
		Local iTile = UpdateTrigonometry()
		Text 10,30,"Tank2 Tilenumber: " + iTile
		DrawImage hImages(iTile), t\x, t\y
	End If
	
End Function
;***************************************************************************
Function UpdateTrigonometry()
	Local iTile, fUnit#
	; add 180, or else you got an value between -180 and 180.
	fAngle# = ATan2(tTank2\y# - tTank1\y# , tTank2\x# - tTank1\x#) + 180 	
	Text 10,10,"Angle: " + fAngle#
	Text 10,20,"cos: " + Cos(fAngle#)
	
	fUnit# = fAngle# / 360
	iTile = Ceil( fUnit# * iNumRotation ) - 1
	Return iTile
End Function
;****************************************************************************
Function CleanUpImages()
	For iLoop = 0 To iNumRotation-1
		FreeImage hImages(iLoop)
	Next
End Function



Sorry I've been a bit busy and literally can't find the time to look at it right now, hopefully soon...

You have been very helpful Grey Alien, you don't have to help me, i have to figure it out myself.
"Cudgel one's brains" ;). But don't be suprised if have the same question again, on this forum :).
....... I hope my english is readable.

Your English is fine. When you call CreateTank you don't need .Tank after the function name. .Tank is only needed in the function declaration. So you can do this:

Global tTank1.Tank = CreateTank(True,200,200)
It saves typing.

Anyway, to get frame 0 for angle -5 to 5 (where 0 is at the top, like a clock), we need to add on half of the number of "degrees per frame". 360/ANIM_FRAMES = degrees per frame. Then if the number is greater than 360, we have to keep it in the range 0 to 360, so we need to subtract 360 from it e.g. 362 changes to 362-360=2 degrees i.e. the first frame!

Adjusting my original code looks like this:

Const ANIM_FRAMES = 36
angle# = ATan2(my-y,mx-x) + 180 ;makes it in the range >0 to 360
;add on half the degrees per frame for accuracy
angle = angle + (360/ANIMFRAMES)/2
;Is angle too large now?
If angle > 360 then angle=angle-360
unit# = angle#/360 ;get in the range >0 to 1 as a float
finalframe% = Ceil(unit*ANIM_FRAMES)-1 ;round up and subtract 1 to get in range 0 to ANIM_FRAMES-1

And that's it I think. This is untested so I hope it works. Good luck.