This page is a mirror of Tepples' nesdev forum mirror (URL TBD).
Last updated on Oct-18-2019 Download

The Background Saga

The Background Saga
by on (#58286)
Hello,
I was the entire day on the IRC with people helping me to improve my code(adding DMA, NMI..., special thanks for jero32 and jsr), but now I want to have a background(thing that is very important to a game), then I've got a code like this:
Code:
   .inesprg 1   ; 1 bank of code
   .ineschr 1   ; 1 bank of spr/bkg data
   .inesmir 1   ; something always 1
   .inesmap 0   ; we use mapper 0

   .bank 0   ; bank 0 - our place for code.
   .org $0000
Sprite1_X   .db 50       ; a X position for our sprite, start at 20
Sprite1_Y   .db 20       ; a Y position for our sprite, start at 20
Sprite2_X   .db 50       ; a X position for our sprite, start at 20
Sprite2_Y   .db 20       ; a Y position for our sprite, start at 20
   .org $8000  ; code starts at $8000
   
Start: 
   lda #%10001000  ; do the setup of PPU
   sta $2000       ; that we

   ldx #$00    ; clear X

   lda #$3F    ; have $2006 tell
   sta $2006   ; $2007 to start
   lda #$00    ; at $3F00 (pallete).
   sta $2006

loadpal:                ; this is a freaky loop
   lda tilepal, x  ; that gives 32 numbers
   sta $2007       ; to $2007, ending when
   inx             ; X is 32, meaning we
   cpx #32         ; are done.
   bne loadpal     ; if X isn't =32, goto "loadpal:" line.

   lda #$20
   sta $2006 ; give $2006 both parts of address $2020.
   sta $2006
   ldx #$00

   loadNames:
   lda ourMap, X ; load A with a byte from address (ourMap + X)
   inx
   sta $2007
   cpx #64 ; map in previous section 64 bytes long
   bne loadNames ; if not all 64 done, loop and do some more

waitblank1:         
   lda $2002  ; these 3 lines wait for VBlank, this loop will actually miss VBlank
   bpl waitblank1 ; alot, in a later Day, I'll give a better way
   txa
clrmem:
   sta $000,x
   sta $100,x
   sta $200,x
   sta $300,x
   sta $400,x
   sta $500,x
   sta $600,x
   sta $700,x  ; Remove this if you're storing reset-persistent data
   inx
   bne clrmem
   
waitblank2:         
   lda $2002  ; these 3 lines wait for VBlank, this loop will actually miss VBlank
   bpl waitblank2 ; alot, in a later Day, I'll give a better way
   lda #%00011110
   sta $2001
   
loop:
   jmp loop
   
infinite:  ; a label to start our infinite loop
nmi:

   ; Load Sprite1
   lda Sprite1_Y
   sta $0300
   lda #$11
   sta $0301
   lda #$00
   sta $0302
   lda Sprite1_X
   sta $0303
   
   ; Load Sprite2
   lda Sprite2_Y
   sta $0304
   lda #$12
   sta $0305
   lda #$00
   sta $0306
   lda Sprite2_X
   sta $0307
   
   lda #$01   ; these
   sta $4016  ; lines
   lda #$00   ; setup/strobe the
   sta $4016  ; keypad.

   lda $4016  ; load Abutton Status ; note that whatever we ain't interested
   lda $4016  ; load Bbutton Status ; in we just load so it'll go to the next one.
   lda $4016  ; load Select button status
   lda $4016  ; load Start button status
   lda $4016  ; load UP button status
   and #1     ; AND status with #1
   bne UPKEYdown  ; for some reason (not gonna reveal yet), need to use NotEquals
   ;with ANDs. So it'll jump (branch) if key was down.
   
   lda $4016  ; load DOWN button status
   and #1     ; AND status with #1
   bne DOWNKEYdown

   lda $4016  ; load LEFT button status
   and #1     ; AND status with #1
   bne LEFTKEYdown

   lda $4016  ; load RIGHT button status
   and #1     ; AND status with #1
   bne RIGHTKEYdown
   jmp NOTHINGdown  ; if nothing was down, we just jump (no check for conditions)
   ; down past the rest of everything.

UPKEYdown:
   lda Sprite1_Y ; load A with Y position
   sbc #1  ; subtract 1 from A. Only can do math on A register. SBC (Subtract with Borrow)
   sta Sprite1_Y ; store back to memory
   lda Sprite2_Y ; load A with Y position
   sbc #1  ; subtract 1 from A. Only can do math on A register. SBC (Subtract with Borrow)
   sta Sprite2_Y ; store back to memory
   jmp NOTHINGdown  ; jump over the rest of the handling code.

DOWNKEYdown:
   lda Sprite1_Y
   adc #1  ; add 1 to A. ADC (Add with Carry)((to A register))
   sta Sprite1_Y
   jmp NOTHINGdown ; jump over the rest of handling code.

LEFTKEYdown:
   lda Sprite1_X
   sbc #1 
   sta Sprite1_X
   jmp NOTHINGdown
;the left and right handling code does the same as UP and Down except.. well.. with
; left and right. :)

RIGHTKEYdown:
   lda Sprite1_X
   adc #1
   sta Sprite1_X
   ; don't need to jump to NOTHINGdown, it's right below. Saved several bytes of
   ; PRG-Bank space! :)
   
NOTHINGdown:
   lda #$03
   sta $4014
   rti

tilepal:
   .incbin "our.pal" ; include and label our pallete
   
