It is currently Tue Dec 12, 2017 3:37 am

All times are UTC - 7 hours





Post new topic Reply to topic  [ 1389 posts ]  Go to page Previous  1, 2, 3, 4, 5, 6, 7 ... 93  Next
Author Message
 Post subject:
PostPosted: Fri Mar 25, 2011 5:28 pm 
Offline

Joined: Sat Mar 05, 2011 3:17 pm
Posts: 28
Location: Houston, Texas
unregistered wrote:
[color=#808080]^ yesyesyall, sorry, I'm uncomfortable to meet with you. :oops:
cool! totally understand!


Top
 Profile  
 
 Post subject:
PostPosted: Mon Mar 28, 2011 3:43 pm 
Offline
User avatar

Joined: Thu Apr 23, 2009 11:21 pm
Posts: 805
Location: cypress, texas
unregistered wrote:
tokumaru wrote:
It may seem strange if you are doing it in a hardcoded way (manually setting up all the sprites of a particular object), but usually programmers implement a sprite system. For each possible frame of a character there is a list of the necessary sprites to draw it. It's just a series of .db or .dw statements that represent things like "this frame needs 4 sprites; the first one is at coordinates (4, 5) and uses tile $78; the second is at coordinates (12, 8) and uses tile $79 (...)". The coordinates are usually relative to the position of the object/character being drawn.


How do you make the coordinates relative to the position of the object/character being drawn?
Code:
aY .byte 10
aX .byte 20
.db aY, $80, $00, aX, aY, $81, $00, aX +1
would this work?

Code:
aY .equ 10
aX .equ 20
.db aY,$80,$00, aX, aY, $81, $00, aX +1
this would work but I don't understand how the coordinates would stay relative. Aren't aY and aX constants here?

unregistered wrote:
tokumaru wrote:
This means that the sprite system can draw any frame of any character if you point it to the correct list.

Really happy to have found this, thank you. :)


Top
 Profile  
 
 Post subject:
PostPosted: Mon Mar 28, 2011 3:46 pm 
Offline
User avatar

Joined: Wed Oct 15, 2008 11:50 am
Posts: 939
The positions you specify in the meta-sprite are relative to the object's origin. You make it relative to the object's position by adding the object's position to those values. If you game scrolls you will also need to subtract the scroll amounts.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Mar 28, 2011 5:24 pm 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10164
Location: Rio de Janeiro - Brazil
There is no automatic way to make the coordinates relative. This is not something the NES or the assembler will do for you, you'll have to code the logic for this yourself.

Every frame, instead of blindly copying the meta-sprite definitions directly to OAM, you'll do some processing with that data. Since you have the position of the object somewhere in RAM, you'll have to add the relative sprite coordinates to the object coordinates in order to find the final sprite coordinates, which you'll then write to OAM. Be careful with sprites going off screen, as you probably don't want pats of your characters wrapping to the opposite side of the screen.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Mar 31, 2011 10:25 am 
Offline
User avatar

Joined: Thu Apr 23, 2009 11:21 pm
Posts: 805
Location: cypress, texas
Thank you qbradq and tokumaru, that makes sense; I'm stumbling on one part... how do you, or what is the best way you can, write to OAM? Right now i have one meta-sprite to display and move around the screen. Am i susposed to use lda and sta to write all the sprites to $0200?
Each frame during v blank it sends all of $0200 - $02ff to OAM through the OAM_DMA register. That's all I can think of... lda and sta to page 02.... is there a better method?


Top
 Profile  
 
 Post subject:
PostPosted: Thu Mar 31, 2011 11:47 am 
Offline
User avatar

Joined: Wed Oct 15, 2008 11:50 am
Posts: 939
Nope. That's how most games (homebrew and commercial alike) do it.

Also, you do not usually allocate slots within the OAM page to specific objects. Rather you loop over all of your objects each frame and lay down thier OAM data in the OAM page. That way when you need to start cycling your sprites (and you will, trust me), you can just change your starting location in the OAM page each frame.

But we'll cover sprite cycling when you get there :D


Top
 Profile  
 
 Post subject:
PostPosted: Thu Mar 31, 2011 4:13 pm 
Offline
User avatar

Joined: Thu Apr 23, 2009 11:21 pm
Posts: 805
Location: cypress, texas
unregistered wrote:
unregistered wrote:
tokumaru wrote:
This means that the sprite system can draw any frame of any character if you point it to the correct list.



How do you point it to the correct list? So far I have this
Code:
;80 81       
;90 91       
;a0 a1       
;b0 b1   
        .db aY, $80, $00, aX, aY, $81, $00, aX+8,
          aY+8, $90, $00, aX, aY+8, $91, $00, aX+8,
          aY+16, $a0, $00, aX, aY+16, $a1, $00, aX+8,
         aY+24, $b0, $00, aX, aY+24, $b1, $00, aX+8

There's something i'm missing. :(


Top
 Profile  
 
 Post subject:
PostPosted: Thu Mar 31, 2011 5:33 pm 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19334
Location: NE Indiana, USA (NTSC)
It'd go a little something like this (untested):
Code:
hero_frame1:
  .db aY,    $80, $00, aX, aY,    $81, $00, aX+8
  .db aY+8,  $90, $00, aX, aY+8,  $91, $00, aX+8
  .db aY+16, $a0, $00, aX, aY+16, $a1, $00, aX+8
  .db aY+24, $b0, $00, aX, aY+24, $b1, $00, aX+8
hero_frame2:
  .db aY,    $82, $00, aX, aY,    $83, $00, aX+8
  .db aY+8,  $92, $00, aX, aY+8,  $93, $00, aX+8
  .db aY+16, $a2, $00, aX, aY+16, $a3, $00, aX+8
  .db aY+24, $b2, $00, aX, aY+24, $b3, $00, aX+8
hero_frame3:
  .db aY,    $84, $00, aX, aY,    $85, $00, aX+8
  .db aY+8,  $94, $00, aX, aY+8,  $95, $00, aX+8
  .db aY+16, $a4, $00, aX, aY+16, $a5, $00, aX+8
  .db aY+24, $b4, $00, aX, aY+24, $b5, $00, aX+8
hero_frame4:
  .db aY,    $86, $00, aX, aY,    $87, $00, aX+8
  .db aY+8,  $96, $00, aX, aY+8,  $97, $00, aX+8
  .db aY+16, $a6, $00, aX, aY+16, $a7, $00, aX+8
  .db aY+24, $b6, $00, aX, aY+24, $b7, $00, aX+8

; Operator < produces the low byte of an address
sprite_layouts_lo:
  .db <hero_frame1, <hero_frame2, <hero_frame3, <hero_frame4

; Operator > produces the high byte of an address
sprite_layouts_hi:
  .db >hero_frame1, >hero_frame2, >hero_frame3, >hero_frame4

; Number of hardware sprites in each layout
sprite_layouts_count:
  .db 8, 8, 8, 8

draw_sprite:
  ; t0-t2 are temporary zero page locations holding
  ; the address of a particular sprite layout and the
  ; number of sprites left to draw
  lda sprite_layouts_lo,x
  sta t0
  lda sprite_layouts_hi,x
  sta t0+1
  lda sprite_layouts_count,x
  sta t2
  ldy #0
  ; oamIndex is a variable tracking how far you've written
  ; into shadow OAM (customarily at $0200-$02FF)
  ldx oamIndex
@loop:
  ; If you have the address of an array in a zero page pointer,
  ; you use the (d),y addressing mode and increase Y to go
  ; to the next byte.
  lda (t0),y
  iny
  ; etc.
  dec t2
  bne @loop
  stx oamIndex
  rts

some_other_method:
  ldx #2
  jsr draw_sprite



EDIT: Fixed a typo.


Last edited by tepples on Mon Apr 04, 2011 9:36 am, edited 1 time in total.

Top
 Profile  
 
 Post subject:
PostPosted: Thu Mar 31, 2011 6:11 pm 
Offline
User avatar

Joined: Wed Oct 15, 2008 11:50 am
Posts: 939
Yea, what Tepples said :D

I have added a wiki document about using pointer tables. I wrote it prior to seeing Tepples's reply so it uses different code, but there is more explanation.

Dang Tepples, you code quick :D


Top
 Profile  
 
 Post subject:
PostPosted: Thu Mar 31, 2011 7:34 pm 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10164
Location: Rio de Janeiro - Brazil
tepple's example is right. First you have to define the sprite data for all possible animation frames. Then you make a list of pointers to each of the frames, in order to give each of them an index. Finally, you make a function/subroutine that will receive a meta-sprite index and an object index and will render the requested frame for the requested object.

You can use registers X and Y to pass the indexes as parameters to the sprite drawing function. This function should add the meta-sprite coordinates to the object's coordinates (this is why the function needs to receive an object index) in order to find the final sprite coordinates, and, if those coordinates are within screen limits, write them to the OAM buffer (usually $0200-$02FF).


Top
 Profile  
 
 Post subject:
PostPosted: Thu Mar 31, 2011 9:41 pm 
Offline
User avatar

Joined: Thu Apr 23, 2009 11:21 pm
Posts: 805
Location: cypress, texas
tepples wrote:
It'd go a little something like this (untested):
Code:
hero_frame1:
  .db aY,    $80, $00, aX, aY,    $81, $00, aX+8
  .db aY+8,  $90, $00, aX, aY+8,  $91, $00, aX+8
  .db aY+16, $a0, $00, aX, aY+16, $a1, $00, aX+8
  .db aY+24, $b0, $00, aX, aY+24, $b1, $00, aX+8
hero_frame2:
  .db aY,    $82, $00, aX, aY,    $83, $00, aX+8
  .db aY+8,  $92, $00, aX, aY+8,  $93, $00, aX+8
  .db aY+16, $a2, $00, aX, aY+16, $a3, $00, aX+8
  .db aY+24, $b2, $00, aX, aY+24, $b3, $00, aX+8
hero_frame3:
  .db aY,    $84, $00, aX, aY,    $85, $00, aX+8
  .db aY+8,  $94, $00, aX, aY+8,  $95, $00, aX+8
  .db aY+16, $a4, $00, aX, aY+16, $a5, $00, aX+8
  .db aY+24, $b4, $00, aX, aY+24, $b5, $00, aX+8
hero_frame4:
  .db aY,    $86, $00, aX, aY,    $87, $00, aX+8
  .db aY+8,  $96, $00, aX, aY+8,  $97, $00, aX+8
  .db aY+16, $a6, $00, aX, aY+16, $a7, $00, aX+8
  .db aY+24, $b6, $00, aX, aY+24, $b7, $00, aX+8

; Operator < produces the low byte of an address
sprite_layouts_lo:
  .db <hero_frame1, <hero_frame2, <hero_frame3, <hero_frame4

; Operator > produces the high byte of an address
sprite_layouts_hi:
  .db >hero_frame1, >hero_frame2, >hero_frame3, >hero_frame4

; Number of hardware sprites in each layout
sprite_layouts_count:
  .db 8, 8, 8, 8

draw_sprite:
  ; t0-t2 are temporary zero page locations holding
  ; the address of a particular sprite layout and the
  ; number of sprites left to draw
  lda sprite_layouts_lo,x
  sta t0
  lda sprite_layouts_hi,x
  sta t0+1
  lda sprite_layouts_count,x
  sta t2
  ldy #0
  ; oamIndex is a variable tracking how far you've written
  ; into shadow OAM (customarily at $0200-$02FF)
  ldx oamIndex
@loop:
  ; If you have the address of an array in a zero page pointer,
  ; you use the (d),y addressing mode and increase Y to go
  ; to the next byte.
  lda (t0),y
  iny
  ; etc.
  dec t2
  bne loop
  stx oamIndex
  rts

some_other_method:
  ldx #2
  jsr draw_sprite


:mrgreen: Thank you tepples! :D And thank you qbradq for your work... haven't really thought about it yet, sorry, tired. And thank you tokumaru! This is the second time, i think, you have explained step by step the first guy's help and that helps me so much too! :D Tomorrow is going to be so much fun! :D Good night.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Apr 01, 2011 9:49 am 
Offline
User avatar

Joined: Thu Apr 23, 2009 11:21 pm
Posts: 805
Location: cypress, texas
tepples, this code rocks the house!! Thank you so much! :)


