cool! totally understand!unregistered wrote:^ yesyesyall, sorry, I'm uncomfortable to meet with you.
8x16 and whatever else unreg wants to know
Moderator: Moderators
-
- Posts: 28
- Joined: Sat Mar 05, 2011 3:17 pm
- Location: Houston, Texas
-
- Posts: 1318
- Joined: Thu Apr 23, 2009 11:21 pm
- Location: cypress, texas
How do you make the coordinates relative to the position of the object/character being drawn?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.
Code: Select all
aY .byte 10
aX .byte 20
.db aY, $80, $00, aX, aY, $81, $00, aX +1
Code: Select all
aY .equ 10
aX .equ 20
.db aY,$80,$00, aX, aY, $81, $00, aX +1
Really happy to have found this, thank you.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.
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.
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.
-
- Posts: 1318
- Joined: Thu Apr 23, 2009 11:21 pm
- 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?
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?
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
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
-
- Posts: 1318
- Joined: Thu Apr 23, 2009 11:21 pm
- Location: cypress, texas
How do you point it to the correct list? So far I have thisunregistered 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.
Code: Select all
;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
It'd go a little something like this (untested):
EDIT: Fixed a typo.
Code: Select all
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.
Yea, what Tepples said
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
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
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).
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).
-
- Posts: 1318
- Joined: Thu Apr 23, 2009 11:21 pm
- Location: cypress, texas
Thank you tepples! 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! Tomorrow is going to be so much fun! Good night.tepples wrote:It'd go a little something like this (untested):Code: Select all
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
-
- Posts: 1318
- Joined: Thu Apr 23, 2009 11:21 pm
- Location: cypress, texas
-
- Posts: 1318
- Joined: Thu Apr 23, 2009 11:21 pm
- Location: cypress, texas
I get the error "daprg.asm(250): Branch out of range."
frome here:
So why is it out of range? The only help i could find was
in this thread
frome here:
Code: Select all
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:
in this thread
I don't understand though.koitsu wrote:Branch instructions range from +127 to -128. It's just a signed 8-bit number.
-
- Posts: 1318
- Joined: Thu Apr 23, 2009 11:21 pm
- Location: cypress, texas
Ok, I didn't know if the local link needed an @ in 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"?
Code: Select all
bne @loop
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.