ourMap:
   .incbin "our.map" ; assuming our.map is the binary map file.
   .bank 1   ; following goes in bank 1
   .org $FFFA  ; start at $FFFA
   .dw nmi    ; dw stands for Define Word and we give 0 as address for NMI routine
   .dw Start ; give address of start of our code for execution on reset of NES.
   .dw 0   ; give 0 for address of VBlank interrupt handler, we tell PPU not to
   ; make an interrupt for VBlank.
   
   .bank 2   ; switch to bank 2
   .org $0000  ; start at $0000
   .incbin "our.bkg"  ; empty background first
   .incbin "our.spr"  ; our sprite pic data

And here are all the files used:

But when I emulate this I got a monochome background(because I don't have a pallete for it):
Image

Then I want to know some simple things:
  • What is the simplest way to define a pallete for the background?
  • How can I arrange the background to have a smile(of 4 tiles) that isn't tiled(repeated line by line)?


Best Regards,
Nathan Paulino Campos

by on (#58318)
You're missing "ourMap.map" attached,but it's fine.(I used my own map)
Quote:
What is the simplest way to define a pallete for the background?

If I understand you correctly,You need to load Atribute table.You have to load it after map into 2007.If I'm not wrong then Atribute table should be 40 bytes long.
1 Byte is numer of palete used for 2x2 square.

by on (#58326)
The attribute table is 64 bytes long ($40 is 64 in hex, so that could be why you said 40 - in the future, please be careful to indicate the base of the values). Each byte covers a 32x32-pixel area, and each 2 bits inside that byte selects palettes %00 (0) through %11 (3) for each 16x16-pixel area.

If you want the whole background to use the same palette it's easy, but if you want to configure each 16x16 block individually it's better to use a specific software, such as this, because doing it by hand can be very tedious.

by on (#58328)
tokumaru wrote:
The attribute table is 64 bytes long ($40 is 64 in hex, so that could be why you said 40 - in the future, please be careful to indicate the base of the values).

Ok..,forgot to say it's in HEX :oops:
Hmm,nathanpc,in order to use Name.exe you need to create batch file.
You need to specify 3 thing:
-chr file
-Palete file
-And map file.
Example:
Code:
name our.chr our.pal our.map

Note that "neme" must be first.
("our.chr" is name for background,so in your case it's should be"our.bkg")

by on (#58350)
I've done all correct, used name with my map file(chr one) and the pallete file(bkg.pal).

Now when I emulate, I got all organized(as I've done in name, but it's still monochrome(background only).

Remember that I haven't changed anything on the code, just compiled it with the new files

by on (#58358)
Um,if you really dodn't changed a thing,then you still didn't loaded Atribute table.You need to load more than 64 bytes from map file.Also first palette for backgorund is in monochrome,that's why.
And if that won't work then please upload your map file.

by on (#58377)
I can't understand what you're saying, but here are the files:


Best Regards.

by on (#58388)
My english is really soo poor? :(
Uh...anyway...It's just like I said,you didn't loaded whole file.When you're creating a map file with "name.exe",then map file will have 3C0 bytes to load(HEX)as actual name table.The rest(40 bytes in HEX) is atributes.
You need to delete this
Code:
   loadNames:
   lda ourMap, X ; load A with a byte from address (ourMap + X)
   inx
   sta $2007
   cpx #64 ; map in previous section 64 bytes long
   bne loadNames ; if not all 64 done, loop and do some more

And insert This instead:
Code:
Map_Load:
  LDA $2002             ; read PPU status to reset the high/low latch
  LDA #$20
  STA $2006             ; write the high byte of $2000 address
  LDA #$00
  STA $2006             ; write the low byte of $2000 address
  lda #low(ourMap)
  sta addrLO
  Lda #high(ourMap)              ; start out at 0
  sta addrHI

  ldx #4
  ldy #0

Map_Load_loop:
  LDA [addrLO], y     ; load data from address (background + the value in x)
  STA $2007             ; write to PPU
  INy                   ; X = X + 1
  BNE Map_Load_loop  ; Branch to LoadBackgroundLoop if compare was Not Equal to zero
  inc addrHI
  dex
  bne Map_Load_loop

Don't forget to make make variable's for indirect addressing:
addrLO and addrHI.

by on (#58394)
Ok, but what will be the addrLO and addrHI .db values?

by on (#58396)
Umm,Values is automatically appended to these variables.
you don't have to do anything manually.

by on (#58413)
Hmm, but I still got this:
Code:
NES Assembler (v2.0)

#[1]   OUR.ASM
   44  00:8035                    sta addrLO
       Undefined symbol in operand field!
   46  00:803A                    sta addrHI
       Undefined symbol in operand field!
   52  00:8041                    LDA [addrLO], y     ; load data from address (
background + the value in x)
       Undefined symbol in operand field!
   56  00:8049                    inc addrHI
       Undefined symbol in operand field!
# 4 ERROR(s)

by on (#58414)
Did you declare these variables? The assembler won't know what "addrLO" and "addrHI" mean unless you tell it. You can put in the beginning of your file something like this:

Code:
addrLO = $10
addrHI = $11

Make sure to not use addresses that are already in use by other variables.

by on (#58416)
Muito obrigado amigo. ;)
E é muito bom ver que há outros brasileros na área. :D

PS: Sou do Espirito Santo

by on (#58418)
Hehe, OK! =)

É bom mesmo ver outros brasileiros interessados nessa área. Tentarei ajudar sempre que puder! Só vamos evitar falar muito português fora do lugar porque não é muito educado com quem não entende... Mas no fórum internacional está liberado!

Translation: It is indeed good to see other brazilians interested in this area. I'll try to help whenever I can! Let's just avoid using too much portuguese out of place because it's not very polite to those who don't understand it... It's OK in the international forum though!

by on (#58419)
It's all right ;)