Top
 Profile  
 
 Post subject:
PostPosted: Mon Apr 04, 2011 9:20 am 
Offline
User avatar

Joined: Thu Apr 23, 2009 11:21 pm
Posts: 805
Location: cypress, texas
I get the error "daprg.asm(250): Branch out of range."

frome here:
Code:
      draw_sprite:
        ; t0-t2 are temporary zero page locations holding
        ; the address of a particular sprite layout and the
        ; number of sprites left to draw
        lda sprite_layouts_lo, x
        sta t0
        lda sprite_layouts_hi, x
        sta t0+1
        lda sprite_layouts_count, x
        sta t2
        ldy #0
        ; oamIndex is a variable tracking how far you've written
        ; into shadow OAM (customarily at $0200-$02FF)
        ldx oamIndex
      @loop:
        ; If you have the address of an array in a zero page pointer,
        ; you use the (d),y addressing mode and increase Y to go
        ; to the next byte.
        lda (t0), y
        iny
        ;ect.
        dec t2
        bne loop ;########(LINE NUMBER 250)
        stx oamIndex
        rts
       
       
       
       
        ; Set initial value of dx
        lda #$01
        sta dx
        rts

; Load palette into $3F00
load_palette:


So why is it out of range? The only help i could find was
in this thread
koitsu wrote:
Branch instructions range from +127 to -128. It's just a signed 8-bit number.


I don't understand though. :(


Top
 Profile  
 
 Post subject:
PostPosted: Mon Apr 04, 2011 9:36 am 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19334
Location: NE Indiana, USA (NTSC)
The problem is my fault. I partially rewrote the code to reflect an apparent coding style of not using the .proc statement of ca65. So I changed loop: to @loop: but not bne loop to bne @loop. I have edited the sample code.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Apr 04, 2011 11:53 am 
Offline
User avatar

Joined: Thu Apr 23, 2009 11:21 pm
Posts: 805
Location: cypress, texas
Ok, I didn't know if the local link needed an @ in
Code:
bne @loop
because with the @ asm6 builds the rom with out error; but, now, when running it, Nintendulator stops and says "Bad opcode, CPU locked" and VirtuaNES stops and says "Executed an undefined order." I thought this was brought on by adding the @ to loop up there... the asm6 README.TXT doesn't have an example of that code. So, thank you for helping me learn that it's proper to use an @ in that code. :) It's ok tepples :)
I'm still lost. It confuses me that asm6 would assemble a "bad opcode"? :?


Last edited by unregistered on Mon Apr 04, 2011 12:56 pm, edited 1 time in total.

Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 1389 posts ]  Go to page Previous  1, 2, 3, 4, 5, 6, 7 ... 93  Next

All times are UTC - 7 hours


Who is online

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