Как изменить положение спрайта с помощью сборки 65c816 для SNES?
Я пытаюсь изменить позицию своего спрайта, но не могу понять, как
Я часами искал ответы, но ни один из них не работает с ассемблером, который я использую: WLA-DX. Я чрезвычайно новичок в сборке 6502, так что прости меня, если моя логика действительно искажена. Я следовал учебному пособию по обучению georgjz на GitHub. Мой спрайт - это просто один цветной квадрат, а поддон - это поддон по умолчанию, который поставляется с 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
Я пытаюсь, по крайней мере, заставить спрайт переместиться вправо на 1 пиксель за кадр, но спрайт не движется вообще
================================================== =========================
Редактировать: я добавил код из комментария @Michael, и ничего не изменилось. Вот код, который я обновил:
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
и я добавил подпрограмму MoveSprite после CGRAMLoop
1 ответ
Я не вижу кода, который на самом деле изменит позицию вашего спрайта.
Но допустим, что у вас есть переменная zeropage, в которой вы храните текущую позицию X:
.define spriteX $00A0 ; I used address $A0 as an example. Just pick some address
; that you aren't already using for something else
И где-то во время инициализации вы даете ему некоторое начальное значение:
sep #$20
lda #$78
sta spriteX
Затем вы можете написать подпрограмму, которая увеличивает значение и записывает его в OAM:
MoveSprite:
php
sep #$20
stz $2102
stz $2103
inc spriteX
lda spriteX
sta $2104
lda #$68
sta $2104 ; This write is necessary even if you're not changing the Y position,
; because there's some internal latching going on in the PPU.
plp
rts
И тогда вы могли бы вызвать эту подпрограмму из вашего VBlank
обработчик прерываний.
Обратите внимание, что вам может понадобиться дополнительный счетчик, который будет увеличивать позицию только через каждый второй кадр (или любой другой интервал, который вам нравится); в противном случае спрайт будет прокручиваться довольно быстро.
Вам также нужно включить VBlank NMI для фактического запуска прерывания:
lda #$80
sta $4200 ; Enable VBlank NMI
jmp GameLoop ; all initialization is done