diff --git a/atlantico/Makefile b/atlantico/Makefile index 317fe0d..d8efe12 100755 --- a/atlantico/Makefile +++ b/atlantico/Makefile @@ -15,4 +15,4 @@ clean: # Rule to run the final cartridge .nes file in the FCEUX emulator ############################################################################### run: - on-workspace 6 "fceux atlantico.nes" + on-workspace 4 "fceux atlantico.nes" diff --git a/atlantico/actor.inc b/atlantico/actor.inc index b707c9f..c9139b0 100644 --- a/atlantico/actor.inc +++ b/atlantico/actor.inc @@ -12,6 +12,4 @@ Type .byte XPos .byte YPos .byte - XVel .byte - YVel .byte .endstruct diff --git a/atlantico/atlantico.asm b/atlantico/atlantico.asm index 0d65b1e..22a1246 100755 --- a/atlantico/atlantico.asm +++ b/atlantico/atlantico.asm @@ -5,30 +5,38 @@ .include "utils.inc" .segment "ZEROPAGE" -Buttons: .res 1 ; Pressed buttons (A|B|Select|Start|Up|Dwn|Lft|Rgt) +Buttons: .res 1 ; Pressed buttons (A|B|Select|Start|Up|Dwn|Lft|Rgt) +PrevButtons: .res 1 ; Pressed buttons (A|B|Select|Start|Up|Dwn|Lft|Rgt) PREVIOUSLY -XPos: .res 2 ; Player X 16-bit position (8.8 fixed-point): hi+lo/256px -YPos: .res 2 ; Player Y 16-bit position (8.8 fixed-point): hi+lo/256px +XPos: .res 1 ; Player X 16-bit position (8.8 fixed-point): hi+lo/256px +YPos: .res 1 ; Player Y 16-bit position (8.8 fixed-point): hi+lo/256px -XVel: .res 1 ; Player X (signed) velocity (in pixels per 256 frames) -YVel: .res 1 ; Player Y (signed) velocity (in pixels per 256 frames) +XVel: .res 1 ; Player X (signed) velocity (in pixels per 256 frames) +YVel: .res 1 ; Player Y (signed) velocity (in pixels per 256 frames) -Frame: .res 1 ; Counts frames (0 to 255 and repeats) -IsDrawComplete: .res 1 ; Flag to indicate when vblank is done drawing -Clock60: .res 1 ; Counter that increments per second (60 frames) -BgPtr: .res 2 ; Pointer to background address - 16bits (lo,hi) +PrevSubmarine: .res 1 ; how long ago we added previous submarine in seconds -XScroll: .res 1 ; Store the horizontal scroll position -CurrNametable: .res 1 ; Store the current starting nametable (0 or 1) -Column: .res 1 ; Stores the column (of tiles) we are in the level -NewColAddr: .res 2 ; The destination address of the new column in PPU -SourceAddr: .res 2 ; The source address in ROM of the new column tiles +Frame: .res 1 ; Counts frames (0 to 255 and repeats) +IsDrawComplete: .res 1 ; Flag to indicate when vblank is done drawing +Clock60: .res 1 ; Counter that increments per second (60 frames) -ParamType: .res 1 ; Used as param to subrouting -ParamXPos: .res 1 ; Used as param to subrouting -ParamYPos: .res 1 ; Used as param to subrouting -ParamXVel: .res 1 ; Used as param to subrouting -ParamYVel: .res 1 ; Used as param to subrouting +BgPtr: .res 2 ; Pointer to background address - 16bits (lo,hi) +SprPtr: .res 2 ; pointer to the sprite address - 16bits (lo,hi) + +XScroll: .res 1 ; Store the horizontal scroll position +CurrNametable: .res 1 ; Store the current starting nametable (0 or 1) +Column: .res 1 ; Stores the column (of tiles) we are in the level +NewColAddr: .res 2 ; The destination address of the new column in PPU +SourceAddr: .res 2 ; The source address in ROM of the new column tiles + +ParamType: .res 1 ; Used as param to subrouting +ParamXPos: .res 1 ; Used as param to subrouting +ParamYPos: .res 1 ; Used as param to subrouting +ParamTileNum: .res 1 ; Used as param to subrouting +ParamNumTiles: .res 1 ; Used as param to subrouting +ParamAttribs: .res 1 ; Used as param to subrouting + +PrevOAMCount: .res 1 ; Store previous number of bytes sent to the OAM ; Store enough space for an array of actors ActorsArray: .res MAX_ACTORS * .sizeof(Actor) @@ -215,7 +223,7 @@ LoopButtons: ;AddNewActor ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Subroutine to add new actor to the array in the first empty slot found -;; Params: ParamType, ParamXPos, ParamYPos, ParamXVel, ParamYVel +;; Params: ParamType, ParamXPos, ParamYPos, ParamYVel ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; .proc AddNewActor ldx #0 @@ -231,6 +239,7 @@ LoopButtons: adc #.sizeof(Actor) tax jmp ArrayLoop + AddNewActorToArray: lda ParamType sta ActorsArray+Actor::Type,x @@ -238,14 +247,239 @@ LoopButtons: sta ActorsArray+Actor::XPos,x lda ParamYPos sta ActorsArray+Actor::YPos,x - lda ParamXVel - sta ActorsArray+Actor::XVel,x - lda ParamYVel - sta ActorsArray+Actor::YVel,x EndRoutine: rts .endproc +.proc SpawnActors + SpawnSubmarine: + lda Clock60 ; Submarines added in 3 second intervals + sec ; + sbc PrevSubmarine ; + cmp #3 ; Only add if 3 seconds have pased + bne :+ ; + lda #ActorType::SUBMARINE ; + sta ParamType ; Load Param for the actor type + lda #223 ; + sta ParamXPos ; Load X Pos + lda #185 ; + sta ParamYPos ; + ; + jsr AddNewActor ; Call subroutine + ; + lda Clock60 ; + sta PrevSubmarine ; Save the current clocktime as the submarine clock spawn time + : + rts +.endproc + + +.proc UpdateActors + ldx #0 ; counter of how many actors + ActorsLoop: + lda ActorsArray+Actor::Type,x + + cmp #ActorType::MISSILE + bne :+ + ;;Update y Pos + ;; y-- + lda ActorsArray+Actor::YPos,x + sec + sbc #1 ; Decrement Y Position + sta ActorsArray+Actor::YPos,x ; + bcs SkipMissile + ;; Delete Missile + lda #ActorType::NULL + sta ActorsArray+Actor::Type,x ; + SkipMissile: + jmp NextActor + : + + cmp #ActorType::SUBMARINE + bne :+ + ;;Update x Pos + ;; x-- + lda ActorsArray+Actor::XPos,x + sec + sbc #1 ; Decrement X Position + sta ActorsArray+Actor::XPos,x ; + bcs SkipSubmarine + ;; Delete SUB + lda #ActorType::NULL + sta ActorsArray+Actor::Type,x ; + SkipSubmarine: + jmp NextActor + : + + NextActor: + txa + clc + adc #.sizeof(Actor) + tax + cmp #MAX_ACTORS * .sizeof(Actor) + bne ActorsLoop + rts +.endproc + + + +.proc RenderActors + lda #$02 ; + sta SprPtr+1 ; + lda #$00 ; + sta SprPtr ; set SprPtr to $0200 + + ldy #0 ; counter of how many tiles + ldx #0 ; counter of how many actors + ActorsLoop: + lda ActorsArray+Actor::Type,x + + cmp #ActorType::SPRITE0 + bne :+ + ;; Load Params with Y, TileNumber, Attribs, X,NumTiles=4 + lda ActorsArray+Actor::XPos,x + sta ParamXPos + lda ActorsArray+Actor::YPos,x + sta ParamYPos + lda #$70 + sta ParamTileNum + lda #%00100000 + sta ParamAttribs + lda #1 + sta ParamNumTiles + jsr DrawSprite + jmp NextActor + : + + cmp #ActorType::PLAYER + bne :+ + ;; Load Params with Y, TileNumber, Attribs, X,NumTiles=4 + lda ActorsArray+Actor::XPos,x + sta ParamXPos + lda ActorsArray+Actor::YPos,x + sta ParamYPos + lda #$60 + sta ParamTileNum + lda #%00000000 + sta ParamAttribs + lda #4 + sta ParamNumTiles + jsr DrawSprite + jmp NextActor + : + + cmp #ActorType::MISSILE + bne :+ + ;; Load Params with Y, TileNumber, Attribs, X,NumTiles=1 + lda ActorsArray+Actor::XPos,x + sta ParamXPos + lda ActorsArray+Actor::YPos,x + sta ParamYPos + lda #$50 + sta ParamTileNum + lda #%00000001 + sta ParamAttribs + lda #1 + sta ParamNumTiles + jsr DrawSprite + jmp NextActor + : + + cmp #ActorType::SUBMARINE + bne :+ + ;; Load Params with Y, TileNumber, Attribs, X,NumTiles=1 + lda ActorsArray+Actor::XPos,x + sta ParamXPos + lda ActorsArray+Actor::YPos,x + sta ParamYPos + lda #$04 + sta ParamTileNum + lda #%00000000 + sta ParamAttribs + lda #4 + sta ParamNumTiles + jsr DrawSprite + jmp NextActor + : + + NextActor: + txa + clc + adc #.sizeof(Actor) + tax + cmp #MAX_ACTORS * .sizeof(Actor) + + beq :+ + jmp ActorsLoop + : + + tya + pha ; Save Y to the Stack + + LoopTrailingTiles: + ;; Loop all bytes until we reach PrevOAMCount + cpy PrevOAMCount + bcs :+ + lda #$FF + sta (SprPtr),y ; set Y position to $ff to hide + iny ; + sta (SprPtr),y ; Set tile number as $FF + iny ; + sta (SprPtr),y ; Set attribs as $FF + iny ; + sta (SprPtr),y ; Setr X Position to $FF to hide tile + iny ; + jmp LoopTrailingTiles + : + + pla + sta PrevOAMCount + rts +.endproc + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Routine to loop "NumTiles" times, sending bytes to the OAM-RAM +;; Params = ParamXPos, ParamYPos, ParamTileNum, ParamAttribs, ParamNumTiles +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +.proc DrawSprite + txa ;push x to stack + pha ; save value of X register before anything + + ldx #0 + TileLoop: + lda ParamYPos + sta (SprPtr),y ; Send Y Position to Ram + iny + + lda ParamTileNum ; Send Tile# to the OAM + sta (SprPtr),y ; + inc ParamTileNum ; ParamTileNum++ + iny + + lda ParamAttribs ; Send Attribs to the OAM + sta (SprPtr),y + iny + + lda ParamXPos ; Send X Position to the OAM + sta (SprPtr),y + clc + adc #8 + sta ParamXPos ; increment X Pos 8 pixels + + iny + + inx ; X++ + cpx ParamNumTiles ; loop NumTiles times + bne TileLoop + + ; pop x from stack + pla + tax ; pull value of X from stack and transfer to x + + rts +.endproc + + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Reset handler (called when the NES resets or powers on) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -274,9 +508,6 @@ AddSprite0: sta ParamXPos lda #27 sta ParamYPos - lda #0 - sta ParamXVel - sta ParamYVel jsr AddNewActor AddPlayer: @@ -286,9 +517,6 @@ AddPlayer: sta ParamXPos lda YPos sta ParamYPos - lda #0 - sta ParamXVel - sta ParamYVel jsr AddNewActor InitBackgroundTiles: @@ -361,6 +589,9 @@ EnableRendering: ;;;;;;; START GAME LOOP GameLoop: + lda Buttons + sta PrevButtons + ;Perform Game Logic Here jsr ReadControllers @@ -368,26 +599,21 @@ CheckAButton: lda Buttons and #BUTTON_A beq :+ - lda YPos - lda #ActorType::MISSILE - sta ParamType - lda XPos - sta ParamXPos - lda YPos - sta ParamYPos - lda #0 - sta ParamXVel - lda #255 - sta ParamYVel - jsr AddNewActor + lda Buttons + and #BUTTON_A ; DEBOUNCE A PRESS + cmp PrevButtons ; Compare current buttons and check if A was previously pressed + beq:+ + lda #ActorType::MISSILE + sta ParamType + lda XPos + sta ParamXPos + lda YPos + jsr AddNewActor : - ;; TODO - ;;------------------ - ;jsr SpawnActors - ;jsr UpdateActors - ;jsr RenderActors - ;;------------------ + jsr SpawnActors + jsr UpdateActors + jsr RenderActors WaitForVBlank: ; we lock execution lda IsDrawComplete ; check and only perform game loop call once NMI is done drawing @@ -433,26 +659,26 @@ NewAttribsCheck: jsr DrawNewAttribs : -;SetPPUNoScroll: -; lda #0 -; sta PPU_SCROLL -; sta PPU_SCROLL -; -;EnablePPUSprite0: -; lda #%10010000 -; sta PPU_CTRL -; lda #%00011110 -; sta PPU_MASK -; -;WaitForNoSprite0: -; lda PPU_STATUS -; and #%01000000 -; bne WaitForNoSprite0 -; -;WaitForSprite0: -; lda PPU_STATUS -; and #%01000000 ; PPU address $2002 bit 6 is the sprite hit flag -; beq WaitForSprite0 ; loop until we do NOT have a sprite 0 hit +SetPPUNoScroll: + lda #0 + sta PPU_SCROLL + sta PPU_SCROLL + +EnablePPUSprite0: + lda #%10010000 + sta PPU_CTRL + lda #%00011110 + sta PPU_MASK + +WaitForNoSprite0: + lda PPU_STATUS + and #%01000000 + bne WaitForNoSprite0 + +WaitForSprite0: + lda PPU_STATUS + and #%01000000 ; PPU address $2002 bit 6 is the sprite hit flag + beq WaitForSprite0 ; loop until we do NOT have a sprite 0 hit ScrollBackground: inc XScroll ; XScroll++ diff --git a/atlantico/atlantico.nes b/atlantico/atlantico.nes index 42ea5d8..c003e50 100644 Binary files a/atlantico/atlantico.nes and b/atlantico/atlantico.nes differ diff --git a/atlantico/atlantico.o b/atlantico/atlantico.o index 3134f7c..1b16774 100644 Binary files a/atlantico/atlantico.o and b/atlantico/atlantico.o differ