I am trying to modify my sprite's position, but I can't figure out how to
I have spent hours searching for answers, but none of which work with the assembler I am using: WLA-DX. I am extremely new to 6502 assembly, so forgive me if my logic is really skewed. I was following the tutorial on georgjz's tutorial on GitHub. My sprite is just a single colored square and the pallet is the default pallet that comes with yy-chr
Header.inc
;==LoRom== ; We'll get to HiRom some other time.
.MEMORYMAP ; Begin describing the system architecture.
SLOTSIZE $8000 ; The slot is $8000 bytes in size. More details on slots later.
DEFAULTSLOT 0
SLOT 0 $8000 ; Defines Slot 0's starting address.
.ENDME ; End MemoryMap definition
.ROMBANKSIZE $8000 ; Every ROM bank is 32 KBytes in size
.ROMBANKS 8 ; 2 Mbits - Tell WLA we want to use 8 ROM Banks
.SNESHEADER
ID "SNES" ; 1-4 letter string, just leave it as "SNES"
NAME "SNES Testing " ; Program Title - can't be over 21 bytes,
; "123456789012345678901" ; use spaces for unused bytes of the name.
SLOWROM
LOROM
CARTRIDGETYPE $00 ; $00 = ROM only, see WLA documentation for others
ROMSIZE $08 ; $08 = 2 Mbits, see WLA doc for more..
SRAMSIZE $00 ; No SRAM see WLA doc for more..
COUNTRY $01 ; $01 = U.S. $00 = Japan $02 = Australia, Europe, Oceania and Asia $03 = Sweden $04 = Finland $05 = Denmark $06 = France $07 = Holland $08 = Spain $09 = Germany, Austria and Switzerland $0A = Italy $0B = Hong Kong and China $0C = Indonesia $0D = Korea
LICENSEECODE $00 ; Just use $00
VERSION $00 ; $00 = 1.00, $01 = 1.01, etc.
.ENDSNES
.SNESNATIVEVECTOR ; Define Native Mode interrupt vector table
COP EmptyHandler
BRK EmptyHandler
ABORT EmptyHandler
NMI VBlank
IRQ EmptyHandler
.ENDNATIVEVECTOR
.SNESEMUVECTOR ; Define Emulation Mode interrupt vector table
COP EmptyHandler
ABORT EmptyHandler
NMI EmptyHandler
RESET Start ; where execution starts
IRQBRK EmptyHandler
.ENDEMUVECTOR
.BANK 0 SLOT 0 ; Defines the ROM bank and the slot it is inserted in memory.
.ORG 0 ; .ORG 0 is really $8000, because the slot starts at $8000
.SECTION "EmptyVectors" SEMIFREE
EmptyHandler:
rti
.ENDS
.EMPTYFILL $00 ; fill unused areas with $00, opcode for BRK.
; BRK will crash the snes if executed.
Snes_Init.asm
.MACRO Snes_Init
sei ; Disabled interrupts
clc ; clear carry to switch to native mode
xce ; Xchange carry & emulation bit. native mode
rep #$18 ; Binary mode (decimal mode off), X/Y 16 bit
ldx #$1FFF ; set stack to $1FFF
txs
jsr Init
.ENDM
.bank 0
.section "Snes_Init" SEMIFREE
Init:
sep #$20 ; X,Y,A are 8 bit numbers
lda #$8F ; screen off, full brightness
sta $2100 ; brightness + screen enable register
stz $2101 ; Sprite register (size + address in VRAM)
stz $2102 ; Sprite registers (address of sprite memory [OAM])
stz $2103 ; "" ""
stz $2105 ; Mode 0, = Graphic mode register
stz $2106 ; noplanes, no mosaic, = Mosaic register
stz $2107 ; Plane 0 map VRAM location
stz $2108 ; Plane 1 map VRAM location
stz $2109 ; Plane 2 map VRAM location
stz $210A ; Plane 3 map VRAM location
stz $210B ; Plane 0+1 Tile data location
stz $210C ; Plane 2+3 Tile data location
stz $210D ; Plane 0 scroll x (first 8 bits)
stz $210D ; Plane 0 scroll x (last 3 bits) #$0 - #$07ff
lda #$FF ; The top pixel drawn on the screen isn't the top one in the tilemap, it's the one above that.
sta $210E ; Plane 0 scroll y (first 8 bits)
sta $2110 ; Plane 1 scroll y (first 8 bits)
sta $2112 ; Plane 2 scroll y (first 8 bits)
sta $2114 ; Plane 3 scroll y (first 8 bits)
lda #$07 ; Since this could get quite annoying, it's better to edit the scrolling registers to fix this.
sta $210E ; Plane 0 scroll y (last 3 bits) #$0 - #$07ff
sta $2110 ; Plane 1 scroll y (last 3 bits) #$0 - #$07ff
sta $2112 ; Plane 2 scroll y (last 3 bits) #$0 - #$07ff
sta $2114 ; Plane 3 scroll y (last 3 bits) #$0 - #$07ff
stz $210F ; Plane 1 scroll x (first 8 bits)
stz $210F ; Plane 1 scroll x (last 3 bits) #$0 - #$07ff
stz $2111 ; Plane 2 scroll x (first 8 bits)
stz $2111 ; Plane 2 scroll x (last 3 bits) #$0 - #$07ff
stz $2113 ; Plane 3 scroll x (first 8 bits)
stz $2113 ; Plane 3 scroll x (last 3 bits) #$0 - #$07ff
lda #$80 ; increase VRAM address after writing to $2119
sta $2115 ; VRAM address increment register
stz $2116 ; VRAM address low
stz $2117 ; VRAM address high
stz $211A ; Initial Mode 7 setting register
stz $211B ; Mode 7 matrix parameter A register (low)
lda #$01
sta $211B ; Mode 7 matrix parameter A register (high)
stz $211C ; Mode 7 matrix parameter B register (low)
stz $211C ; Mode 7 matrix parameter B register (high)
stz $211D ; Mode 7 matrix parameter C register (low)
stz $211D ; Mode 7 matrix parameter C register (high)
stz $211E ; Mode 7 matrix parameter D register (low)
sta $211E ; Mode 7 matrix parameter D register (high)
stz $211F ; Mode 7 center position X register (low)
stz $211F ; Mode 7 center position X register (high)
stz $2120 ; Mode 7 center position Y register (low)
stz $2120 ; Mode 7 center position Y register (high)
stz $2121 ; Color number register ($0-ff)
stz $2123 ; BG1 & BG2 Window mask setting register
stz $2124 ; BG3 & BG4 Window mask setting register
stz $2125 ; OBJ & Color Window mask setting register
stz $2126 ; Window 1 left position register
stz $2127 ; Window 2 left position register
stz $2128 ; Window 3 left position register
stz $2129 ; Window 4 left position register
stz $212A ; BG1, BG2, BG3, BG4 Window Logic register
stz $212B ; OBJ, Color Window Logic Register (or,and,xor,xnor)
sta $212C ; Main Screen designation (planes, sprites enable)
stz $212D ; Sub Screen designation
stz $212E ; Window mask for Main Screen
stz $212F ; Window mask for Sub Screen
lda #$30
sta $2130 ; Color addition & screen addition init setting
stz $2131 ; Add/Sub sub designation for screen, sprite, color
lda #$E0
sta $2132 ; color data for addition/subtraction
stz $2133 ; Screen setting (interlace x,y/enable SFX data)
stz $4200 ; Enable V-blank, interrupt, Joypad register
lda #$FF
sta $4201 ; Programmable I/O port
stz $4202 ; Multiplicand A
stz $4203 ; Multiplier B
stz $4204 ; Multiplier C
stz $4205 ; Multiplicand C
stz $4206 ; Divisor B
stz $4207 ; Horizontal Count Timer
stz $4208 ; Horizontal Count Timer MSB (most significant bit)
stz $4209 ; Vertical Count Timer
stz $420A ; Vertical Count Timer MSB
stz $420B ; General DMA enable (bits 0-7)
stz $420C ; Horizontal DMA (HDMA) enable (bits 0-7)
stz $420D ; Access cycle designation (slow/fast rom)
cli ; Enable interrupts
rts
.ends
Testing.asm
.include "header.inc"
.include "Snes_Init.asm"
SpriteData: .incbin "sprite.sprite"
ColorData: .incbin "sprite.pal"
VBlank: ; Needed to satisfy interrupt definition in "Header.inc"
RTI
Start:
Snes_Init
sei ; disable interrupts
clc ; clear the carry flag
xce ; switch the 65816 to native (16-bit mode)
lda #$8f ; force v-blanking
sta $2100
stz $4200 ; disable NMI
; transfer VRAM data
stz $2116 ; set the VRAM address to $0000
stz $2117
lda #$80
sta $2115 ; increment VRAM address by 1 when writing to $2119
ldx #$00 ; set register X to zero, we will use X as a loop counter and offset
VRAMLoop:
.16BIT
lda SpriteData, X ; get bitplane 0/2 byte from the sprite data
sta $2118 ; write the byte in A to VRAM
sta $0000 ; write the byte in A to VRAM
inx ; increment counter/offset
lda SpriteData, X ; get bitplane 1/3 byte from the sprite data
sta $2119 ; write the byte in A to VRAM
sta $0000 ; write the byte in A to VRAM
inx ; increment counter/offset
cpx #$20 ; check whether we have written $04 * $20 : $80 bytes to VRAM (four sprites)
bcc VRAMLoop ; if X is smaller than $80, continue the loop
; transfer CGRAM data
lda #$80
sta $2121 ; set CGRAM address to $80
ldx #$00 ; set X to zero, use it as loop counter and offset
CGRAMLoop:
lda ColorData, X ; get the color low byte
sta $2122 ; store it in CGRAM
inx ; increase counter/offset
lda ColorData, X ; get the color high byte
sta $2122 ; store it in CGRAM
inx ; increase counter/offset
cpx #$20 ; check whether 32/$20 bytes were transfered
bcc CGRAMLoop ; if not, continue loop
stz $2102 ; set the OAM address to ...
stz $2103 ; ...at $0000
; OAM data for first sprite
lda #$78 ; horizontal position of first sprite
sta $2104
lda #$68 ; vertical position of first sprite
sta $2104
lda #$00 ; name of first sprite
sta $2104
lda #$00 ; no flip, prio 0, palette 0
sta $2104
; make Objects visible
lda #$10
sta $212C
; release forced blanking, set screen to full brightness
lda #$0f
sta $2100
jmp GameLoop ; all initialization is done
GameLoop:
wai ; wait for NMI / V-Blank
jmp GameLoop
I am trying to at least get the sprite to move to the right 1 pixel per frame, but the sprite isn't moving at all
===========================================================================
Edit: I added the code from the comment by @Michael, and nothing has changed. Here is the code that I updated:
Snes_Init.asm
.define SpriteX $00A0
Init:
sep #$20 ; X,Y,A are 8 bit numbers
lda #$78
sta SpriteX
;Initialization code
rts
.ends
Testing.asm
VBlank: ; Needed to satisfy interrupt definition in "Header.inc"
jsr MoveSprite
RTI
; Code
CGRAMLoop:
;More code
; OAM data for first sprite
lda SpriteX ; horizontal position of first sprite
sta $2104
lda #$68 ; vertical position of first sprite
sta $2104
lda #$00 ; name of first sprite
sta $2104
lda #$00 ; no flip, prio 0, palette 0
sta $2104
;Even more code
and I added the MoveSprite subroutine after CGRAMLoop
I don't see any code that actually will change the position of your sprite.
But let's say that you have a zeropage variable where you store the current X position:
And somewhere during initialization you give it some initial value:
Then you could write a subroutine that increments the value and writes it to OAM:
And then you could call that subroutine from your
VBlank
interrupt handler.Note that you may want an additional counter to only increment the position every other frame (or whatever interval you like); otherwise the sprite will scroll by fairly quickly.
You also need to enable VBlank NMI for the interrupt to actually be triggered: