6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Sat Oct 05, 2024 7:34 am

All times are UTC




Post new topic Reply to topic  [ 6 posts ] 
Author Message
PostPosted: Fri Aug 23, 2013 2:25 pm 
Offline
User avatar

Joined: Wed May 30, 2012 7:45 pm
Posts: 58
Location: Dallas, TX
I have a routine for one of my Atari 2600 projects. The basic concept of what I am doing is drawing a gamesprite one line at a time.

Sprites' for the Atari are 8 bits wide and as many scanlines tall as you want. For brevity, I'm going to share as little code as possible.

I have decided to use a table pointer because I will store the multiple sprite frames in different tables for animation. Before I decided to animate my sprite, I used the Absolute Indexed mode:

Code:
   ldy SpriteLine ; counter for which line we are drawing
   beq .finish
   lda Sprite-1, y ; <-- this is what I don't like.  Since we beq on zero, I have to reduce this by 1
   sta GRP0 ; player 0 graphics register
   dec SpriteLine
.finish

; elsewhere

Sprite:
   .byte #%00011000
   .byte #%00111100
   .byte #%00011000


In the above code, I am trying to draw a simple diamond shape, 3 scanlines tall. If I don't use the -1 on the Sprite table, it will draw the byte before the table and cut off the bottom.

I've seen this convention used to offset tables, but how would I do that when the table is defined in a pointer? For instance:

Code:
   ldy SpriteLine ; counter for which line we are drawing
   beq .finish
   lda (SpritePtr), y
   sta GRP0 ; player 0 graphics register
   dec SpriteLine
.finish

; elsewhere

Sprite:
   .byte #%00011000
   .byte #%00111100
   .byte #%00011000


That is fine, but I cannot use -1 on the SpritePtr because it would change the pointer itself. Using -1 on Y doesn't work either.

I personally don't like having to use a -1 to begin with. What solutions would make this more sound?

_________________
http://www.thestarrlab.com


Top
 Profile  
Reply with quote  
PostPosted: Fri Aug 23, 2013 3:13 pm 
Offline
User avatar

Joined: Sun Jun 30, 2013 10:26 pm
Posts: 1948
Location: Sacramento, CA, USA
Hello, Johnny

Without seeing the surrounding code to determine whether or not there is a more efficient way, it looks to me like you could simply replace:

Code:
  beq  .finish


with:

Code:
  dey
  bmi  .finish


for the desired behavior. This assumes that your sprite table is always smaller than 128 bytes, but I believe that to be a safe assumption in this case.

If cycle counts are absolutely critical, another method could be to offset the sprite address by one to begin with, or add a 'dummy' byte to the beginning of every sprite table.

Happy coding!

Mike


Top
 Profile  
Reply with quote  
PostPosted: Fri Aug 23, 2013 3:35 pm 
Offline
User avatar

Joined: Wed May 30, 2012 7:45 pm
Posts: 58
Location: Dallas, TX
Ahh yes, 1 less byte of ROM vs. cycles. And yes, 128 bytes for the sprite table is large, but there are 192 scanlines on the typical CRT, and there are times when it would be desirable for a sprite to be drawn on all lines, although it wouldn't be very common.

I think the dummy byte will work for now, but I was hoping for a more elegant solution. If you would like to see the entire scanloop to determine what that might be, then here ya go:

Code:
WaitForVBlank:
   lda INTIM
   bne WaitForVBlank
   ldx #191
   sta WSYNC
   sta VBLANK
   sta WSYNC
   sta HMOVE

   
ScanLoop:
   sta WSYNC
   

; check the activation of sprite
   cpx SpriteY      ; does this scanline match the inital line of our sprite?
   bne .skip      ; if not, skip activation
   lda #8         ; if true, load the size of our sprite to A
   sta SpriteLine   ; store the size in our SpriteLine counter
.skip
   lda #0         ; assuming the sprite is not to be drawn on this line
   sta GRP0      ; store 0 to player graphics register
   ldy SpriteLine   ; load the counter
   beq .finish      ; if it is zero, this means that we're done here
   lda (SpritePtr),y   ; if not zero, draw what we have in our sprite table at y
   sta GRP0      ; store it in our player graphics register
   dec SpriteLine   ; decrease the player line by 1 and move on
.finish

   ; playfield stuff
   

   

   

   dex
   bne ScanLoop
   
   lda #%00000010
   sta WSYNC
   sta VBLANK
   ldx #30 ; setup 30 scan lines for overscan
   
Overscan:
   sta   WSYNC
   dex
   bne Overscan
   jmp Main
   
   
Sprite:
   .byte 0
   .byte #%10100101
   .byte #%01011010
   .byte #%00100100
   .byte #%11111111
   .byte #%11011011
   .byte #%01111110
   .byte #%00111100
   .byte #%00011000


As you can see, the sprite isn't a 3 level diamond. It is actually the sprite from space invaders :) The above uses the dummy byte as you suggested.

Here is what my code displays:

https://www.youtube.com/watch?v=r3qOX2OYu24

_________________
http://www.thestarrlab.com


Top
 Profile  
Reply with quote  
PostPosted: Fri Aug 23, 2013 6:41 pm 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8521
Location: Southern California
My choice would be to do what results in the shortest and fastest code in the target computer, not necessarily in the source code. So if you don't like LDA Sprite-1, y (which there's nothing wrong with, but it's always good to explain why the -1, in the comments), you could do something like:
Code:
Sprite:  EQU  *-1
   .byte #%00011000
   .byte #%00111100
   .byte #%00011000

to avoid taking an extra byte in the table.

_________________
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?


Top
 Profile  
Reply with quote  
PostPosted: Fri Aug 23, 2013 6:55 pm 
Offline
User avatar

Joined: Wed May 30, 2012 7:45 pm
Posts: 58
Location: Dallas, TX
I like it. And good point about "shortest and fasted code in the target computer". I will try to think those terms more often.

_________________
http://www.thestarrlab.com


Top
 Profile  
Reply with quote  
PostPosted: Sat Aug 24, 2013 12:38 am 
Offline

Joined: Sun Nov 08, 2009 1:56 am
Posts: 400
Location: Minnesota
This might be a bit shorter and faster while getting rid of the (perfectly valid and useful) assembly-time computation:

Code:
  sta SpriteLine  ; initialize to zero outside loop
ScanLoop:
  sta WSYNC

  ldy SpriteLine  ; are we drawing a sprite now ?
  bne .nextline   ; b: yes
  tya             ; assume we're not going to start
  cpx SpriteY     ; should we start drawing now ?
  bne .nodraw     ; b: no
  ldy #8          ; height of sprite
.nextline
  dey             ; count down
  sty SpriteLine  ; last data line resets this to zero
  lda Sprite,y    ; image data...
.nodraw           ; ...or lack thereof...
  sta GRPO        ; ...to player graphics register

; elsewhere

Sprite:
   .byte #%10100101
   .byte #%01011010
   .byte #%00100100
   .byte #%11111111
   .byte #%11011011
   .byte #%01111110
   .byte #%00111100
   .byte #%00011000



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

All times are UTC


Who is online

Users browsing this forum: No registered users and 14 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: