It is currently Mon Oct 23, 2017 1:45 pm

All times are UTC - 7 hours





Post new topic Reply to topic  [ 9 posts ] 
Author Message
PostPosted: Fri Nov 18, 2016 7:04 pm 
Offline

Joined: Thu Nov 10, 2016 2:45 pm
Posts: 6
Hi,

So in my game, there's an object that can move diagonally. But the angle is not always 45 degree. It can vary depending on the position of the object's target. I don't have a clue as to how I can do this on NES. I can do it easily on other engines like Unity 3D or Cocos. AFAIK, it's because we can't just use a vector like other game engine, right? Since floats are not exactly supported. So how do I do this?

Thanks in advance.


Top
 Profile  
 
PostPosted: Fri Nov 18, 2016 7:46 pm 
Offline
User avatar

Joined: Sat Jul 12, 2014 3:04 pm
Posts: 936
"Normally," (that is, with higher-powered computers) you'd normalize the difference vector and multiply by your desired speed […or have someone's modules do it for you]. However, normalizing a vector requires finding the magnitude, which requires squaring [multiplication] and square roots, and division. All of those are abysmally slow on 6502.

Castlevania II has a good solution, involving a table lookup after shifting the X- and Y- differences down equally, and using them as an index. I can't find the topic here where we discussed it.

Here's another topic discussing trying to shoot at a player.

edit: and here's another topic about 6502 trigonometry.


Last edited by Myask on Fri Nov 18, 2016 8:15 pm, edited 1 time in total.

Top
 Profile  
 
PostPosted: Fri Nov 18, 2016 7:53 pm 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19122
Location: NE Indiana, USA (NTSC)
Floats are not supported, but q8 fixed-point is.

Aiming a projectile isn't that slow, maybe about 700 cycles at most: one atan2 and two multiplies. Firing one projectile a frame won't contribute that much to slowdown. And even if you're looking for homing missile behavior on 8 different objects, you can have only one per frame adjust its heading.


Top
 Profile  
 
PostPosted: Fri Nov 18, 2016 7:56 pm 
Offline
User avatar

Joined: Mon Sep 15, 2014 4:35 pm
Posts: 3074
Location: Nacogdoches, Texas
To move in something other than a 45 degree angle, you have to move going less than one pixel per frame on an axis. I assume you have some sort of variable for x and y velocity? What you'd do, is add it to the variable for the object's position every frame. The object's position (and velocity) variable should not be measured in pixels, but fractions of pixels. When it's time to display the sprites, you'd only take the bits from the object's position variable that represent whole pixels. How you plan on setting this all up is up to you.

If you want to figure out how to calculate the x and y velocity, you don't. Instead, you have a precalculated table that list different values for each degree. The only need one table, as the values for y are the values for x, just backwards.


Top
 Profile  
 
PostPosted: Fri Nov 18, 2016 8:02 pm 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 5736
Location: Canada
If you aim by time rather than direction, you can use efficient power-of-two timings.

For example, if you want a projectile to hit a certain point in 64 frames (~1 second):

velocity = (target - position) / 64

This produces a velocity that will move "position" to "target" over 64 frames. A division by 64 of course can be done with 6 right shifts (and as mentioned above, "fixed point" is an important concept for precision to store those 6 sub-pixel bits).


Top
 Profile  
 
PostPosted: Fri Nov 18, 2016 9:15 pm 
Offline

Joined: Thu Aug 28, 2008 1:17 am
Posts: 591
What tepples said; fixed-point. There tends to be a lot of tutorials that are c64 oriented, but since it's basically the same processor - so you can use them. Also look up the fast mul for 65x. It's about a 2k table in rom (you'll know it when you see it described as (x^2)/4 in the f(x)). It's pretty quick, and should easily allow 16bit:16bit multiplication (as in 32bit * 32bit -> 32bit) should you need it. I mean, however you want to set the fixed point precision point (byte segmented for faster usage). As far as angle, a 0 to 90 degree (or whatever point system you pre-calculate) look up table should work (just invert whatever axis for the other coordinate planes).

_________________
__________________________
http://pcedev.wordpress.com


Top
 Profile  
 
PostPosted: Sun Nov 20, 2016 5:29 pm 
Offline

Joined: Wed Jul 30, 2008 12:03 am
Posts: 32
one way

determine your deltas dx, dy and what their signs are
decide which has the larger magnitude
develope an index using the signs and which has the larger magnitude
ie three bits two for signs and one for x or y having the larger magnitude
that will define the octant you're moving in and can be used to look up increments
you always move in the direction with the larger magnitude
you'll keep an error accumulator, ea which gets intialized to the greater magnitude
say dy is the greater and dx is the lesser
you'd intialize the ea to dy

take a step in the y direction and subtract dx from the ea
if the ea goes through zero ie if ea is greater after you subtract
you've accumulated y worth of x's and it's time to take a step in x and add dy back into the ea

here's some batari basic code and an excerpt from the asm code it produces

in bB

f{0} = 0

sets bit 0 in variable f to 0

edit: var36 =f is some cruft, ignore it


Code:


move
  temp1 = ea

  if f{0} then skip
  player0y = player0y + yinc[f]
  ea = ea - dx
  if temp1 < ea then ea = ea + dy : player0x = player0x + xinc[f]
  return
skip
  player0x = player0x + xinc[f]
  ea = ea - dy
  if temp1 < ea then ea = ea + dx : player0y = player0y + yinc[f] 
  return





setup_move
 if x0 < x1 then f{2} = 1 : dx = x1 - x0 else f{2} = 0 : dx = x0 - x1
 if y0 < y1 then f{1} = 1 : dy = y1 - y0 else f{1} = 0 : dy = y0 - y1

 if dx > dy then f{0} = 1 : ea = dx else f{0} = 0 : ea = dy
 var36 = f
 return





  data yinc
  $FF, $FF, $01, $01, $FF, $FF,$01, $01
end

  data xinc
  $FF, $FF, $FF, $FF, $01, $01, $01, $01
end



 
.move
 ; move

.L08 ;  temp1  =  ea

   LDA ea
   STA temp1
.
 ;

.L09 ;  if f{0} then skip

   LDA f
   LSR
   bcs .skip
.L010 ;  player0y  =  player0y  +  yinc[f]

   LDA player0y
   LDX f
   CLC
   ADC yinc,x
   STA player0y
.L011 ;  ea  =  ea  -  dx

   LDA ea
   SEC
   SBC dx
   STA ea
.L012 ;  if temp1  <  ea then ea  =  ea  +  dy  :  player0x  =  player0x  +  xinc[f]

   LDA temp1
   CMP ea
     BCS .skipL012
.condpart0
   LDA ea
   CLC
   ADC dy
   STA ea
   LDA player0x
   LDX f
   CLC
   ADC xinc,x
   STA player0x
.skipL012
.L013 ;  return

   RTS
.skip
 ; skip

.L014 ;  player0x  =  player0x  +  xinc[f]

   LDA player0x
   LDX f
   CLC
   ADC xinc,x
   STA player0x
.L015 ;  ea  =  ea  -  dy

   LDA ea
   SEC
   SBC dy
   STA ea
.L016 ;  if temp1  <  ea then ea  =  ea  +  dx  :  player0y  =  player0y  +  yinc[f]

   LDA temp1
   CMP ea
     BCS .skipL016
.condpart1
   LDA ea
   CLC
   ADC dx
   STA ea
   LDA player0y
   LDX f
   CLC
   ADC yinc,x
   STA player0y
.skipL016
.L017 ;  return

   RTS
.
 ;

.
 ;

.
 ;

.setup_move
 ; setup_move

.L018 ;  if x0  <  x1 then f{2}  =  1  :  dx  =  x1  -  x0 else f{2}  =  0  :  dx  =  x0  -  x1

   LDA x0
   CMP x1
     BCS .skipL018
.condpart2
   LDA f
   ORA #4
   STA f
   LDA x1
   SEC
   SBC x0
   STA dx
 jmp .skipelse0
.skipL018
   LDA f
   AND #251
   STA f
   LDA x0
   SEC
   SBC x1
   STA dx
.skipelse0
.L019 ;  if y0  <  y1 then f{1}  =  1  :  dy  =  y1  -  y0 else f{1}  =  0  :  dy  =  y0  -  y1

   LDA y0
   CMP y1
     BCS .skipL019
.condpart3
   LDA f
   ORA #2
   STA f
   LDA y1
   SEC
   SBC y0
   STA dy
 jmp .skipelse1
.skipL019
   LDA f
   AND #253
   STA f
   LDA y0
   SEC
   SBC y1
   STA dy
.skipelse1
.
 ;

.L020 ;  if dx  >  dy then f{0}  =  1  :  ea  =  dx else f{0}  =  0  :  ea  =  dy

   LDA dy
   CMP dx
     BCS .skipL020
.condpart4
   LDA f
   ORA #1
   STA f
   LDA dx
   STA ea
 jmp .skipelse2
.skipL020
   LDA f
   AND #254
   STA f
   LDA dy
   STA ea
.skipelse2
.L021 ;  var36  =  f

   LDA f
   STA var36
.L022 ;  return

   RTS
.
 ;

.L023 ;  data yinc

yinc
   .byte   $FF, $FF, $01, $01, $FF, $FF,$01, $01

.skipL023
.
 ;

.L024 ;  data xinc

xinc
   .byte   $FF, $FF, $FF, $FF, $01, $01, $01, $01

.skipL024
.
 ;


Top
 Profile  
 
PostPosted: Wed Nov 23, 2016 3:16 am 
Offline

Joined: Thu Nov 10, 2016 2:45 pm
Posts: 6
Thanks for the replies guys. This is too many information to chug at once, lol. A good thing though, since I have lots of ways to do it now. I have a question though. If I were to use the lookup table, won't it cost to much memory? I mean I need 90 bytes to store all 90 degrees values, right?


Top
 Profile  
 
PostPosted: Wed Nov 23, 2016 8:55 am 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19122
Location: NE Indiana, USA (NTSC)
Many games use brads, binary fractions of a turn such as 1/32 or 1/256, instead of degrees or radians. In a 32-step system such as that used in Thwaite, 0 to 31 represent 0 to 31/32*360 = 348.75 degrees in 1/32*360 = 11.25 degree steps.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 9 posts ] 

All times are UTC - 7 hours


Who is online

Users browsing this forum: Bing [Bot], Dwedit, lidnariq, romibraman and 6 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group