It is currently Thu Nov 15, 2018 12:01 pm

All times are UTC - 7 hours





Post new topic Reply to topic  [ 5 posts ] 
Author Message
PostPosted: Tue Jan 30, 2018 6:14 pm 
Offline
User avatar

Joined: Sat Sep 27, 2014 10:10 pm
Posts: 30
Location: Houston, TX
I'm wondering how I can improve on the code I've been working on over the past couple days and I've been reading a lot but making little progress. I'm wondering how I can make more of a generic system for handling hardware sprites and meta sprites. My current code is pretty ugly and I'm using constants in NESASM to refer to the RAM buffer for my player sprite like this:

Code:
PLAYER_Y = $0200
PLAYER_TILE = $0201
PLAYER_ATTR = $0202
PLAYER_X = $0203

player_x .rs 1
player_y .rs 1


And then I've got a drawing function that is basically doing this:

Code:
DrawPlayer:
  LDA player_x
  STA PLAYER_X
  LDA player_y
  STA PLAYER_Y


There's a little bit more math in there to calculate the offsets for the other tiles for my player's meta sprite as well.

Now this all works just fine but it's not the way I would approach it if I were coding in something like C or C++. I'm having a hard time wrapping my head around doing any abstraction when I'm coding in assembly. I see some people talking about using arrays and tables and things like that but I'm not quite sure how those are implemented in 6502 assembly.

I've added my sprites and nametables to a section of memory starting at $E000, which I understand to be cartridge rom. Is this the space that is typically used to store things like arrays and tables? For example if I wanted to create some simple sprite animations, would a typical approach be to do something like this:

Code:
walk_anim_ptr .rs 1


Code:
walk_animation_array:
  .db $03, walk1, walk2, walk3 ; length, 1, 2, 3

walk1:
  .db $80, $32, $00, $80
  .db $80, $33, $00, $88
  .db $88, $34, $00, $80
  .db $88, $35, $00, $88

walk2:
  .db $80, $32, $00, $80
  .db $80, $33, $00, $88
  .db $88, $34, $00, $80
  .db $88, $35, $00, $88

walk3:
  .db $80, $32, $00, $80
  .db $80, $33, $00, $88
  .db $88, $34, $00, $80
  .db $88, $35, $00, $88


Because the 6502 has an address bus width of 16, does that mean that my animation "data structure" if you could call it that, is 7 bytes long? Sorry for these simple questions. The tutorials I'm finding range from incredibly simple to very complex with little in between. I just want to make sure that I'm getting this right.

Are further abstractions possible here in terms of data structures? Could I for example implement something like a C struct? What would that look like? Or is that specific to the assembler that I'm using?

What would be a very simple next step from this approach I've outlined above to something that uses a bit more abstraction and possibly a more generalized approach?


Top
 Profile  
 
PostPosted: Tue Jan 30, 2018 7:51 pm 
Offline
User avatar

Joined: Thu Mar 31, 2016 11:15 am
Posts: 419
Do not hardcode the sprite locations. Instead, build the sprite buffer like a stack. Start with

Code:
ldx #0


Then to add a sprite to the buffer write code like this:

Code:
  lda player_x
  sta $203, x
  lda player_y
  sta $200, x
  lda #0
  sta $201, x
  sta $202, x
  inx
  inx
  inx
  inx


Once you've added all your sprites to the buffer you need to "clear" the remaining memory so that junk doesn't appear on the screen.

Code:
    lda #$FF
clearOAMLoop:
    sta $200, x
    inx
    inx
    inx
    inx
    bne clearOAMLoop


Note that you can replace the four 'inx' instructions two: 'tax' followed by the unofficial instruction 'axs #252'.

The way you've implemented metasprites looks fine, but I would consider adding a length field to each metasprite so that the routine can be made generic. Also, one thing metasprite routines typically do is handle clipping with the edges of the screen, and doing so likely requires working with 16 bit coordinates.


Top
 Profile  
 
PostPosted: Tue Jan 30, 2018 7:59 pm 
Offline
User avatar

Joined: Fri May 08, 2015 7:17 pm
Posts: 2331
Location: DIGDUG
.db $03, walk1, walk2, walk3

db is for 1 byte entries. You can't store an address in 1 byte (except for zero page RAM addresses, which these aren't).

nesasm uses .dw or .word for 2 byte addresses.

you can also store an address byte by byte using 2 db slots...

.db LOW[walk1], HIGH[walk1]

_________________
nesdoug.com -- blog/tutorial on programming for the NES


Top
 Profile  
 
PostPosted: Sat Feb 03, 2018 1:46 pm 
Offline
User avatar

Joined: Sat Sep 27, 2014 10:10 pm
Posts: 30
Location: Houston, TX
pubby wrote:
Do not hardcode the sprite locations. Instead, build the sprite buffer like a stack. Start with

Code:
ldx #0


Then to add a sprite to the buffer write code like this:

Code:
  lda player_x
  sta $203, x
  lda player_y
  sta $200, x
  lda #0
  sta $201, x
  sta $202, x
  inx
  inx
  inx
  inx


Once you've added all your sprites to the buffer you need to "clear" the remaining memory so that junk doesn't appear on the screen.

Code:
    lda #$FF
clearOAMLoop:
    sta $200, x
    inx
    inx
    inx
    inx
    bne clearOAMLoop


Note that you can replace the four 'inx' instructions two: 'tax' followed by the unofficial instruction 'axs #252'.

The way you've implemented metasprites looks fine, but I would consider adding a length field to each metasprite so that the routine can be made generic. Also, one thing metasprite routines typically do is handle clipping with the edges of the screen, and doing so likely requires working with 16 bit coordinates.


When I'm setting up my oam buffer, do I copy over all of the frames that I need for an animation or sprite flip and move them off screen when they aren't needed or do I reconstruct the oam buffer each frame? I'm assuming it would be quicker just to copy over what I need each frame right?

Let's say I have 16 bytes of memory for the meta sprite of the player facing right that I've copied to $0200 - $0204, but when left is pressed I want to switch to the left facing meta sprite, do I copy the left facing sprite to $0200 - $0204? Actually as I'm writing this it seems obvious that it is probably the correct way. I kept thinking for whatever reason that I would load all possible animation frames and everything into the oam buffer every frame.

Edit: I mean't 16 bytes with the first hardware sprite starting at $0200, not storing 16 bytes somehow into $0200 - $0204...

Actually now that I think about it, this is exactly what you told me in my sprite flipping thread. I think I'm finally getting what you were talking about.


Last edited by instantaphex on Sat Feb 03, 2018 2:01 pm, edited 1 time in total.

Top
 Profile  
 
PostPosted: Sat Feb 03, 2018 1:47 pm 
Offline
User avatar

Joined: Sat Sep 27, 2014 10:10 pm
Posts: 30
Location: Houston, TX
dougeff wrote:
.db $03, walk1, walk2, walk3

db is for 1 byte entries. You can't store an address in 1 byte (except for zero page RAM addresses, which these aren't).

nesasm uses .dw or .word for 2 byte addresses.

you can also store an address byte by byte using 2 db slots...

.db LOW[walk1], HIGH[walk1]


Oh right, that makes sense. Thanks for the correction. That is going to save me a headache later.


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

All times are UTC - 7 hours


Who is online

Users browsing this forum: No registered users and 1 guest


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