Jump to content

Photo

IntyBASIC atan2(dx,dy)

Intybasic homebrew coding intellivision

22 replies to this topic

#1 artrag OFFLINE  

artrag

    Stargunner

  • 1,120 posts

Posted Thu Feb 15, 2018 2:46 PM

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




#2 intvnut OFFLINE  

intvnut

    River Patroller

  • 3,081 posts
  • Location:@R6 (top of stack)

Posted Thu Feb 15, 2018 4:34 PM

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, yoshi@cognex.com
' 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


#3 nanochess OFFLINE  

nanochess

    Processorus Polyglotus

  • 5,569 posts
  • Coding something good
  • Location:Mexico City

Posted Thu Feb 15, 2018 5:06 PM

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


#4 DZ-Jay OFFLINE  

DZ-Jay

    Quadrunner

  • 11,264 posts
  • The P-Machinery AGE is almost here!
  • Location:NC, USA

Posted Fri Feb 16, 2018 6:58 AM

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



#5 DZ-Jay OFFLINE  

DZ-Jay

    Quadrunner

  • 11,264 posts
  • The P-Machinery AGE is almost here!
  • Location:NC, USA

Posted Mon Feb 19, 2018 7:10 AM

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



#6 nanochess OFFLINE  

nanochess

    Processorus Polyglotus

  • 5,569 posts
  • Coding something good
  • Location:Mexico City

Posted Mon Feb 19, 2018 7:16 AM

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".

#7 artrag OFFLINE  

artrag

    Stargunner

  • Topic Starter
  • 1,120 posts

Posted Mon Feb 19, 2018 7:24 AM

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, Mon Feb 19, 2018 8:25 AM.


#8 DZ-Jay OFFLINE  

DZ-Jay

    Quadrunner

  • 11,264 posts
  • The P-Machinery AGE is almost here!
  • Location:NC, USA

Posted Mon Feb 19, 2018 7:31 AM

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?



#9 artrag OFFLINE  

artrag

    Stargunner

  • Topic Starter
  • 1,120 posts

Posted Mon Feb 19, 2018 7:46 AM

Use cosine and sine of the resulting angle
They are the dx and dy of the bullet
Scale them to variate speed

#10 DZ-Jay OFFLINE  

DZ-Jay

    Quadrunner

  • 11,264 posts
  • The P-Machinery AGE is almost here!
  • Location:NC, USA

Posted Mon Feb 19, 2018 8:17 AM

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.



#11 intvnut OFFLINE  

intvnut

    River Patroller

  • 3,081 posts
  • Location:@R6 (top of stack)

Posted Tue Feb 20, 2018 6:33 PM

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.



#12 artrag OFFLINE  

artrag

    Stargunner

  • Topic Starter
  • 1,120 posts

Posted Wed Feb 21, 2018 12:51 AM

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, Wed Feb 21, 2018 12:52 AM.


#13 DZ-Jay OFFLINE  

DZ-Jay

    Quadrunner

  • 11,264 posts
  • The P-Machinery AGE is almost here!
  • Location:NC, USA

Posted Wed Feb 21, 2018 6:51 AM

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:



#14 artrag OFFLINE  

artrag

    Stargunner

  • Topic Starter
  • 1,120 posts

Posted Wed Feb 21, 2018 4:26 PM

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, Fri Feb 23, 2018 2:02 AM.


#15 artrag OFFLINE  

artrag

    Stargunner

  • Topic Starter
  • 1,120 posts

Posted Sun Mar 11, 2018 4:29 AM

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

 

Sources and data included

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

Attached Files


Edited by artrag, Sun Mar 11, 2018 4:59 PM.


#16 DZ-Jay OFFLINE  

DZ-Jay

    Quadrunner

  • 11,264 posts
  • The P-Machinery AGE is almost here!
  • Location:NC, USA

Posted Sun Mar 11, 2018 6:25 AM

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.



#17 DZ-Jay OFFLINE  

DZ-Jay

    Quadrunner

  • 11,264 posts
  • The P-Machinery AGE is almost here!
  • Location:NC, USA

Posted Sun Mar 11, 2018 6:29 AM

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.



#18 artrag OFFLINE  

artrag

    Stargunner

  • Topic Starter
  • 1,120 posts

Posted Sun Mar 11, 2018 6:31 AM

True, I will fix it tonight

#19 DZ-Jay OFFLINE  

DZ-Jay

    Quadrunner

  • 11,264 posts
  • The P-Machinery AGE is almost here!
  • Location:NC, USA

Posted Sun Mar 11, 2018 6:32 AM

True, I will fix it tonight

 

No worries.  Thanks again! :)

 

  -dZ.



#20 artrag OFFLINE  

artrag

    Stargunner

  • Topic Starter
  • 1,120 posts

Posted Sun Mar 11, 2018 8:51 AM

 

No worries.  Thanks again! :)

 

  -dZ.

Try now in the previous post. I fixed the sources

 

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

Attached Files


Edited by artrag, Sun Mar 11, 2018 10:03 AM.


#21 nanochess OFFLINE  

nanochess

    Processorus Polyglotus

  • 5,569 posts
  • Coding something good
  • Location:Mexico City

Posted Sun Mar 11, 2018 12:53 PM

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:

#22 DZ-Jay OFFLINE  

DZ-Jay

    Quadrunner

  • 11,264 posts
  • The P-Machinery AGE is almost here!
  • Location:NC, USA

Posted Mon Mar 12, 2018 5:21 AM

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:



#23 DZ-Jay OFFLINE  

DZ-Jay

    Quadrunner

  • 11,264 posts
  • The P-Machinery AGE is almost here!
  • Location:NC, USA

Posted Mon Mar 12, 2018 5:29 AM

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.







Also tagged with one or more of these keywords: Intybasic, homebrew, coding, intellivision

0 user(s) are browsing this forum

0 members, 0 guests, 0 anonymous users