Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- .inesprg 1 ; 1x 16KB PRG code
- .ineschr 1 ; 1x 8KB CHR data
- .inesmap 0 ; mapper 0 = NROM, no bank swapping
- .inesmir 1 ; background mirroring
- ;;;;;;;;;;;;;;;
- ;; DECLARE SOME VARIABLES HERE
- .rsset $0000 ;;start variables at ram location 0
- gamestate .rs 1 ; .rs 1 means reserve one byte of space
- ballx .rs 1 ; ball horizontal position
- bally .rs 1 ; ball vertical position
- ballup .rs 1 ; 1 = ball moving up
- balldown .rs 1 ; 1 = ball moving down
- ballleft .rs 1 ; 1 = ball moving left
- ballright .rs 1 ; 1 = ball moving right
- ballspeedx .rs 1 ; ball horizontal speed per frame
- ballspeedy .rs 1 ; ball vertical speed per frame
- paddle1y .rs 1 ; paddle vertical position
- paddle2y .rs 1 ; paddle vertical position
- paddle1y2 .rs 1 ; paddle vertical position
- paddle2y2 .rs 1 ; paddle vertical position
- buttons1 .rs 1 ; player 1 gamepad buttons, one bit per button
- buttons2 .rs 1 ; player 2 gamepad buttons, one bit per button
- scoreOnes .rs 1 ; byte for each digit in the decimal score
- scoreTens .rs 1
- scoreHundreds .rs 1
- scoreOnes2 .rs 1 ; byte for each digit in the decimal score
- scoreTens2 .rs 1
- scoreHundreds2 .rs 1
- ;; DECLARE SOME CONSTANTS HERE
- STATETITLE = $00 ; displaying title screen
- STATEPLAYING = $01 ; move paddles/ball, check for collisions
- STATEGAMEOVER = $02 ; displaying game over screen
- RIGHTWALL = $F4 ; when ball reaches one of these, do something
- TOPWALL = $20
- BOTTOMWALL = $E0
- LEFTWALL = $04
- PADDLE1X = $08 ; horizontal position for paddles, doesnt move
- PADDLE2X = $F0
- PS1 = $01 ; paddle vertical speed per frame
- PS2 = $01 ; paddle vertical speed per frame
- ;;;;;;;;;;;;;;;;;;
- .bank 0
- .org $C000
- RESET:
- SEI ; disable IRQs
- CLD ; disable decimal mode
- LDX #$40
- STX $4017 ; disable APU frame IRQ
- LDX #$FF
- TXS ; Set up stack
- INX ; now X = 0
- STX $2000 ; disable NMI
- STX $2001 ; disable rendering
- STX $4010 ; disable DMC IRQs
- vblankwait1: ; First wait for vblank to make sure PPU is ready
- BIT $2002
- BPL vblankwait1
- clrmem:
- LDA #$00
- STA $0000, x
- STA $0100, x
- STA $0300, x
- STA $0400, x
- STA $0500, x
- STA $0600, x
- STA $0700, x
- LDA #$FE
- STA $0200, x
- INX
- BNE clrmem
- vblankwait2: ; Second wait for vblank, PPU is ready after this
- BIT $2002
- BPL vblankwait2
- LoadPalettes:
- LDA $2002 ; read PPU status to reset the high/low latch
- LDA #$3F
- STA $2006 ; write the high byte of $3F00 address
- LDA #$00
- STA $2006 ; write the low byte of $3F00 address
- LDX #$00 ; start out at 0
- LoadPalettesLoop:
- LDA palette, x ; load data from address (palette + the value in x)
- ; 1st time through loop it will load palette+0
- ; 2nd time through loop it will load palette+1
- ; 3rd time through loop it will load palette+2
- ; etc
- STA $2007 ; write to PPU
- INX ; X = X + 1
- CPX #$20 ; Compare X to hex $10, decimal 16 - copying 16 bytes = 4 sprites
- BNE LoadPalettesLoop ; Branch to LoadPalettesLoop if compare was Not Equal to zero
- ; if compare was equal to 32, keep going down
- ;;;Set some initial ball stats
- LDA #$01
- STA balldown
- STA ballright
- LDA #$00
- STA ballup
- STA ballleft
- LDA #$50
- STA bally
- LDA #$80
- STA ballx
- LDA #$06
- STA ballspeedx
- STA ballspeedy
- LDA #$50
- STA paddle1y
- STA paddle2y
- LDA #$58
- STA paddle1y2
- STA paddle2y2
- ;;;Set initial score value
- LDA #$00
- STA scoreOnes
- STA scoreTens
- STA scoreHundreds
- STA scoreOnes2
- STA scoreTens2
- STA scoreHundreds2
- ;;:Set starting game state
- LDA #STATETITLE
- STA gamestate
- LDA #%10010000 ; enable NMI, sprites from Pattern Table 0, background from Pattern Table 1
- STA $2000
- LDA #%00011110 ; enable sprites, enable background, no clipping on left side
- STA $2001
- Forever:
- JMP Forever ;jump back to Forever, infinite loop, waiting for NMI
- NMI:
- LDA #$00
- STA $2003 ; set the low byte (00) of the RAM address
- LDA #$02
- STA $4014 ; set the high byte (02) of the RAM address, start the transfer
- JSR DrawScore
- JSR DrawScore2
- ;;This is the PPU clean up section, so rendering the next frame starts properly.
- LDA #%10010000 ; enable NMI, sprites from Pattern Table 0, background from Pattern Table 1
- STA $2000
- LDA #%00011110 ; enable sprites, enable background, no clipping on left side
- STA $2001
- LDA #$00 ;;tell the ppu there is no background scrolling
- STA $2005
- STA $2005
- ;;;all graphics updates done by here, run game engine
- JSR ReadController1 ;;get the current button data for player 1
- JSR ReadController2 ;;get the current button data for player 2
- GameEngine:
- LDA gamestate
- CMP #STATETITLE
- BEQ EngineTitle ;;game is displaying title screen
- LDA gamestate
- CMP #STATEGAMEOVER
- BEQ EngineGameOver ;;game is displaying ending screen
- LDA gamestate
- CMP #STATEPLAYING
- BEQ EnginePlaying ;;game is playing
- GameEngineDone:
- JSR UpdateSprites ;;set ball/paddle sprites from positions
- JSR MovePaddle1 ;;get the current button data for player 1
- JSR MovePaddle2 ;;get the current button data for player 2
- JSR CheckPaddleCollision
- RTI ; return from interrupt
- ;;;;;;;;
- EngineTitle:
- LDA buttons1
- AND #%00010000
- BEQ .return
- LDA #STATEPLAYING
- STA gamestate
- JMP EnginePlaying
- .return
- JMP GameEngine
- ;;;;;;;;;
- EngineGameOver:
- LDA buttons1
- AND #%00010000
- BEQ .return1
- LDA #STATEPLAYING
- STA gamestate
- LDA #$00
- STA scoreOnes
- STA scoreTens
- STA scoreHundreds
- STA scoreOnes2
- STA scoreTens2
- STA scoreHundreds2
- JMP EnginePlaying
- .return1
- JMP GameEngine
- ;;;;;;;;;;;
- EnginePlaying:
- MoveBallRight:
- LDA ballright
- BEQ MoveBallRightDone ;;if ballright=0, skip this section
- LDA ballx
- CLC
- ADC ballspeedx ;;ballx position = ballx + ballspeedx
- STA ballx
- LDA ballx
- CMP #RIGHTWALL
- BCC MoveBallRightDone ;;if ball x < right wall, still on screen, skip next section
- LDA #$00
- STA ballright
- LDA #$01
- STA ballleft ;;bounce, ball now moving left
- ;;in real game, give point to player 1, reset ball
- jsr IncrementScore1
- MoveBallRightDone:
- MoveBallLeft:
- LDA ballleft
- BEQ MoveBallLeftDone ;;if ballleft=0, skip this section
- LDA ballx
- SEC
- SBC ballspeedx ;;ballx position = ballx - ballspeedx
- STA ballx
- LDA ballx
- CMP #LEFTWALL
- BCS MoveBallLeftDone ;;if ball x > left wall, still on screen, skip next section
- LDA #$01
- STA ballright
- LDA #$00
- STA ballleft ;;bounce, ball now moving right
- ;;in real game, give point to player 2, reset ball
- jsr IncrementScore2
- MoveBallLeftDone:
- MoveBallUp:
- LDA ballup
- BEQ MoveBallUpDone ;;if ballup=0, skip this section
- LDA bally
- SEC
- SBC ballspeedy ;;bally position = bally - ballspeedy
- STA bally
- LDA bally
- CMP #TOPWALL
- BCS MoveBallUpDone ;;if ball y > top wall, still on screen, skip next section
- LDA #$01
- STA balldown
- LDA #$00
- STA ballup ;;bounce, ball now moving down
- MoveBallUpDone:
- MoveBallDown:
- LDA balldown
- BEQ MoveBallDownDone ;;if ballup=0, skip this section
- LDA bally
- CLC
- ADC ballspeedy ;;bally position = bally + ballspeedy
- STA bally
- LDA bally
- CMP #BOTTOMWALL
- BCC MoveBallDownDone ;;if ball y < bottom wall, still on screen, skip next section
- LDA #$00
- STA balldown
- LDA #$01
- STA ballup ;;bounce, ball now moving down
- MoveBallDownDone:
- JMP GameEngineDone
- MovePaddle1:
- lda buttons1 ;load the current button state for controller1
- and #%00000100 ;isolate the bit representing "up", by clearing all the other bits
- beq ReadDownDone ;if the result was 0, then the "up" bit was clear (thus not pressed), so skip the following code
- ;...
- LDA $0204 ; load sprite 2 position
- CLC ; make sure carry flag is set
- ADC #PS1 ; A = A - 1
- STA $0204 ; save sprite 2 position
- LDA $0204
- STA paddle1y
- LDA $020C ; load sprite 2 position
- CLC ; make sure carry flag is set
- ADC #PS1 ; A = A - 1
- STA $020C ; save sprite 2 position
- LDA $020C
- STA paddle1y2
- LDA paddle1y2
- CMP #BOTTOMWALL
- BCC ReadDownDone
- SEC ; make sure carry flag is set
- SBC #$01 ; A = A - 1
- STA paddle1y2
- LDA paddle1y
- SEC ; make sure carry flag is set
- SBC #$01 ; A = A - 1
- STA paddle1y
- ; LDA paddle1y
- ; SEC
- ; SBC PS1 ;;bally position = bally - ballspeedy
- ; STA paddle1y
- ;
- ; LDA paddle1y
- ; CMP #TOPWALL
- ; BCS ReadDownDone ;;if ball y > top wall, still on screen, skip next section
- ; LDA #$01
- ; STA paddle1down
- ; LDA #$00
- ; STA paddle1down ;;bounce, ball now moving down
- ReadDownDone:
- lda buttons1 ;load the current button state for controller1
- and #%00001000 ;isolate the bit representing "up", by clearing all the other bits
- beq ReadUpDone ;if the result was 0, then the "up" bit was clear (thus not pressed), so skip the following code
- ;...
- ; LDA $4016
- ; CMP #%00001000
- ; BNE ReadUpDone
- LDA $0204 ; load sprite 2 position
- SEC ; make sure carry flag is set
- SBC #PS1 ; A = A - 1
- STA $0204 ; save sprite 2 position
- LDA $0204
- STA paddle1y
- LDA $020C ; load sprite 2 position
- SEC ; make sure carry flag is set
- SBC #PS1 ; A = A - 1
- STA $020C ; save sprite 2 position
- LDA $020C
- STA paddle1y2
- LDA paddle1y
- CMP #TOPWALL
- BCS ReadUpDone
- CLC ; make sure carry flag is set
- ADC #$01 ; A = A - 1
- STA paddle1y
- LDA paddle1y2
- CLC ; make sure carry flag is set
- ADC #$01 ; A = A - 1
- STA paddle1y2
- ; LDA paddle1y
- ; SEC
- ; SBC PS1 ;;bally position = bally - ballspeedy
- ; STA paddle1y
- ;
- ; LDA paddle1y
- ; CMP #TOPWALL
- ; BCS ReadUpDone ;;if ball y > top wall, still on screen, skip next section
- ; LDA #$01
- ; STA paddle1down
- ; LDA #$00
- ; STA paddle1up ;;bounce, ball now moving down
- ReadUpDone:
- RTS
- MovePaddle2:
- lda buttons2 ;load the current button state for controller1
- and #%00000100 ;isolate the bit representing "up", by clearing all the other bits
- beq MovePaddleDownDone ;if the result was 0, then the "up" bit was clear (thus not pressed), so skip the following code
- ;...
- LDA $0208 ; load sprite 2 position
- CLC ; make sure carry flag is set
- ADC #PS2 ; A = A - 1
- STA $0208 ; save sprite 2 position
- LDA $0208
- STA paddle2y
- LDA $0210 ; load sprite 2 position
- CLC ; make sure carry flag is set
- ADC #PS2 ; A = A - 1
- STA $0210 ; save sprite 2 position
- LDA $0210
- STA paddle2y2
- LDA paddle2y2
- CMP #BOTTOMWALL
- BCC MovePaddleDownDone
- SEC ; make sure carry flag is set
- SBC #$01 ; A = A - 1
- STA paddle2y2
- LDA paddle2y
- SEC ; make sure carry flag is set
- SBC #$01 ; A = A - 1
- STA paddle2y
- MovePaddleDownDone:
- lda buttons2 ;load the current button state for controller1
- and #%00001000 ;isolate the bit representing "up", by clearing all the other bits
- beq MovePaddleUpDone ;if the result was 0, then the "up" bit was clear (thus not pressed), so skip the following code
- ;...
- LDA $0208 ; load sprite 2 position
- SEC ; make sure carry flag is set
- SBC #PS2 ; A = A - 1
- STA $0208 ; save sprite 2 position
- LDA $0208
- STA paddle2y
- LDA $0210 ; load sprite 2 position
- SEC ; make sure carry flag is set
- SBC #PS2 ; A = A - 1
- STA $0210 ; save sprite 2 position
- LDA $0210
- STA paddle2y2
- LDA paddle2y
- CMP #TOPWALL
- BCS MovePaddleUpDone
- CLC ; make sure carry flag is set
- ADC #$01 ; A = A - 1
- STA paddle2y
- LDA paddle2y2
- CLC ; make sure carry flag is set
- ADC #$01 ; A = A - 1
- STA paddle2y2
- ;;if up button pressed
- ;; if paddle top > top wall
- ;; move paddle top and bottom up
- MovePaddleUpDone:
- RTS
- Skip:
- CheckPaddleCollision:
- LDA ballx
- CMP #PADDLE1X+8
- BCS CheckPaddleCollisionDone ;;if ball x > left wall, still on screen, skip next section
- LDA bally
- CMP paddle1y
- BCS CheckPaddleCollisionDone ;;if ball y > top wall, still on screen, skip next section
- LDA bally
- CMP paddle1y2
- BCC CheckPaddleCollisionDone ;;if ball y < bottom wall, still on screen, skip next section
- ; LDA ballx
- ; CLC
- ; ADC ballspeedx ;;ballx position = ballx - ballspeedx
- ; STA ballx
- LDA #$01
- STA ballright
- LDA #$00
- STA ballleft ;;bounce, ball now moving right
- LDA bally
- CMP paddle1y2
- BCS .point2
- LDA #$01
- STA ballup
- LDA #$00
- STA balldown
- ; LDA bally
- ; SEC
- ; SBC ballspeedy ;;bally position = bally - ballspeedy
- ; STA bally
- JMP CheckPaddleCollisionDone
- .point2
- ; LDA #$01
- ; LDA bally
- ; CLC
- ; ADC ballspeedy ;;bally position = bally - ballspeedy
- ; STA bally
- LDA #$01
- STA balldown
- LDA #$00
- STA ballup
- ; LDA #$00
- ; STA ballleft
- ; LDA #$00
- ; STA balldown
- ; LDA #$00
- ; STA ballup
- CheckPaddleCollisionDone:
- RTS
- ; JMP GameEngineDone
- UpdateSprites:
- LDA bally ;;update all ball sprite info
- STA $0200
- LDA #$30
- STA $0201
- LDA #$00
- STA $0202
- LDA ballx
- STA $0203
- LDA paddle1y ;;update all ball sprite info
- STA $0204
- LDA #$7F
- STA $0205
- LDA #$10
- STA $0206
- LDA #PADDLE1X
- STA $0207
- LDA paddle1y2 ;;update all ball sprite info
- STA $020C
- LDA #$7F
- STA $020D
- LDA #$10
- STA $020E
- LDA #PADDLE1X
- STA $020F
- LDA paddle2y
- STA $0208
- LDA #$7F
- STA $0209
- LDA #$10
- STA $020A
- LDA #PADDLE2X
- STA $020B
- LDA paddle2y2
- STA $0210
- LDA #$7F
- STA $0211
- LDA #$10
- STA $0212
- LDA #PADDLE2X
- STA $0213
- ;;update paddle sprites
- RTS
- DrawScore:
- LDA $2002
- LDA #$20
- STA $2006
- LDA #$20
- STA $2006 ; start drawing the score at PPU $2020
- .Zero1
- LDA scoreHundreds ; last digit
- cmp #$00
- beq .pointa
- cmp #$24
- bne .point
- LDA scoreTens ; next digit
- cmp #$00
- bne .point
- LDA #$24
- STA scoreTens
- JMP .point
- .pointa
- LDA #$24
- STA scoreHundreds
- .point
- LDA scoreHundreds ; get first digit
- ; CLC
- ; ADC #$30 ; add ascii offset (this is UNUSED because the tiles for digits start at 0)
- STA $2007 ; draw to background
- LDA scoreTens ; next digit
- ; CLC
- ; ADC #$30 ; add ascii offset
- STA $2007
- LDA scoreOnes ; last digit
- ; CLC
- ; ADC #$30 ; add ascii offset
- STA $2007
- RTS
- DrawScore2:
- LDA $2002
- LDA #$20
- STA $2006
- LDA #$3C
- STA $2006 ; start drawing the score at PPU $203C
- .Zero
- LDA scoreHundreds2 ; last digit
- cmp #$00
- beq .point2b
- cmp #$24
- bne .point2
- LDA scoreTens2 ; next digit
- cmp #$00
- bne .point2
- LDA #$24
- STA scoreTens2
- JMP .point2
- .point2b
- LDA #$24
- STA scoreHundreds2
- .point2
- LDA scoreHundreds2 ; get first digit
- ; CLC
- ; ADC #$30 ; add ascii offset (this is UNUSED because the tiles for digits start at 0)
- STA $2007 ; draw to background
- LDA scoreTens2 ; next digit
- ; CLC
- ; ADC #$30 ; add ascii offset
- STA $2007
- LDA scoreOnes2 ; last digit
- ; CLC
- ; ADC #$30 ; add ascii offset
- STA $2007
- RTS
- IncrementScore1:
- IncOnes:
- LDA scoreOnes ; load the lowest digit of the number
- CLC
- ADC #$01 ; add one
- STA scoreOnes
- CMP #$0A ; check if it overflowed, now equals 10
- bne IncDone ; if there was no overflow, all done
- IncTens:
- LDA #$00
- STA scoreOnes ; wrap digit to 0
- LDA scoreTens ; load the next digit
- cmp #$24
- bne .add
- sec
- sbc #$24
- STA scoreTens
- .add
- LDA scoreTens ; load the next digit
- CLC
- ADC #$01 ; add one, the carry from previous digit
- STA scoreTens
- CMP #$0A ; check if it overflowed, now equals 10
- bne IncDone ; if there was no overflow, all done
- IncHundreds:
- LDA #$00
- STA scoreTens ; wrap digit to 0
- LDA scoreHundreds ; load the next digit
- cmp #$24
- bne .add1
- sec
- sbc #$24
- STA scoreHundreds
- .add1
- LDA scoreHundreds ; load the next digit
- CLC
- ADC #$01 ; add one, the carry from previous digit
- STA scoreHundreds
- IncDone:
- JMP IncDone2
- IncrementScore2:
- IncOnes2:
- LDA scoreOnes2 ; load the lowest digit of the number
- CLC
- ADC #$01 ; add one
- STA scoreOnes2
- CMP #$0A ; check if it overflowed, now equals 10
- BNE IncDone2 ; if there was no overflow, all done
- IncTens2:
- LDA #$00
- STA scoreOnes2 ; wrap digit to 0
- LDA scoreTens2 ; load the next digit
- cmp #$24
- bne .add
- sec
- sbc #$24
- STA scoreTens2
- .add
- LDA scoreTens2 ; load the next digit
- CLC
- ADC #$01 ; add one, the carry from previous digit
- STA scoreTens2
- CMP #$0A ; check if it overflowed, now equals 10
- BNE IncDone2 ; if there was no overflow, all done
- IncHundreds2:
- LDA #$00
- STA scoreTens2 ; wrap digit to 0
- LDA scoreHundreds2 ; load the next digit
- cmp #$24
- bne .add1
- sec
- sbc #$24
- STA scoreHundreds2
- .add1
- LDA scoreHundreds2 ; load the next digit
- CLC
- ADC #$01 ; add one, the carry from previous digit
- STA scoreHundreds2
- IncDone2:
- LDA scoreHundreds
- cmp #$01
- BEQ GameOver
- LDA scoreHundreds2
- cmp #$01
- BEQ GameOver
- ReadController1:
- LDA #$01
- STA $4016
- LDA #$00
- STA $4016
- LDX #$08
- ReadController1Loop:
- LDA $4016
- LSR A ; bit0 -> Carry
- ROL buttons1 ; bit0 <- Carry
- DEX
- BNE ReadController1Loop
- RTS
- ReadController2:
- LDA #$01
- STA $4016
- LDA #$00
- STA $4016
- LDX #$08
- ReadController2Loop:
- LDA $4017
- LSR A ; bit0 -> Carry
- ROL buttons2 ; bit0 <- Carry
- DEX
- BNE ReadController2Loop
- RTS
- GameOver:
- LDA #STATEGAMEOVER
- STA gamestate
- JMP GameEngine
- ;;;;;;;;;;;;;;
- .bank 1
- .org $E000
- palette:
- .db $22,$29,$1A,$0F, $22,$36,$17,$0F, $22,$30,$21,$0F, $22,$27,$17,$0F ;;background palette
- .db $22,$1C,$15,$14, $22,$02,$38,$3C, $22,$1C,$15,$14, $22,$02,$38,$3C ;;sprite palette
- sprites:
- ;vert tile attr horiz
- .db $52, $01, $00, $28 ; Player1 paddle top
- .db $5A, $11, $00, $28 ; Player1 paddle bottom
- .db $52, $01, $01, $D8 ; Player2 paddle top
- .db $5A, $11, $01, $D8 ; Player2 paddle bottom
- .db $74, $02, $02, $78 ; Ball
- .org $FFFA ;first of the three vectors starts here
- .dw NMI ;when an NMI happens (once per frame if enabled) the
- ;processor will jump to the label NMI:
- .dw RESET ;when the processor first turns on or is reset, it will jump
- ;to the label RESET:
- .dw 0 ;external interrupt IRQ is not used in this tutorial
- ;;;;;;;;;;;;;;
- .bank 2
- .org $0000
- .incbin "mario.chr" ;includes 8KB graphics file from SMB1
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement