Jump to content
Sign in to follow this  
artrag

IntyBASIC atan2(dx,dy)

Recommended Posts

To whom it may concern, a small and fast snippet useful for bullet aiming and other game mechanics.

The code is fully tested and optimized, ready to be used by coders in the IntyBASIC Programming Contest 2018.

 

PS

The post is about the function ATAN2(), sine and cosine come for free.

''''''''''''''''''''''''''''''''''''''''''''''''
'        ;;;;;;;; atan(2^(x/32))*128/pi ;;;;;;;;
atan_tab:   
        data $20,$20,$20,$21,$21,$22,$22,$23,$23,$23,$24,$24,$25,$25,$26,$26
        data $26,$27,$27,$28,$28,$28,$29,$29,$2A,$2A,$2A,$2B,$2B,$2C,$2C,$2C
        data $2D,$2D,$2D,$2E,$2E,$2E,$2F,$2F,$2F,$30,$30,$30,$31,$31,$31,$31
        data $32,$32,$32,$32,$33,$33,$33,$33,$34,$34,$34,$34,$35,$35,$35,$35
        data $36,$36,$36,$36,$36,$37,$37,$37,$37,$37,$37,$38,$38,$38,$38,$38
        data $38,$39,$39,$39,$39,$39,$39,$39,$39,$3A,$3A,$3A,$3A,$3A,$3A,$3A
        data $3A,$3B,$3B,$3B,$3B,$3B,$3B,$3B,$3B,$3B,$3B,$3B,$3C,$3C,$3C,$3C
        data $3C,$3C,$3C,$3C,$3C,$3C,$3C,$3C,$3C,$3D,$3D,$3D,$3D,$3D,$3D,$3D
        data $3D,$3D,$3D,$3D,$3D,$3D,$3D,$3D,$3D,$3D,$3D,$3D,$3E,$3E,$3E,$3E
        data $3E,$3E,$3E,$3E,$3E,$3E,$3E,$3E,$3E,$3E,$3E,$3E,$3E,$3E,$3E,$3E
        data $3E,$3E,$3E,$3E,$3E,$3E,$3E,$3E,$3E,$3E,$3E,$3E,$3F,$3F,$3F,$3F
        data $3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F
        data $3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F
        data $3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F
        data $3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F
        data $3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F
 
'        ;;;;;;;; log2(x)*32 ;;;;;;;; 
log2_tab:  
        data $00,$00,$20,$32,$40,$4A,$52,$59,$60,$65,$6A,$6E,$72,$76,$79,$7D
        data $80,$82,$85,$87,$8A,$8C,$8E,$90,$92,$94,$96,$98,$99,$9B,$9D,$9E
        data $A0,$A1,$A2,$A4,$A5,$A6,$A7,$A9,$AA,$AB,$AC,$AD,$AE,$AF,$B0,$B1
        data $B2,$B3,$B4,$B5,$B6,$B7,$B8,$B9,$B9,$BA,$BB,$BC,$BD,$BD,$BE,$BF
        data $C0,$C0,$C1,$C2,$C2,$C3,$C4,$C4,$C5,$C6,$C6,$C7,$C7,$C8,$C9,$C9
        data $CA,$CA,$CB,$CC,$CC,$CD,$CD,$CE,$CE,$CF,$CF,$D0,$D0,$D1,$D1,$D2
        data $D2,$D3,$D3,$D4,$D4,$D5,$D5,$D5,$D6,$D6,$D7,$D7,$D8,$D8,$D9,$D9
        data $D9,$DA,$DA,$DB,$DB,$DB,$DC,$DC,$DD,$DD,$DD,$DE,$DE,$DE,$DF,$DF
        data $DF,$E0,$E0,$E1,$E1,$E1,$E2,$E2,$E2,$E3,$E3,$E3,$E4,$E4,$E4,$E5
        data $E5,$E5,$E6,$E6,$E6,$E7,$E7,$E7,$E7,$E8,$E8,$E8,$E9,$E9,$E9,$EA
        data $EA,$EA,$EA,$EB,$EB,$EB,$EC,$EC,$EC,$EC,$ED,$ED,$ED,$ED,$EE,$EE
        data $EE,$EE,$EF,$EF,$EF,$EF,$F0,$F0,$F0,$F1,$F1,$F1,$F1,$F1,$F2,$F2
        data $F2,$F2,$F3,$F3,$F3,$F3,$F4,$F4,$F4,$F4,$F5,$F5,$F5,$F5,$F5,$F6
        data $F6,$F6,$F6,$F7,$F7,$F7,$F7,$F7,$F8,$F8,$F8,$F8,$F9,$F9,$F9,$F9
        data $F9,$FA,$FA,$FA,$FA,$FA,$FB,$FB,$FB,$FB,$FB,$FC,$FC,$FC,$FC,$FC
        data $FD,$FD,$FD,$FD,$FD,$FD,$FE,$FE,$FE,$FE,$FE,$FF,$FF,$FF,$FF,$FF
        data $FF							' trick to cope with 256
		

'-----------------------------------------------
' Source: https://www.msx.org/forum/msx-talk/development/8-bit-atan2?page=0
' 8-bit atan2
' Calculate the angle, in a 256-degree circle.
' The trick is to use logarithms to get the y/x ratio and
' integrate the power function into the atan table. 
'   input
'   #dx_in, #dy_in    in -256,255
'
'   output
'   angle       	 in 0-255
'      ^
'  q1  |  q0
'------+------>
'  q3  |  q2
'      |
		
		signed #dx_in
		signed #dy_in
		
atan2:  procedure
		if 	(#dy_in>0) then 
			if 	(#dx_in>0) then 
				gosub atan2_q0			'	q0 
			else
				#dx_in=-#dx_in			'	q1 				
				gosub atan2_q0 
				angle = (-angle) and $7F
				return		
			end if
		else 
			if 	(#dx_in>0) then 
				#dy_in=-#dy_in			'	q2 
				gosub atan2_q0 
				angle = -angle
				return		
			else
				#dx_in=-#dx_in			'	q3 				
				#dy_in=-#dy_in
				gosub atan2_q0 
				angle = angle + 128
				return		
			end if
		end if
		return
		end
		
atan2_q0: procedure         
		if (#dx_in>=#dy_in) then
			angle = (-atan_tab(log2_tab(#dx_in)-log2_tab(#dy_in))) and $3F		
		else
			angle = atan_tab(log2_tab(#dy_in)-log2_tab(#dx_in))
		end if
		return		
		end
		
    	
		
';;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
'    input
'    angle       in 0-255
' 
'    output
'    #dy_out = sin(angle)		in -256,256
' 	 #dx_out = cos(angle)    	in -256,256
		
getsincos: procedure
	#dy_out = #sin_table(angle)
	#dx_out = #cos_table(angle)
	end
	
#sin_table:
		data   0,    6,   12,   18,   25,   31,   37,   43,   49,   56,   62,   68,   74,   80,   86,   92
		data  97,  103,  109,  115,  120,  126,  131,  136,  142,  147,  152,  157,  162,  167,  171,  176
		data 181,  185,  189,  193,  197,  201,  205,  209,  212,  216,  219,  222,  225,  228,  231,  234
		data 236,  238,  241,  243,  244,  246,  248,  249,  251,  252,  253,  254,  254,  255,  255,  255
#cos_table:
		data  256,  255,  255,  255,  254,  254,  253,  252,  251,  249,  248,  246,  244,  243,  241,  238
		data  236,  234,  231,  228,  225,  222,  219,  216,  212,  209,  205,  201,  197,  193,  189,  185
		data  181,  176,  171,  167,  162,  157,  152,  147,  142,  136,  131,  126,  120,  115,  109,  103
		data   97,   92,   86,   80,   74,   68,   62,  56,    49,   43,   37,   31,   25,   18,   12,    6
		data    0,   -6,  -12,  -18,  -25,  -31,  -37,  -43,  -49,  -56,  -62,  -68,  -74,  -80,  -86,  -92
		data  -97, -103, -109, -115, -120, -126, -131, -136, -142, -147, -152, -157, -162, -167, -171, -176
		data -181, -185, -189, -193, -197, -201, -205, -209, -212, -216, -219, -222, -225, -228, -231, -234
		data -236, -238, -241, -243, -244, -246, -248, -249, -251, -252, -253, -254, -254, -255, -255, -255
		data -256, -255, -255, -255, -254, -254, -253, -252, -251, -249, -248, -246, -244, -243, -241, -238
		data -236, -234, -231, -228, -225, -222, -219, -216, -212, -209, -205, -201, -197, -193, -189, -185
		data -181, -176, -171, -167, -162, -157, -152, -147, -142, -136, -131, -126, -120, -115, -109, -103
		data  -97,  -92,  -86,  -80,  -74,  -68,  -62,  -56,  -49,  -43,  -37,  -31,  -25,  -18,  -12,   -6
		data    0,    6,   12,   18,   25,   31,   37,   43,   49,   56,   62,   68,   74,   80,   86,   92
		data   97,  103,  109,  115,  120,  126,  131,  136,  142,  147,  152,  157,  162,  167,  171,  176
		data  181,  185,  189,  193,  197,  201,  205,  209,  212,  216,  219,  222,  225,  228,  231,  234
		data  236,  238,  241,  243,  244,  246,  248,  249,  251,  252,  253,  254,  254,  255,  255,  255


  • Like 5

Share this post


Link to post
Share on other sites

Interesting approach, using logarithms to transform the division into a subtraction. That should be quite fast!

 

I wonder, does it make sense to add an antilog table, so you could also get a cheap divide approximate as part of this math kit? That is, div_approx = antilog(log(x) - log(y)). That could be useful for normalizing vectors, when combined with something like dist_fast. Depending on what you're doing, that may be a more direct route.

 

For example, if you know the delta-x and delta-y to the object you're aiming at, then you might want your target velocity to be roughly as follows:

 

.

dist = sqrt(dx*dx + dy*dy)
vx = dx / dist
vy = dy / dist

.

 

Of course, all this computation is very expensive. dist_fast lets you do the dist calculation quickly. If you could also do the divide quickly, then you'd be in good shape. Something like:

.

dist_log = log(dist_fast(dx, dy))
vx = antilog(log(dx) - dist_log)
vy = antilog(log(dy) - dist_log)

.

FWIW, here is my BASIC translation of the veclen2 function from dist_fast. I have not tested it. Free for all to use, naturally.

.

' From "Fast Linear Approximations of Euclidean Distance in Higher Dimensions"
' by Yoshikazu Ohashi, [email protected]
' in "Graphics Gems IV", Academic Press, 1994
'
' Takes input in #IX, #IY.  Returns result in #T.
' Can be converted to 8-bit values trivially.
DistFast    PROCEDURE
            #IX = ABS(#IX)
            #IY = ABS(#IY)
            IF #IX < #IY THEN #IX = #IY XOR #IX : #IY = #IX XOR #IY : #IX = #IY XOR #IX

            #T = #IY + #IY/2
            #T = #IX - #IX/32 - #IX/128 + #T/4 + #T/64
            END

Share this post


Link to post
Share on other sites

Wow! pretty cool! you both are better in maths than me :)

 

This is my atan2 code from Meteors, it returns the angle in the range 0-71, and my cos/sin table with 6 bit precision:

 

It depends on x(1) and x(0) to be in the range 0-159 and y(0) and y(1) in the range 0-95.

 

								IF x(1) > x(0) THEN
									IF y(1) > y(0) THEN
										d = atan2((x(1) - x(0)) / 4 + (y(1) - y(0)) / 4 * 40) + 54
									ELSE
										d = 54 - atan2((x(1) - x(0)) / 4 + (y(0) - y(1)) / 4 * 40)
									END IF
								ELSE
									IF y(1) > y(0) THEN
										d = 90 - atan2((x(0) - x(1)) / 4 + (y(1) - y(0)) / 4 * 40)
									ELSE
										d = atan2((x(0) - x(1)) / 4 + (y(0) - y(1)) / 4 * 40) + 18
									END IF
								END IF
								IF d >= 72 THEN d = d - 72

atan2:
	DATA 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	DATA 18,12,8,6,5,4,3,3,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0
	DATA 18,15,12,10,8,7,6,5,5,4,4,3,3,3,3,3,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1
	DATA 18,16,14,12,10,9,8,7,6,6,5,5,5,4,4,4,3,3,3,3,3,3,3,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1
	DATA 18,16,15,13,12,11,10,9,8,7,7,6,6,5,5,5,5,4,4,4,4,4,3,3,3,3,3,3,3,3,3,2,2,2,2,2,2,2,2,2
	DATA 18,17,15,14,13,12,11,10,9,9,8,7,7,7,6,6,6,5,5,5,5,4,4,4,4,4,4,3,3,3,3,3,3,3,3,3,3,3,2,2
	DATA 18,17,16,15,14,13,12,11,10,10,9,8,8,8,7,7,6,6,6,6,5,5,5,5,5,4,4,4,4,4,4,4,3,3,3,3,3,3,3,3
	DATA 18,17,16,15,14,13,13,12,11,10,10,9,9,8,8,8,7,7,7,6,6,6,6,5,5,5,5,5,5,4,4,4,4,4,4,4,4,4,3,3
	DATA 18,17,16,15,15,14,13,12,12,11,11,10,10,9,9,8,8,8,7,7,7,6,6,6,6,6,5,5,5,5,5,5,5,4,4,4,4,4,4,4
	DATA 18,17,16,16,15,14,14,13,12,12,11,11,10,10,9,9,9,8,8,8,7,7,7,7,6,6,6,6,6,5,5,5,5,5,5,5,5,4,4,4
	DATA 18,17,17,16,15,15,14,13,13,12,12,11,11,10,10,10,9,9,9,8,8,8,7,7,7,7,7,6,6,6,6,6,6,5,5,5,5,5,5,5
	DATA 18,17,17,16,16,15,14,14,13,13,12,12,11,11,11,10,10,9,9,9,9,8,8,8,7,7,7,7,7,6,6,6,6,6,6,6,5,5,5,5
	DATA 18,17,17,16,16,15,15,14,14,13,13,12,12,11,11,11,10,10,10,9,9,9,8,8,8,8,8,7,7,7,7,7,6,6,6,6,6,6,6,5
	DATA 18,17,17,16,16,15,15,14,14,13,13,13,12,12,11,11,11,10,10,10,9,9,9,9,8,8,8,8,8,7,7,7,7,7,7,6,6,6,6,6
	DATA 18,18,17,17,16,16,15,15,14,14,13,13,13,12,12,11,11,11,10,10,10,10,9,9,9,9,8,8,8,8,8,7,7,7,7,7,7,6,6,6
	DATA 18,18,17,17,16,16,15,15,14,14,14,13,13,13,12,12,11,11,11,11,10,10,10,9,9,9,9,9,8,8,8,8,8,7,7,7,7,7,7,7
	DATA 18,18,17,17,16,16,15,15,15,14,14,14,13,13,12,12,12,11,11,11,11,10,10,10,10,9,9,9,9,9,8,8,8,8,8,7,7,7,7,7
	DATA 18,18,17,17,16,16,16,15,15,14,14,14,13,13,13,12,12,12,12,11,11,11,10,10,10,10,9,9,9,9,9,8,8,8,8,8,8,7,7,7
	DATA 18,18,17,17,16,16,16,15,15,15,14,14,14,13,13,13,12,12,12,12,11,11,11,11,10,10,10,10,9,9,9,9,9,8,8,8,8,8,8,8
	DATA 18,18,17,17,17,16,16,16,15,15,14,14,14,14,13,13,13,12,12,12,12,11,11,11,11,10,10,10,10,10,9,9,9,9,9,8,8,8,8,8
	DATA 18,18,17,17,17,16,16,16,15,15,15,14,14,14,13,13,13,13,12,12,12,12,11,11,11,11,10,10,10,10,10,9,9,9,9,9,9,8,8,8
	DATA 18,18,17,17,17,16,16,16,15,15,15,15,14,14,14,13,13,13,13,12,12,12,12,11,11,11,11,10,10,10,10,10,10,9,9,9,9,9,9,8
	DATA 18,18,17,17,17,16,16,16,16,15,15,15,14,14,14,14,13,13,13,13,12,12,12,12,11,11,11,11,11,10,10,10,10,10,9,9,9,9,9,9
	DATA 18,18,17,17,17,17,16,16,16,15,15,15,15,14,14,14,13,13,13,13,12,12,12,12,12,11,11,11,11,11,10,10,10,10,10,10,9,9,9,9

cos:
	DATA 0
	DATA 6
	DATA 11
	DATA 17
	DATA 22
	DATA 27
	DATA 32
	DATA 37
	DATA 41
	DATA 45
	DATA 49
	DATA 52
	DATA 55
	DATA 58
	DATA 60
	DATA 62
	DATA 63
	DATA 63
	DATA 63
	DATA 63
	DATA 63
	DATA 62
	DATA 60
	DATA 58
	DATA 55
	DATA 52
	DATA 49
	DATA 45
	DATA 41
	DATA 37
	DATA 32
	DATA 27
	DATA 22
	DATA 17
	DATA 11
	DATA 6
	DATA 0
	DATA -5
	DATA -10
	DATA -16
	DATA -21
	DATA -26
	DATA -31
	DATA -36
	DATA -40
	DATA -44
	DATA -48
	DATA -51
	DATA -54
	DATA -57
	DATA -59
	DATA -61
	DATA -62
	DATA -63
	DATA -63
	DATA -63
	DATA -62
	DATA -61
	DATA -59
	DATA -57
	DATA -54
	DATA -51
	DATA -48
	DATA -44
	DATA -40
	DATA -36
	DATA -31
	DATA -26
	DATA -21
	DATA -16
	DATA -10
	DATA -5

sin:
	DATA -63
	DATA -63
	DATA -62
	DATA -61
	DATA -59
	DATA -57
	DATA -54
	DATA -51
	DATA -48
	DATA -44
	DATA -40
	DATA -36
	DATA -31
	DATA -26
	DATA -21
	DATA -16
	DATA -10
	DATA -5
	DATA 0
	DATA 6
	DATA 11
	DATA 17
	DATA 22
	DATA 27
	DATA 32
	DATA 37
	DATA 41
	DATA 45
	DATA 49
	DATA 52
	DATA 55
	DATA 58
	DATA 60
	DATA 62
	DATA 63
	DATA 63
	DATA 63
	DATA 63
	DATA 63
	DATA 62
	DATA 60
	DATA 58
	DATA 55
	DATA 52
	DATA 49
	DATA 45
	DATA 41
	DATA 37
	DATA 32
	DATA 27
	DATA 22
	DATA 17
	DATA 11
	DATA 6
	DATA 0
	DATA -5
	DATA -10
	DATA -16
	DATA -21
	DATA -26
	DATA -31
	DATA -36
	DATA -40
	DATA -44
	DATA -48
	DATA -51
	DATA -54
	DATA -57
	DATA -59
	DATA -61
	DATA -62
	DATA -63
  • Like 2

Share this post


Link to post
Share on other sites

I wonder how far I can really go making games without understanding (or implementing) any of these things. :dunce:

  • Like 1

Share this post


Link to post
Share on other sites

Can I ask a stupid question? What's an application for this atan() routine? Where and why would I use it for? :dunce:

Share this post


Link to post
Share on other sites

Can I ask a stupid question? What's an application for this atan() routine? Where and why would I use it for? :dunce:

It's the easiest way to point a shoot from an enemy to the player.

 

Another way would be a Bresenham line but I'm lazy :dunce: I think the startup calculations are too "heavy".

Share this post


Link to post
Share on other sites

Moreover using Bresenham for bullets of variable speed is not very practical, as you need to reiterate controls for each step of one pixel on the short side and it is not easy to calibrate the final speed (actually one could run two Bresenham algorithms, one on x the other on y, using time as short side, but things can get complex at will).

Edited by artrag

Share this post


Link to post
Share on other sites

Sorry, if I'm really dense, but I still don't get how I would use this. :dunce:

 

I know how I would do this with bresenham (and like artrag said, it would require adjusting as you go along), but I don't know how to use the arctangent. (I also don't really recall much of my high-school trig).

 

 

So you compute the angle at which to shoot, then what? Do you then use that to compute the x and y velocity components?

Share this post


Link to post
Share on other sites

Use cosine and sine of the resulting angle

They are the dx and dy of the bullet

Scale them to variate speed

 

Aha! Got it. Thanks! :thumbsup:

 

-dZ.

Share this post


Link to post
Share on other sites

I personally prefer to normalize the vector (dx, dy) if I can come up with a fast way to do that. Saves the trip through the arctan, sine and cosine and ends up being more accurate.

 

atan2() though can also be useful for picking a picture to render for an object, if the picture needs to change with respect to the object's actual heading.

Share this post


Link to post
Share on other sites

I personally prefer to normalize the vector (dx, dy) if I can come up with a fast way to do that. Saves the trip through the arctan, sine and cosine and ends up being more accurate.

 

atan2() though can also be useful for picking a picture to render for an object, if the picture needs to change with respect to the object's actual heading.

I will try to use logarithms to avoid the division and the norm approximation you posted.

For single bullets maybe it could be interesting. Anyway if you need to cast more bullets in a range of angles atan is the way.

Edited by artrag

Share this post


Link to post
Share on other sites

I personally prefer to normalize the vector (dx, dy) if I can come up with a fast way to do that.

 

What do you mean? :dunce:

Share this post


Link to post
Share on other sites

DZ, when you cast a bullet from (x0,y0) to (x1,y1), the full computation should be:

 

dx = x1-x0

dy = y1-y0

 

vx = s*dx/sqrt(dx*dx+dy*dy)

vy = s*dy/sqrt(dx*dx+dy*dy)

 

Where s is the speed of the bullet in pixels per loop iteration and (vx,vy) are the increments to be applied along the x and y to move the bullet

 

Assuming to approximate sqrt(dx*dx+dy*dy) as above by dist_fast(dx,dy), you still need two divisions to get the increments

 

norm = dist_fast(dx,dy)

 

vx = s*dx/norm

vy = s*dy/norm

 

Divisions are very time consuming and should be avoided when possible

 

A trick to avoid divisions is to resort to logarithms, because for positive numbers, if a=b/c, then a = 2^(log2(b)-log2( c))

 

Naturally if you want speed, you need to use tables of precomputed values, introducing some more approximations

 

In our case, willing to use tables of max 256 elements, limiting dx in -128,128, we have:

 

vx = s*dx/norm = sign(dx)* 2^(1/32*(32*log2(s)+32*log2(abs(dx))-32*log(norm)))

same for vy

 

so, we need a table of 128 values for the logarithm

logtab(x) = round(32*log2(x)) with x = 1:128

 

and a table of 256 values for the antilogarithm

antilog(x) = round(2^(x/32)) with x = 0:255

 

With the above tables you get

 

vx = sign(dx)*antilog(logtab(s)+logtab(abs(dx))-logtab(norm))

 

You can keep the antilog array of sole 256 elements even using 36 instead of 32 in the above formulas if |dx|<128. This increases slightly the overall accuracy, but in the end you get quite approximated results especially for large values of s and of |dx| or of |dy|. This could be due to accumulated effects of the norm approximation and of the rounding in the tables when we use values close to 128. The pro is that it is very fast! You have done just 4 accesses to tables (3 if the speed s is constant) and a couple of additions. Computing vy too, you reach 6 table accesses and 4 sums/subtractions that should be added to the 8 sums/logical operation and 5 shifts needed by dist_fast()

 

The other way is to use cosine and sine. DZ, What you need to know is that

 

vx = s*dx/sqrt(dx*dx+dy*dy) = s * cos(alpha)

vy = s*dy/sqrt(dx*dx+dy*dy) = s * sin(alpha)

 

where alpha is the angle of the right-angled triangle of sides dx and dy opposite to the side dy

 

Provided that tangent is defined in this way

 

tang(alpha) = sin(alpha)/cos(alpha) = dy / dx

 

and that arc-tangent is its inverse function for alpha in 0-180 degree, we have:

 

alpha = atan(dy/dx) + k *180°

 

where k can be determined by examining the signs of dx and dy separately.

 

The above atan2(dx,dy) function returns alpha unrolled in the whole circle, resolving the 180° uncertainness of the normal atan()

 

With this method, once you have dx and dy you need to do

 

alpha = atan2(dx,dy)

vx = s * cos(alpha)

vy = s * sin(alpha)

 

You get errors in any case when dx and dy are large, but the overall error is in +/- 1 step in the alpha angle

The cost is 3 table accesses and an addition in atan2, plus two table accesses and two multiplications for vx,vy. Total 5 table accesses, 1 addition, two multiplications.

 

In the end:

dist_fast and logarithms are faster but less accurate

atan2(), cos() and sin() are slower but more accurate

 

PS: the latter method is more interesting if you want to cast more bullets at the same time, e.g. 3 bullets, one at alpha, one at alpha+beta and one at alpha-beta

 

 

 

Edited by artrag
  • Like 4

Share this post


Link to post
Share on other sites

A small demo of atan2() just for fun, Being lazy, I have leaved the PSG log player as background

 

Sources and data included

 

Awesome, artrag! It illustrates the case perfectly. Thanks for posting it. :)

 

Nanochess, you should consider including something like this as a "contrib" in the next version of IntyBASIC.

 

-dZ.

Share this post


Link to post
Share on other sites

A small demo of atan2() just for fun, Being lazy, I have leaved the PSG log player as background

 

Sources and data included

 

artrag,

 

The RAR archive contains all the scripts and logs to generate the music data, but not the IntyBASIC source code to illustrate how to use the arctan() function. Perhaps it was an oversight?

 

-dZ.

Share this post


Link to post
Share on other sites

A small demo of atan2() just for fun, Being lazy, I have leaved the PSG log player as background

 

Sources and data included

[EDIT] now correct sources included (I hope...)

Pretty nice demo :)

 

Awesome, artrag! It illustrates the case perfectly. Thanks for posting it. :)

 

Nanochess, you should consider including something like this as a "contrib" in the next version of IntyBASIC.

 

-dZ.

I would be happy to include it if it's made to use a single source file.

 

I don't have yet decided how to include multi-source contributions. :ponder:

Share this post


Link to post
Share on other sites

Try now in the previous post. I fixed the sources

 

Here, instead, there is a slightly more advanced demo with 3 bullets

 

That looks very nice! :thumbsup:

Share this post


Link to post
Share on other sites

Pretty nice demo :)

 

 

I would be happy to include it if it's made to use a single source file.

 

I don't have yet decided how to include multi-source contributions. :ponder:

 

Also, I would recommend artag to include REM comments describing how the code works -- that's if he wants to submit it as a contribution to the SDK and the compiler's library.

 

-dZ.

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
Sign in to follow this  

  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...