

PlayerSetupÂ
The first subroutine (PlayerSetup) defines the background color, border color, and the sprite multicolors. Then the sprite to character position is initialized. The variable (PARAM1) stores the X register. Then we set zero in the X register to point to Sprite 0. The variable (PARAM2) manages the Y position. Finally the subroutine (SpriteToCharPos) is called that sets up this position, saving the X/Y newly defined values, and stores them in the Sprite(s)’s position.
After this another similar set of parameters is defined for Sprite 1 which manages the X/Y positions. Both of these calls together created the top/bottom of the Sprite (head down to the legs). Here’s a description:
Sprite 0:
PARAM1 = X Position
X Register = Sprite (X)
PARAM2 = Y Position
Next the variable (PLAYER_STATE_IDLE) is loaded and a call is made to the subroutine (ChangePlayerState). This is used to call the main routine “PlayerStateIdle”, which monitors the Sprite’s joystick movement, idle animation, and monitors the Player’s gravity.
The last part actives the Sprite by setting bit 1 of variable (SPRITE_IS_ACTIVE) and (SPRITE_IS_ACTIVE + 1). Finally the variable (PLAYER_FALLCOUNT) resets a count that manages the Player falling in midair.
;------------------------------------------------------------------------------ ; PLAYER SETUP ;------------------------------------------------------------------------------ ; PLAYER has a strange setup as it's ALWAYS going to be using sprites 0 and 1 ; As well as always being 'active' (used) ;------------------------------------------------------------------------------
PlayerSetup lda #COLOR_BLACK sta VIC_BACKGROUND_COLOR sta VIC_BORDER_COLOR lda #%00000011 ; Turn on multicolor for sprites 0 and 1 sta VIC_SPRITE_MULTICOLOR ; also turn all others to single color lda #COLOR_BLACK sta VIC_SPRITE_MULTICOLOR_1 ; Set sprite shared multicolor 1 to brown lda #COLOR_LTRED sta VIC_SPRITE_MULTICOLOR_2 ; set sprite shared multicolor 2 to 'pink' lda #COLOR_YELLOW sta VIC_SPRITE_COLOR ; set sprite 0 color to yellow lda #COLOR_BLUE sta VIC_SPRITE_COLOR + 1 ; set sprite 1 color to orange (bkground sprite) ;------------------------------------------------------------------------------ ; We now use a system that tracks the sprite position in character coords on ; the screen, so to avoid costly calculations every frame, we set the sprite ; to a character border initially and track all movement from there. That way ; we need only do this set of calculations once in the lifetime of the Player. ; ; To initially place the sprite, we use 'SpriteToCharPos' ;------------------------------------------------------------------------------ ; Sprite X position
lda #19 sta PARAM1 ; Sprite Y0 Head ldx #0 lda #3 sta PARAM2 jsr SpriteToCharPos ; Sprite Y1 Legs
ldx #1
lda #5
sta PARAM2
jsr SpriteToCharPos
lda #PLAYER_STATE_IDLE ; Set initial state (idle)
jsr ChangePlayerState
;——————————– This will be relevant later
; Trim for better collisions
lda #0 sta SPRITE_DELTA_TRIM_X ; Not used ;-------------------------------- Set Player Mob active lda #1 sta SPRITE_IS_ACTIVE ; Set sprite 0 to active sta SPRITE_IS_ACTIVE + 1 ; Set sprite 1 to active lda #0 ; reset the player fallcount sta PLAYER_FALLCOUNT rts
UpdatePlayer
The subroutine (UpdatePlayer) manages all of the Player (Sprite’s) boundary limits when moving close to the map’s edge. The constants are listed and defined as follows before getting into the subroutine.
PLAYER_RIGHT_CAP = Defines how far the Sprite walks to the right before scrolling the screen..
PLAYER_LEFT_CAP = Defines how far the Sprite walks to the left before scrolling the screen.
PLAYER_UP_CAP = Defines how far the Sprite can walk up before scrolling the screen.
PLAYER_DOWN_CAP = Defines how far the Sprite can walk down before scrolling the screen.
The variable (SPRITE_IS_ACTIVE) checks if the Sprite is still alive. If the Sprite is not dead yet, then a call is made to animate the Sprite using (AnimateSprite) and a call is made to (UpdatePlayerState).
;===================================================================================================
; UPDATE PLAYER
;---------------------------------------------------------------------------------------------------
; Update the player. Joystick controls are updated via interrupt so we read the values from JOY_X
; and JOY_Y
;---------------------------------------------------------------------------------------------------
PLAYER_RIGHT_CAP = $
1c ; Sprite movement caps - at this point we don't
PLAYER_LEFT_CAP = $09 ; Move the sprite, we scroll the screen
PLAYER_UP_CAP = $04
PLAYER_DOWN_CAP = $0F
UpdatePlayer
; Only update the player if it's active
lda SPRITE_IS_ACTIVE ; check against sprite #0 - is it active?
bne @update
rts
@update
ldx #0
jsr AnimateSprite ; Animate sprite
jsr UpdatePlayerState ; Update player by state
rts
JoystickReady
;=================================================================================================
; JOYSTICK / PLAYER MOVEÂ ;=================================================================================================
; JOYSTICK READY
;—————————————————————————————————
; There are times atm when we have to ignore joystick input so the scrolling can ‘catch up’ after ; movement stops. Usually for a couple of frames.
;
; Returns A : 0 = ready 1 = not ready
;
; Modifies A ;—————————————————————————————————
In the subroutine (JoystickReady) scrolling functions are manages. A “1” is saved here if the joystick has not moved yet and zero means it has movement. The variables are defined below:
SCROLL_MOVING = Checks if the screen is still scrolling or not
SCROLL_DIRECTION = Checks for the direction the Player is moving in
SCROLL_STOP = The scrolling has stopped. Check if it needs to move again.
;===================================================================================================
; JOYSTICK / PLAYER MOVE
;===================================================================================================
; The old system of joystick movement was going to become very unweildy very fast and not be very
; good for expanding what the player can do. I'm trying a new system where the routines are broken
; down and input is checked in individual states for what the player can do at any given time.
; The movement routines will then be broken down and called as needed by the states.
; Since the old system didn't actually read the joystick or scroll the screen (it read / set
; variables by routines that do) - this SHOULD be fairly workable.
;---------------------------------------------------------------------------------------------------
;===================================================================================================
; JOYSTICK READY
;---------------------------------------------------------------------------------------------------
; There are times atm when we have to ignore joystick input so the scrolling can 'catch up' after
; movement stops. Usually for a couple of frames.
;
; Returns A : 0 = ready 1 = not ready
;
; Modifies A
;---------------------------------------------------------------------------------------------------
JoystickReady lda SCROLL_MOVING ; if moving is 'stopped' we can test joystick beq @joyready ; if it's moving but direction is stopped, we're 'fixing' lda SCROLL_DIRECTION bne @joyready lda #1 ; Send code for joystick NOT ready for input rts
@joyready
lda #SCROLL_STOP ; reset scroll direction - if it needs to scroll sta SCROLL_DIRECTION ; it will be updated lda #0 ; send code for joystick ready rts
MovePlayerRight
For the (MovePlayerRight) subroutine the variable (SCROLL_FIX_SKIP) is cleared first. This handles a left pixel scroll issue that is used to skip a frame in the subroutine (UpdateScroll – found in the file scrolling.asm).
After this the variable (SPRITE_CHAR_POS_X) checks for a PLAYER_RIGHT_CAP for a right movement of the Player.
;===================================================================================================
; MOVE PLAYER RIGHT
;---------------------------------------------------------------------------------------------------
; Move the player one pixel to the right if possible, taking into account scrolling, map limits
; and collision detection against the screen ; ; Returns A: any blocking or special character to the right, or 0 if clear
;
;---------------------------------------------------------------------------------------------------
MovePlayerRight
lda #0 sta SCROLL_FIX_SKIP ;------------------------------------------ CHECK RIGHT MOVEMENT CAP clc ; clear carry flag because I'm paranoid lda SPRITE_CHAR_POS_X ; load the sprite char X position cmp #PLAYER_RIGHT_CAP ; check against the right edge of the screen bcc @rightMove ; if X char pos < cap - move the sprite, else scroll ; Check against map edge
A check is made to the variable (MAP_X_POS) to see if the map needs to scroll to the right and it also checks the delta with the variable (MAP_X_DELTA).
If the variable (MAP_X_DELTA) is equal to zero then the variable (SCROLL_FIX_SKIP) is set.
lda MAP_X_POS ; load the current MAP X Position cmp #54 ; the map is 64 tiles wide, the screen is 10 tiles wide bne @scrollRight lda MAP_X_DELTA ; each tile is 4 characters wide (0-3) cmp #1 ; if we hit this limit we don't scroll (or move) bne @scrollRight ;at this point we will revert to move lda #1 sta SCROLL_FIX_SKIP jmp @rightMove rts
Since the variable (MAP_X_DELTA) is not at zero yet then we perform a call to (CheckMoveRight) to see if the Player can move to the right (are they blocked by a tile in the way?). A zero return here means a collision occurred. Then the variable (SCROLL_RIGHT) is cast into (SCROLL_DIRECTION) and (SCROLL_MOVING). Finally the subroutine returns a clear code in the accumulator.
;------------------------------------------ SCROLL RIGHT ; Pre-scroll check @scrollRight ldx #0 jsr CheckMoveRight ; Collision check against characters beq @scroll ; TODO - return the collision code here rts ; Setup for the scroll
@scroll
lda #SCROLL_RIGHT ; Set the direction for scroll and post scroll checks sta SCROLL_DIRECTION sta SCROLL_MOVING lda #0 ; load 'clear code' rts ; TODO - ensure collision code is returned ;----------------------------------------- MOVE SPRITE RIGHT
Check to see if the Player can move right using the subroutine (CheckMoveRight). If it’s not zero then a collision was found so we can’t move.
If no right collision was found then call a subroutine to (MoveSpriteRight – twice). Then set a clear code.
@rightMove
ldx #0 jsr CheckMoveRight ; Check ahead for character collision bne @rightDone
@moveRight
ldx #0 jsr MoveSpriteRight ; Move sprites one pixel right ldx #1 jsr MoveSpriteRight lda #0 ; move code 'clear'
@rightDone
rts
MovePlayerLeft
For the (MovePlayerLeft) subroutine the variable (SCROLL_FIX_SKIP) is cleared first. This handles a left pixel scroll issue that is used to skip a frame in the subroutine (UpdateScroll – found in the file scrolling.asm).
After this the variable (SPRITE_CHAR_POS_X) checks for a PLAYER_LEFT_CAP for a left movement of the Player.
;===================================================================================================
; MOVE PLAYER LEFT
;---------------------------------------------------------------------------------------------------
; Move the player one pixel to the left if possible, taking into account scrolling, map limits
; and collision detection against the screen
;
; Returns A: any blocking or special character to the right, or 0 if clear
;---------------------------------------------------------------------------------------------------
MovePlayerLeft
lda #0 ; Make sure scroll 'fix' is on
sta SCROLL_FIX_SKIP ;---------------------------------------- CHECK MOVEMENT CAP ($07)
lda SPRITE_CHAR_POS_X ; Check for left side movement cap
cmp #PLAYER_LEFT_CAP
bcs @leftMove ; if below cap, we move the sprite
A check is made to the variable (MAP_X_POS) to see if the map needs to scroll to the left and it also checks the delta with the variable (MAP_X_DELTA).
If the variable (MAP_X_DELTA) is equal to zero then the variable (SCROLL_FIX_SKIP) is set. Then the variable (SPRITE_POS_X)) is check to see if the Sprite has moved to the left edge of the screen.
; Otherwise we prepare to scroll
; Check for edge of map for scrolling
lda MAP_X_POS ; Check for map pos X = 0
bne @scrollLeft
lda MAP_X_DELTA ; check for map delta = 0
bne @scrollLeft ; We're at the maps left edge
; So we revert to sprite movement once more
lda #1
sta SCROLL_FIX_SKIP
lda SPRITE_POS_X,x ; Check for sprite pos > 0 (not sprite char pos)
bpl @leftMove ; so we could walk to the edge of screen
rts
Since the variable (MAP_X_DELTA) is not at zero yet then we perform a call to (CheckMoveLeft) to see if the Player can move to the left (are they blocked by a tile in the way?). A zero return here means a collision occurred. Then the variable (SCROLL_LEFT) is cast into (SCROLL_DIRECTION) and (SCROLL_MOVING). Finally the subroutine returns a clear code in the accumulator.
@scrollLeft
;--------------------------------------- SCROLL SCREEN FOR LEFT MOVE
ldx #0
jsr CheckMoveLeft ; check for character collision to the left
beq @scroll
rts ; TODO - return collision code
@scroll
lda #SCROLL_LEFT
sta SCROLL_DIRECTION
sta SCROLL_MOVING
lda #0 ; return 'clear code' ; TODO - return clear collision code
rts ;---------------------------------------- MOVE THE PLAYER LEFT ONE PIXEL
Check to see if the Player can move left using the subroutine (CheckMoveLeft). If it’s not zero then a collision was found so we can’t move.
If no left collision was found then call a subroutine to (MoveSpriteLeft – twice). Then set a clear code.
@leftMove
ldx #0
jsr CheckMoveLeft ; check for collisions with characters
bne @leftDone ; TODO return collision code
@moveLeft
ldx #0
jsr MoveSpriteLeft
ldx #1
jsr MoveSpriteLeft
lda #0 ; move code 'clear'
@leftDone rts
MovePlayerDown
Check the variable (SPRITE_CHAR_POS_Y) against the variable (PLAYER_DOWN_CAP) to see if the Player has not reached a boundary yet and can still move down.
;===================================================================================================
; MOVE PLAYER DOWN
;---------------------------------------------------------------------------------------------------
; Move the player one pixel down if possible, taking into account scrolling, map limits
; and collision detection against the screen
;
; Returns A: any blocking or special character below, or 0 if clear
;
; Modifies X
;---------------------------------------------------------------------------------------------------
MovePlayerDown clc lda SPRITE_CHAR_POS_Y cmp #PLAYER_DOWN_CAP bcc @downMove
A check is then made to the variable (MAP_Y_POS) to see if the screen is ready to scroll down after the Player has reached a boundary and it also checks the delta with the variable (MAP_Y_DELTA) to see if a delta was range was reached.
lda MAP_Y_POS cmp #$1B bne @downScroll lda MAP_Y_DELTA cmp #02 bcc @downScroll rts
Since the variable (MAP_Y_DELTA) is not at zero yet then we perform a call to (CheckMoveDown) to see if the Player can move down (are they blocked by a tile in the way?) A zero here means a collision occurred. Then the variable (SCROLL_DOWN) is cast into (SCROLL_DIRECTION) and (SCROLL_MOVING). Finally a subroutine returns a clear code in the accumulator.
@downScroll
ldx #0 ; Check Sprite #0 jsr CheckMoveDown ; returns: 0 = can move : 1 = blocked beq @scroll ; We are not blocked = 0 rts ; return with contents of collison routine
@scroll
lda #SCROLL_DOWN sta SCROLL_DIRECTION sta SCROLL_MOVING lda #0 ; return a clear collision code rts
Check to see if the Player can move down using the subroutine (CheckMoveDown). If it’s not zero then a collision was found so we can’t move.
If no down collision was found then call a subroutine to (MoveSpriteDown – twice). Then set a clear code.
@downMove
ldx #0 ; Check Sprite #0 jsr CheckMoveDown ; returns: 0 = can move : 1 = blocked bne @downDone ; retun with contents of collision code jsr MoveSpriteDown ; = 0 so we can move the Sprite Down ldx #1 jsr MoveSpriteDown lda #0 ; return with clear code
@downDone rts
MovePlayerUp
Check the variable (SPRITE_CHAR_POS_Y) against the variable (PLAYER_UP_CAP) to see if the Player has not reached a boundary yet and can still move up.
;===================================================================================================
; MOVE PLAYER UP
;---------------------------------------------------------------------------------------------------
; Move the player one pixel up if possible, taking into account scrolling, map limits
; and collision detection against the screen
;
; Returns A: any blocking or special character below, or 0 if clear
;---------------------------------------------------------------------------------------------------
MovePlayerUp
sec
lda SPRITE_CHAR_POS_Y
cmp #PLAYER_UP_CAP
bcs @upMove
A check is then made to the variable (MAP_Y_POS) to see if the screen is ready to scroll down after the Player has reached a boundary and it also checks the delta with the variable (MAP_Y_DELTA) to see if a delta was range was reached.
lda MAP_Y_POS
bne @upScroll
clc
lda MAP_Y_DELTA
cmp #1
bcs @upScroll
rts
Since the variable (MAP_Y_DELTA) is not at zero yet then we perform a call to (CheckMoveUp) to see if the Player can move up (are they blocked by a tile in the way?) A zero here means a collision occurred. Then the variable (SCROLL_UP) is cast into (SCROLL_DIRECTION) and (SCROLL_MOVING). Finally a subroutine returns a clear code in the accumulator.
@upScroll
ldx #0
jsr CheckMoveUp
beq @scroll
rts
@scroll
lda #SCROLL_UP
sta SCROLL_DIRECTION
sta SCROLL_MOVING
rts
Check to see if the Player can move up using the subroutine (CheckMoveUp). If it’s not zero then a collision was found so we can’t move.
If no up collision was found then call a subroutine to (MoveSpriteUp – twice). Then set a clear code.
@upMove
ldx #0 ; Check Sprite 0 (head/body) jsr CheckMoveUp bne @upDone
jsr MoveSpriteUp
ldx #1
jsr MoveSpriteUp
@upDone rts
ApplyGravity
Check to see if there is right movement and save a result in the variable (JOY_X). Otherwise we found right movement of the joystick.
;===================================================================================================
; APPLY GRAVITY
;===================================================================================================
; Apply Gravity to the player - this system will be totally rewritten at some point to apply
; a proper gravity to a player or any other sprite.. but for now it's just super basic
;
; A returns 0 if we moved down and a collision code if we didn't
;---------------------------------------------------------------------------------------------------
ApplyGravity
lda #%00000100 ; Mask for bit 2 bit JOY_2 bne @testRightMov ; Set Left state lda #$FF sta JOY_X jmp @doneMov
@testRightMov
; Test for Right lda #%00001000 ; Mask for bit 3 bit JOY_2 bne @doneMov
Make a call to subroutine (CheckBlockUnder) to see if there is a water collision (COLL_WATER) and execute that branch.
Else make a call to check for a rope collision (COLL_ROPE) and execute that branch.
Else make a call to check for a floor collision (COLL_FLOOR) and execute that branch.
@doneMov
ldx #1 ; if we are on a rope, can we move down? jsr CheckBlockUnder ; first check we are on a rope lda COLLIDER_ATTR cmp #COLL_WATER beq @goFloat ldx #1 ; if we are on a rope, can we move down? jsr CheckBlockUnder ; first check we are on a rope lda COLLIDER_ATTR cmp #COLL_ROPE beq @ontheRope ; Player is on the rope cmp #COLL_FLOOR beq @noFalling ; Otherwise we have more checks.
Check the variable (SPRITE_POS_X_DELTA) to see if we are lined up to a tile and branch, otherwise we exit this routine.
lda SPRITE_POS_X_DELTA ; if not lined up on the rope we get a false positive cmp #4 ; for collisions around a 'rope hole' beq @moveDown ; If we are lined up, and blocked, its' solid ground bcc @moveDown ; if less than 4 - shift left one jmp @noFalling
If the delta was aligned then we make a call to subroutine (CheckMoveDown) to see if a tile exists there, otherwise we exit.
No tile was found here so call the subroutine (MovePlayerDown – twice) to move the Sprite down the screen since they are airbound.
We found a rope collision, call the subroutine “PlayerStateRope”
We found a water collision, call the subroutine “PlayerStateFloating”
; Otherwise shift right one
@moveDown
ldx #0 jsr CheckMoveDown ; If we are at the end, there will be solid ground under us beq @spriteMovesDown ; No tile exists under Player, he falls rts ; TILE FOUND: Stop gravity
@spriteMovesDown
ldx #0 jsr MovePlayerDown ldx #1 jsr MovePlayerDown
@noFalling rts
@ontheRope
lda #PLAYER_STATE_ROPE ; change to climb rope state jmp ChangePlayerState
@goFloat
lda #PLAYER_STATE_FLOATING ; change to climb rope state jmp ChangePlayerState
;===================================================================================================
; PLAYER STATES
;===================================================================================================
; Player states are incremented by 2 as they are indexes to look up the address of the state
; code on the PLAYER_STATE_JUMPTABLE. An address is 2 bytes (1 word) egro the index must increase
; by 2 bytes.
;---------------------------------------------------------------------------------------------------
PLAYER_STATE_IDLE = 0; standing still - awaiting input
PLAYER_STATE_WALK_R = 2 ; Walking right
PLAYER_STATE_WALK_L = 4 ; Walking left
PLAYER_STATE_FALL = 6 ; Falling
PLAYER_STATE_STAIRS_R = 8 ; stairs on the right
PLAYER_STATE_STAIRS_L = 10 ; stairs on the left
PLAYER_STATE_ROPE = 12 ; climb rope
PLAYER_STATE_JUMP = 14 ; Jumping
PLAYER_STATE_PUNCH_R = 16 ; punch right
PLAYER_STATE_PUNCH_L = 18 ; punch left
PLAYER_STATE_KICK_R = 20 ; kick right
PLAYER_STATE_KICK_L = 22 ; kick left
PLAYER_STATE_JUMP_R = 24 ; jump right
PLAYER_STATE_JUMP_L = 26 ; jump left
PLAYER_STATE_SWIM_R = 28 ; swim right
PLAYER_STATE_SWIM_L = 30 ; swim left
PLAYER_STATE_FLOATING = 32 ; floating
PLAYER_SUBSTATE_ENTER =Â 0 ; we have just entered this state
PLAYER_SUBSTATE_RUNNING = 1 ; This state is running normally
;---------------------------------------------------------------------------------------------------
; PLAYER STATE JUMPTABLE
;---------------------------------------------------------------------------------------------------
PLAYER_STATE_JUMPTABLE
word PlayerStateIdle
word PlayerStateWalkR
word PlayerStateWalkL
word PlayerStateFall
word PlayerStateStairsR
word PlayerStateStairsL
word PlayerStateRope
word PlayerStateJump
word PlayerStatePunchR
word PlayerStatePunchL
word PlayerStateKickR
word PlayerStateKickL
word PlayerStateJumpR
word PlayerStateJumpL
word PlayerStateSwimR
word PlayerStateSwimL
word PlayerStateFloating
ChangePlayerState
Save the variable (PLAYER_STATE) in the X register. Read the immediate value constant (PLAYER_SUBSTATE_ENTER). Save this in the variable (PLAYER_SUBSTATE). Set a “1” value in (SPRITE_ANIM_PLAY).
Next read from the table (PLAYER_STATE_JUMPTABLE. Save it in ZEROPAGE_POINTER_1 (low and high bytes). Execute the subroutine saved in the indirect address ZEROPAGE_POINTER_1.
This routine will point to individual subroutines based on whatever exists in the PLAYER_STATE_JUMPTABLE,x (which points to the specific line for that routine).
;===================================================================================================
; CHANGE PLAYER STATE
;---------------------------------------------------------------------------------------------------
; Change a players state
;
; A = state to change to
;
; Modifies A,X,ZEROPAGE_POINTER_1
;C64 Brain Notes: Player states recorded (animation, idle, running, etc.). Data is saved to PLAYER_SUBSTATE
;---------------------------------------------------------------------------------------------------
ChangePlayerState
tax ; transfer A to X stx PLAYER_STATE ; store the new player state lda #PLAYER_SUBSTATE_ENTER ; Set substate to ENTER sta PLAYER_SUBSTATE lda #1 sta SPRITE_ANIM_PLAY lda PLAYER_STATE_JUMPTABLE,x ; lookup state to change to sta ZEROPAGE_POINTER_1 ; and store it in ZEROPAGE_POINTER_1 lda PLAYER_STATE_JUMPTABLE + 1,x sta ZEROPAGE_POINTER_1 + 1 jmp (ZEROPAGE_POINTER_1) ; jump to state (to setup) ; NOTE: This is NOT a jsr. ; The state will act as an extension of ; this routine then return. rts
UpdatePlayerState
Save the constant (PLAYER_STATE) in the X register. Load from the table (PLAYER_STATE_JUMPTABLE) and save in ZEROPAGE_POINTER_1 (low and high bytes). Go to the subroutine (indirect register) to the pointer address located in ZEROPAGE_POINTER_1 (low and high bytes).
This works similar to (ChangePlayerState) and can be used to update a specific pointer in memory.
;===================================================================================================
; UPDATE PLAYER STATE
;---------------------------------------------------------------------------------------------------
; Update the player based on their state
;---------------------------------------------------------------------------------------------------
UpdatePlayerState
ldx PLAYER_STATE ; Load player state lda PLAYER_STATE_JUMPTABLE,x ; fetch the state address from the jump table sta ZEROPAGE_POINTER_1 ; store it in ZEROPAGE_POINTER_1 lda PLAYER_STATE_JUMPTABLE + 1,x sta ZEROPAGE_POINTER_1 + 1 jmp (ZEROPAGE_POINTER_1) ; jump to the right state (note - NOT a jsr) rts
PlayerStateIdle
;===================================================================================================
; STATE IDLE
;---------------------------------------------------------------------------------------------------
; The player is standing still and waiting input.
; Possible optimizations we are doublechecking CheckBlockUnder and CheckDown, we can check once
; and store those in a temp variable and look them up if needed.
;---------------------------------------------------------------------------------------------------
PlayerStateIdle
lda PLAYER_SUBSTATE ; Check for first entry to state
bne @running
ldx #0 ; load sprite number (0) in X lda #; load animation list in ZEROPAGE_POINTER_1 sta ZEROPAGE_POINTER_1 ; byte %00000111 lda #>ANIM_PLAYER_IDLE sta ZEROPAGE_POINTER_1 + 1 jsr InitSpriteAnim ; setup the animation for Idle lda PLAYER_SUBSTATE_RUNNING ; set the substate to Running sta PLAYER_SUBSTATE rts @running
jsr JoystickReady
beq @input
rts
@input ;=============================================================================== ; SPRITE CLIMBING THE POLE ;=============================================================================== ldx #1 jsr CheckBlockUnder lda COLLIDER_ATTR cmp #COLL_ROPE ; Check for rope under player beq @goRopeClimb ; found it, go to Rope climb state
@buttonCheck
lda #%00010000 ; Mask for bit 0 bit JOY_2 ; check zero = jumping (button pressed) beq @butPress
;=============================================================================== ; JOYSTICK: PUNCHING/JUMPING ;=============================================================================== @checkdiagonals lda checkupright bit JOY_2 ; punch right beq @pressUpRight lda checkupleft ; Mask for bit 0 bit JOY_2 ; check zero = jumping (button pressed) beq @pressUpLeft ; punch left
;=============================================================================== ; SPRITE FLOOR CHECK (ON GROUND) ;=============================================================================== ldx #1 jsr CheckBlockUnder lda COLLIDER_ATTR cmp #COLL_FLOOR ; Does floor exist under us? bne @stillFalling ; No, player keeps falling ; Move Player Up if not falling. This fixes a big that positions the player ; below the floor. ldx #0 jsr MovePlayerUp ldx #1 jsr MovePlayerUp jmp @horizCheck ; Player has landed on tile (can't fall)
;===============================================================================
; SPRITE FALLING (Gravity applied)
;===============================================================================
@stillFalling
jsr ApplyGravity
@horizCheck
lda JOY_X ; horizontal movement beq @vertCheck ; check zero - ho horizontal input bmi @left ; negative = left ;--------------------------------------------- JOYSTICK RIGHT
@right
lda #PLAYER_STATE_WALK_R ; go to walk state right jmp ChangePlayerState ;--------------------------------------------- JOYSTICK LEFT
@left
lda #PLAYER_STATE_WALK_L ; go to walk state left jmp ChangePlayerState
@goFloating
lda #PLAYER_STATE_FLOATING
jmp ChangePlayerState
@vertCheck ;=============================================================================== ; SPRITE SWIMMING IN WATER ;=============================================================================== ldx #1 ; if we are on a rope, can we move down? jsr CheckBlockUnder ; first check we are on a rope lda COLLIDER_ATTR cmp #COLL_WATER beq @goFloating lda JOY_Y ; check vertical joystick input beq @end ; zero means no input bmi @up ; negative means up bpl @down ; already checked for 0 - so this is positive rts
@goRopeClimb
lda #PLAYER_STATE_ROPE
jmp ChangePlayerState
@inLakeTest
lda #PLAYER_STATE_IDLE
jmp ChangePlayerState
rts
@pressUpRight
lda #PLAYER_STATE_PUNCH_R ; go to jump state jmp ChangePlayerState
@pressUpLeft
lda #PLAYER_STATE_PUNCH_L ; go to jump state jmp ChangePlayerState
@butPress
lda #PLAYER_STATE_JUMP ; go to jump state jmp ChangePlayerState
;--------------------------------------------- JOYSTICK UP
@up
ldx #1 jsr CheckBlockUnder lda COLLIDER_ATTR cmp #COLL_ROPE ; Check for rope under player bne @end
lda #PLAYER_STATE_ROPE ; change to climb rope state jmp ChangePlayerState ;-------------------------------------------- JOYSTICK DOWN
@down
ldx #1 ; if we are on a rope, can we move down? jsr CheckBlockUnder ; first check we are on a rope lda COLLIDER_ATTR cmp #COLL_ROPE bne @noRope jsr CheckMoveDown ; If we are at the end, there will be solid ground under us beq @goRopeClimb ; No blocking and on rope? We change to climbing ; Otherwise we have more checks. lda SPRITE_POS_X_DELTA ; if not lined up on the rope we get a false positive cmp #4 ; for collisions around a 'rope hole' beq @end ; If we are lined up, and blocked, its' solid ground bcc @deltaLess ; if less than 4 - shift left one ldx #0 jsr MovePlayerLeft rts
@deltaLess
; Otherwise shift right one ldx #0 jsr MovePlayerRight rts
@goWaterFloatRight
lda #PLAYER_STATE_SWIM_R
jmp ChangePlayerState
@goWaterFloatLeft
lda #PLAYER_STATE_SWIM_L
jmp ChangePlayerState
@noRope
@end
rts
IDLE_VAR
byte $00
Â
PlayerStateWalkR
;===================================================================================================
; STATE WALKING RIGHT
;---------------------------------------------------------------------------------------------------
PlayerStateWalkR
ldx #0
jsr CheckMoveRight
lda COLLIDER_ATTR
cmp #COLL_WATER
beq @goSwimRight
lda PLAYER_SUBSTATE bne @running ;------------------------------------------------------- SETUP CODE GOES HERE ldx #0 ; Use sprite number 0 lda #; load animation in ZEROPAGE_POINTER_1 sta ZEROPAGE_POINTER_1 lda #>ANIM_PLAYER_WALK_R sta ZEROPAGE_POINTER_1 + 1 jsr InitSpriteAnim ; initialize the animation lda #PLAYER_SUBSTATE_RUNNING ; set substate to RUNNING sta PLAYER_SUBSTATE rts ; wait till next frame to start ;-----------------------------------------------------------------------------
@running
jsr JoystickReady
beq @input ; Check creates the 'fix' pause for scroll resetting
lda #PLAYER_STATE_IDLE
jmp ChangePlayerState
rts
@input ldx #1 ; Rope Check jsr CheckBlockUnder lda COLLIDER_ATTR cmp #COLL_ROPE beq @joyCheck jsr ApplyGravity ; Apply Gravity - if we are not falling bne @joyCheck ; check the joystick input ; Enables player to move right while falling inc PLAYER_FALLCOUNT lda PLAYER_FALLCOUNT cmp #10 bcs @joyCheck rts
@goSwimRight
lda #PLAYER_STATE_SWIM_R
jmp ChangePlayerState
@joyCheck
lda #0
sta PLAYER_FALLCOUNT ; Check for JUMP to RIGHT
@buttonCheck
lda JOY_X
bmi @idle ; if negative we are idling
beq @idle ; Pressed joystick to right
@right
jsr JoystickReady
lda #%00010000 ; Mask for bit 0
bit JOY_2 ; check zero = button pressed
beq @jumping ; Player can jump right
ldx #0
jsr MovePlayerRight ; Move player one pixel across - A = move? 0 or 1
ldx #1
jsr MovePlayerRight
jsr ApplyGravity
rts
@foundWaterTile
lda #1
sta 53281
rts
@idle
jsr ApplyGravity ; Apply Gravity - if we are not falling
lda #PLAYER_STATE_IDLE
jmp ChangePlayerState
@jumping
jsr ApplyGravity ; Apply Gravity - if we are not falling
lda #PLAYER_STATE_JUMP
jmp ChangePlayerState
@doneJoy
rtsÂ
PlayerStateWalkL
;===================================================================================================
; STATE WALKING LEFT
;---------------------------------------------------------------------------------------------------
PlayerStateWalkL
ldx #0
jsr CheckMoveLeft
lda COLLIDER_ATTR
cmp #COLL_WATER
beq @goSwimLeft
lda PLAYER_SUBSTATE
bne @running
;------------------------------------------------------- SETUP CODE GOES HERE
ldx #0 ; Use sprite number 0
lda #; load animation in ZEROPAGE_POINTER_1
sta ZEROPAGE_POINTER_1
lda #>ANIM_PLAYER_WALK_L
sta ZEROPAGE_POINTER_1 + 1
jsr InitSpriteAnim ; initialize the animation
lda #PLAYER_SUBSTATE_RUNNING ; set substate to RUNNING
sta PLAYER_SUBSTATE
rts ; wait till next frame to start
@running
jsr JoystickReady
beq @input ; Check creates the 'fix' pause for scroll resetting
lda #PLAYER_STATE_IDLE
jmp ChangePlayerState
rts
@input ldx #1 ; Rope Check jsr CheckBlockUnder lda COLLIDER_ATTR cmp #COLL_ROPE beq @joyCheck jsr ApplyGravity ; we are falling bne @joyCheck ; Enables player to move left while falling inc PLAYER_FALLCOUNT ; if we fall > 8 pixels we are truly falling lda PLAYER_FALLCOUNT cmp #10 ; Player continues to fall for 10 frames bcs @joyCheck rts
@goSwimLeft
lda #PLAYER_STATE_SWIM_L
jmp ChangePlayerState
@joyCheck
lda #0 sta PLAYER_FALLCOUNT ; Button pressed for Left
@buttonCheck
lda JOY_X bpl @idle ; if negative we are idling beq @idle
@left
jsr JoystickReady lda #%00010000 ; Mask for bit 0 bit JOY_2 ; check zero = button pressed beq @jumping ; Player can jump left ldx #0 jsr MovePlayerLeft ; Move player one pixel across - A = move? 0 or 1 ldx #1 jsr MovePlayerLeft jsr ApplyGravity rts
@foundWaterTile
lda #1 sta 53281 rts
lda #PLAYER_STATE_IDLE
jmp ChangePlayerState
@idle
jsr ApplyGravity ; Apply Gravity - if we are not falling
lda #PLAYER_STATE_IDLE
jmp ChangePlayerState
@jumping jsr ApplyGravity ; Apply Gravity - if we are not falling lda #PLAYER_STATE_JUMP jmp ChangePlayerState
@foundObject lda #7 sta 53280 lda #1 sta 53281 rts
@doneJoy rts
PlayerStateRope
;===================================================================================================
; STATE ROPE UP
;---------------------------------------------------------------------------------------------------
; Climbing a rope up
;---------------------------------------------------------------------------------------------------
PlayerStateRope
lda PLAYER_SUBSTATE ; test for first run
bne @running
;——————————————————- SETUP CODE GOES HERE
ldx #0 ; Use sprite number 0
lda #; load animation in ZEROPAGE_POINTER_1
sta ZEROPAGE_POINTER_1
lda #>ANIM_CLIMB_ROPE_UP
sta ZEROPAGE_POINTER_1 + 1
jsr InitSpriteAnim ; initialize the animation
lda #PLAYER_SUBSTATE_RUNNING ; set substate to RUNNING
sta PLAYER_SUBSTATE
rts ; change takes effect next frame ;—————————————————————————–
@running
;———————————————————- JOYSTICK INPUT
 jsr JoystickReady
beq @input ; not ready for input
rts
;————————————————————————– ; Process valid joystick input
@input
ldx #1
jsr CheckBlockUnder ; Check tile under Top sprite (Sprite)
lda COLLIDER_ATTR
cmp #COLL_ROPE ; Does pole exist here?
bne @exitRopeClimb ; No pole found, exit routine
; Still climbing the rope here
lda JOY_X
beq @vertCheck
bmi @left
bpl @right
rts
@exitRopeClimb
; Move Player Up if not falling. This fixes a big that positions the player ; below the floor.
ldx #0
jsr MovePlayerUp
ldx #1
jsr MovePlayerUp ; Also scroll the screen upward
lda #SCROLL_UP
sta SCROLL_DIRECTION
sta SCROLL_MOVING
lda #PLAYER_STATE_IDLE
jmp ChangePlayerState
@right
ldx #1
jsr CheckMoveRight
beq @goRight ; Not blocked, right routine
rts
@goRight
lda #PLAYER_STATE_WALK_R
jmp ChangePlayerState
@left
ldx #1
jsr CheckMoveLeft
beq @goLeft ; Not blocked, left routine
rts
@goLeft
lda #PLAYER_STATE_WALK_L
jmp ChangePlayerState ; Align Player on rope so he can pass through ‘holes’ ; Check UP and DOWN on the ladder
@vertCheck
ldx #1
lda SPRITE_POS_X_DELTA,x
cmp #4 ; they pass through if delta is 4
beq @check ; We have passed completely through the tile
bcc @less ; if less than 4, shift right one pixel
jsr MovePlayerLeft ; not equal, not less, must be more – shift left one
jmp @check
@less
ldx #0
jsr MovePlayerRight
ldx #1
jsr MovePlayerRight
@check
; No tile was found underneath sprite, he falls
lda JOY_Y
beq @end
bmi @up
bpl @down
rts
@up
sec
lda SPRITE_CHAR_POS_Y
cmp #PLAYER_UP_CAP
bcs @goingUp
lda MAP_Y_POS
bne @upScroll
clc
lda MAP_Y_DELTA
cmp #1
bcs @upScroll
rts
@upScroll
ldx #0
jsr CheckMoveUp
beq @scroll
rts
@scroll
lda #SCROLL_UP
sta SCROLL_DIRECTION
sta SCROLL_MOVING
rts
@goingUp
lda #1
sta SPRITE_ANIM_PLAY ; play our animation
ldx #0
jsr MovePlayerUp
ldx #1
jsr MovePlayerUp
@exitMoveUp
rts
@down
lda #1
sta SPRITE_ANIM_PLAY ; play our animation
ldx #0
jsr MovePlayerDown ; Otherwise, move the Sprite Down
ldx #1
jsr MovePlayerDown
bne @endClimb ; We are not blocked continue on
rts
@finishDown
lda #1
sta SPRITE_ANIM_PLAY
jsr MovePlayerDown
bne @endClimb ; We are not blocked continue on
rts ; We are blocked=1 by a tile
@endClimb
lda SPRITE_POS_X_DELTA ; Check if Sprite is passing
cmp #4 ; completely through the tile
beq @stopClimb ; Yes, they passed through
rts
@stopClimb
lda #PLAYER_STATE_IDLE
jmp ChangePlayerState
@end
lda #0
sta SPRITE_ANIM_PLAY
; pause our animation
;————————————————————————–
rts
@playerFalls
jsr ApplyGravity
@exitRope
rts
PlayerStateJump
;===================================================================================================
; STATE JUMP UPÂ
;---------------------------------------------------------------------------------------------------
; Player is jumping
;---------------------------------------------------------------------------------------------------
; This routine is entered when a Joystick button is pressed.
PlayerStateJump
@running
@checkJump
@jumping
; First check if ledge is above Sprite ldx #0 jsr CheckMoveUp ; Check for tile above our Sprite beq @contJump ; No tile exit stage lda #PLAYER_STATE_IDLE jmp ChangePlayerState
@contJump
inc PLAYER_JUMP_POS ; Counter to track table loop lda PLAYER_JUMP_POS ; for PLAYER_JUMP_TABLE,x to read until cmp #28 ; it finds a "0" value. 28 bytes bcc @jumpOn
lda #0 sta PLAYER_JUMP_POS jmp @jumpComplete ; Still Jumping
; PLAYER_JUMP_POS Counter is still less than 28
@jumpOn
ldx PLAYER_JUMP_POS ; check x for jump table (x = current state ; of increment PLAYER_JUMP_POS) lda PLAYER_JUMP_TABLE,x ; check if at end of jump table = 0 beq @jumpComplete
@jumpContinue
jsr JoystickReady lda JOY_X beq @moveUp bmi @leftJump ; Check for joystick to Left = 255 bpl @rightJump ; Check for joystick to Right = 1 jmp @moveUp ; Slow down the jumping Sprite
@rightJump
ldx #0 jsr MovePlayerRight ldx #1 jsr MovePlayerRight jmp @moveUp ; Check for Jump to the Left
@leftJump ldx #0 jsr MovePlayerLeft ldx #1 jsr MovePlayerLeft
@moveUp
ldx #1 jsr CheckBlockUnder bne @onGround ; No tile exists under Sprite jsr ApplyGravity
@onGround ldx #0 jsr MovePlayerUp ldx #1 jsr MovePlayerUp lda PLAYER_TIMER bne @skipJump lda #1 sta PLAYER_SPEED lda #0 sta PLAYER_TIMER
@skipJump
jmp @jumping ; Table jump for PLAYER_JUMP_TABLE,x is done.
; Value of "0" was found.
@jumpComplete
jsr ApplyGravity
lda #PLAYER_STATE_IDLE
jmp ChangePlayerState
;---------------------------------------JOYSTICK RIGHT @right lda PLAYER_SUBSTATE bne @animJumpRightEnd ldx #0 lda #sta ZEROPAGE_POINTER_1 lda #>ANIM_PLAYER_WALK_R sta ZEROPAGE_POINTER_1 + 1 jsr InitSpriteAnim ; initialize the animation lda #PLAYER_SUBSTATE_RUNNING ; set substate to RUNNING sta PLAYER_SUBSTATE rts
lda #PLAYER_STATE_WALK_R ; go to walk state right jmp ChangePlayerState
;---------------------------------------JOYSTICK LEFT @left lda PLAYER_SUBSTATE bne @animJumpLeftEnd ldx #0 lda #<ANIM_PLAYER_WALK_L sta ZEROPAGE_POINTER_1 lda #>ANIM_PLAYER_WALK_L sta ZEROPAGE_POINTER_1 + 1 jsr InitSpriteAnim ; initialize the animation lda #PLAYER_SUBSTATE_RUNNING ; set substate to RUNNING sta PLAYER_SUBSTATE rts
@animJumpLeftEnd
lda #PLAYER_STATE_IDLE jmp ChangePlayerState lda #PLAYER_STATE_WALK_L ; go to walk state left jmp ChangePlayerState
@animJumpRightEnd
lda #PLAYER_STATE_IDLE jmp ChangePlayerState lda #PLAYER_STATE_WALK_R ; go to walk state left jmp ChangePlayerState
@idle
lda #PLAYER_STATE_IDLE jmp ChangePlayerState
PlayerStatePunchR
;===================================================================================================
; STATE PUNCH RIGHT
;—————————————————————————————————
; IMPORTANT: Checks when the Player can Move LEFT or RIGHT. No other state or subroutine does this.
; The player is standing still and waiting input.
; Possible optimizations we are doublechecking CheckBlockUnder and CheckDown, we can check once
; and store those in a temp variable and look them up if needed.
;—————————————————————————————————
PlayerStatePunchR lda PLAYER_SUBSTATE ; Check for first entry to state bne @running ldx #0 lda #<ANIM_PLAYER_PUNCH_R ; load animation list in ZEROPAGE_POINTER_1 sta ZEROPAGE_POINTER_1 lda #>ANIM_PLAYER_PUNCH_R sta ZEROPAGE_POINTER_1 + 1 jsr InitSpriteAnim ; setup the animation for Idle lda PLAYER_SUBSTATE_RUNNING ; set the substate to Running sta PLAYER_SUBSTATE rts ; wait till next frame to start
@running ;------------------------------------------------------------ JOYSTICK INPUT jsr JoystickReady beq @input rts ; not ready for input, we return
@input ; process valid joystick input
@gravity
beq @joyCheck
jsr ApplyGravity ; Apply Gravity – if we are not falling
bne @joyCheck ; check the joystick input
@joyCheck lda JOY_X beq @idle ; if JOY_X is 0 we are idling and need to change states bmi @idle ; if negative we are idling
@doneJoy rts
@idle lda #0 sta SPRITE_ANIM_PLAY ; pause our animation lda #PLAYER_STATE_IDLE jmp ChangePlayerState
PlayerStatePunchL
;===================================================================================================
; STATE PUNCH RIGHT
;---------------------------------------------------------------------------------------------------
; IMPORTANT: Checks when the Player can Move LEFT or RIGHT. No other state or subroutine does this.
; The player is standing still and waiting input.
; Possible optimizations we are doublechecking CheckBlockUnder and CheckDown, we can check once
; and store those in a temp variable and look them up if needed.
;---------------------------------------------------------------------------------------------------
PlayerStatePunchL
lda PLAYER_SUBSTATE ; Check for first entry to state bne @running ldx #0 lda #<ANIM_PLAYER_PUNCH_L ; load animation list in ZEROPAGE_POINTER_1 sta ZEROPAGE_POINTER_1 lda #>ANIM_PLAYER_PUNCH_L sta ZEROPAGE_POINTER_1 + 1 jsr InitSpriteAnim ; setup the animation for Idle lda PLAYER_SUBSTATE_RUNNING ; set the substate to Running sta PLAYER_SUBSTATE rts ; wait till next frame to start
@running
;------------------------------------------------------------ JOYSTICK INPUT lda #1 sta SPRITE_ANIM_PLAY ; begin our animation when set to one jsr JoystickReady beq @input rts ; not ready for input, we return
@input
; process valid joystick input
@gravity
@joyCheck
lda JOY_X beq @idle ; if JOY_X is 0 we are idling and need to change states bmi @idle ; if negative we are idling
lda #PLAYER_STATE_IDLE
jmp ChangePlayerState
rts
@idle ; lda #PLAYER_STATE_IDLE ; jmp ChangePlayerState
PlayerStateKickR
;===================================================================================================
; STATE STAIRS RIGHT
;---------------------------------------------------------------------------------------------------
; Player state for climbing stairs
;---------------------------------------------------------------------------------------------------
PlayerStateKickR
lda PLAYER_SUBSTATE ; test for first run bne @running ;------------------------------------------------------- SETUP CODE GOES HERE ; TODO - some check to change to walking right animation ; if it's currently different
ldx #0 ; Use sprite number 0
lda #; load animation in ZEROPAGE_POINTER_1
sta ZEROPAGE_POINTER_1
lda #>ANIM_PLAYER_KICK_R
sta ZEROPAGE_POINTER_1 + 1
jsr InitSpriteAnim ; initialize the animation
lda #PLAYER_SUBSTATE_RUNNING ; set substate to RUNNING
sta PLAYER_SUBSTATE
rts ; state change goes into effect next frame
;—————————————————————————– @running
;———————————————————- JOYSTICK INPUT
jsr JoystickReady
beq @input ; not ready for input
rts
@input
lda JOY_X beq @vert_check ; X axis in 0 - check for up bmi @idle ; if it's -1 (left) return to idle ; so it has to be 1 (right) - climb the stair
@vert_check
; TO DO : check for an up press ;@climb lda #PLAYER_STATE_IDLE ; return to idle (which will likely go to fall) jmp ChangePlayerState
@idle
; lda #PLAYER_STATE_IDLE ; return to idle (which will likely go to fall) ; jmp ChangePlayerState rts
PlayerStateKickL
;=====================================================
; STATE STAIRS RIGHT
;---------------------------------------------------------------------------------------------------
; Player state for climbing stairs
;---------------------------------------------------------------------------------------------------
PlayerStateKickL
lda PLAYER_SUBSTATE ; test for first run
bne @running
;——————————————————- SETUP CODE GOES HERE
; TODO – some check to change to walking right animation
; if it’s currently different
ldx #0 ; Use sprite number 0
lda #<ANIM_PLAYER_KICK_L ; load animation in ZEROPAGE_POINTER_1
sta ZEROPAGE_POINTER_1
lda #>ANIM_PLAYER_KICK_L
sta ZEROPAGE_POINTER_1 + 1
jsr InitSpriteAnim ; initialize the animation
lda #PLAYER_SUBSTATE_RUNNING ; set substate to RUNNING
sta PLAYER_SUBSTATE
rts ; state change goes into effect next frame
;—————————————————————————–
@running
;———————————————————- JOYSTICK INPUT
jsr JoystickReady
beq @input ; not ready for input
rts
@input
lda JOY_X
beq @vert_check ; X axis in 0 – check for up
bmi @idle ; if it’s –1 (left) return to idle
; so it has to be 1 (right) – climb the stair
@vert_check ; TO DO : check for an up press
;@climb
;
; check for stair collider
; jsr MovePlayerRight ; attempt to move right
; lda COLLIDER_ATTR ; we can’t – because of a stair
; cmp #COLL_STAIR
; beq @go_up ; so go up instead
;
; lda #PLAYER_STATE_WALK_R ; else go back to walking (top of stair)
; jmp ChangePlayerState
;
;@go_up
; jsr MovePlayerUp
lda #PLAYER_STATE_IDLE ; return to idle (which will likely go to fall)
jmp ChangePlayerState
; rts @idle
; lda #PLAYER_STATE_IDLE ; return to idle (which will likely go to fall) ;
jmp ChangePlayerState
rts
PlayerStateFloating
;===================================================================================================
; STATE FLOATING
;---------------------------------------------------------------------------------------------------
PlayerStateFloating
lda PLAYER_SUBSTATE
bne @running
;------------------------------------------------------- SETUP CODE GOES HERE
lda #PLAYER_SUBSTATE_RUNNING ; set substate to RUNNING sta PLAYER_SUBSTATE rts ; wait till next frame to start
;—————————————————————————–
@running
jsr JoystickReady
beq @input
; Check creates the ‘fix’ pause for scroll resetting
rts
@input
lda JOY_Y
beq @end
bmi @up
bpl @down
lda JOY_X
beq @end
bmi @left
@right
lda #PLAYER_STATE_SWIM_R
jmp ChangePlayerState
;--------------------------------------------- JOYSTICK LEFT
@left
lda #PLAYER_STATE_SWIM_L
jmp ChangePlayerState
@up
ldx #0 jsr MovePlayerUp ; Move player one pixel across - A = move? 0 or 1 ldx #1 jsr MovePlayerUp rts
@down
ldx #0 jsr MovePlayerDown ; Move player one pixel across - A = move? 0 or 1 ldx #1 jsr MovePlayerDown rts
@end
lda #PLAYER_STATE_IDLE jmp ChangePlayerState
PlayerStateSwimR
;===================================================================================================
; STATE SWIM RIGHT
;---------------------------------------------------------------------------------------------------
PlayerStateSwimR
lda PLAYER_SUBSTATE
bne @running
;------------------------------------------------------- SETUP CODE GOES HERE
ldx #0 ; Use sprite number 0
lda #<ANIM_PLAYER_SWIM_R ; load animation in ZEROPAGE_POINTER_1
sta ZEROPAGE_POINTER_1
lda #>ANIM_PLAYER_SWIM_R
sta ZEROPAGE_POINTER_1 + 1
jsr InitSpriteAnim ; initialize the animation
lda #PLAYER_SUBSTATE_RUNNING ; set substate to RUNNING
sta PLAYER_SUBSTATE
rts
; wait till next frame to start
;—————————————————————————–
@running
lda #1 sta SPRITE_ANIM_PLAY ; begin our animation when set to one jsr JoystickReady beq @input ; Check creates the 'fix' pause for scroll resetting rts
@input
lda JOY_X
beq @idle
bpl @right
jmp @idle
@right
ldx #0 jsr MovePlayerRight ; Move player one pixel across - A = move? 0 or 1 ldx #1 jsr MovePlayerRight rts
lda #PLAYER_STATE_IDLE
jmp ChangePlayerState
@idle
lda #PLAYER_STATE_IDLE
jmp ChangePlayerState
@doneJoy
rts
PlayerStateSwimL
;===================================================================================================
; STATE SWIM LEFT
;---------------------------------------------------------------------------------------------------
PlayerStateSwimL
lda PLAYER_SUBSTATE
bne @running
;------------------------------------------------------- SETUP CODE GOES HERE
ldx #0 ; Use sprite number 0
lda #<ANIM_PLAYER_SWIM_L ; load animation in ZEROPAGE_POINTER_1
sta ZEROPAGE_POINTER_1
lda #>ANIM_PLAYER_SWIM_L
sta ZEROPAGE_POINTER_1 + 1
jsr InitSpriteAnim ; initialize the animation
lda #PLAYER_SUBSTATE_RUNNING ; set substate to RUNNING
sta PLAYER_SUBSTATE
rts
; wait till next frame to start
;—————————————————————————–
@running
lda #1
sta SPRITE_ANIM_PLAY ; begin our animation when set to one
jsr JoystickReady
beq @input ; Check creates the ‘fix’ pause for scroll resetting
rts
@input
lda JOY_X beq @idle bmi @left jmp @idle
@left
ldx #0 jsr MovePlayerLeft ; Move player one pixel across - A = move? 0 or 1 ldx #1 jsr MovePlayerLeft rts
lda #PLAYER_STATE_IDLE
jmp ChangePlayerState
@idle
lda #PLAYER_STATE_IDLE
jmp ChangePlayerState
@doneJoy
rts
PlayerState_Framework
;===================================================================================================
; STATE FRAMEWORK
;---------------------------------------------------------------------------------------------------
; A blank state template to make adding new states easier
;---------------------------------------------------------------------------------------------------
PlayerState_Framework
lda PLAYER_SUBSTATE ; test for first run bne @running
;------------------------------------------------------- SETUP CODE GOES HERE
;
ldx #0 ; Use sprite number 0 ; lda #<ANIM_TEST ; load animation in ZEROPAGE_POINTER_1 ; sta ZEROPAGE_POINTER_1 ; lda #>ANIM_TEST ; sta ZEROPAGE_POINTER_1 + 1 jsr InitSpriteAnim ; initialize the animation lda #PLAYER_SUBSTATE_RUNNING ; set substate to RUNNING sta PLAYER_SUBSTATE rts ; change takes effect next frame
;—————————————————————————–
@running
;---------------------------------------------------------- JOYSTICK INPUT jsr JoystickReady beq @input ; not ready for input rts
;————————————————————————–
; Process valid joystick input
@input
; lda JOY_X
; beq @vertCheck
; bmi @left
; bpl @right
; rts @right
@left @vertCheck
; lda JOY_Y
; beq @end
; bmi @up
; bpl @down
; rts
@up
@down
@end
;————————————————————————–
rts
;=================================================================================================== ; PLAYER DATA ;--------------------------------------------------------------------------------------------------- PLAYER_DATA PLAYER_STATE ; Current state - walking, standing, dying, climbing byte 0
PLAYER_SUBSTATE
byte 0 ; Current substate - jumping up, falling down, start dying
PLAYER_DIRECTION_X byte 0
PLAYER_DIRECTION_Y byte 0
PLAYER_FALLCOUNT byte 0 ; Counting frames to actual fall
PLAYER_JUMPUPRIGHT byte 0
PLAYER_JUMPUPLEFT byte 0
PLAYER_FALLFLAG byte 0 ; Jump table from Endurion's code sample: ;gamedeve.net/blog/949/entry-2250107-a-c64-game-step-7'
PLAYER_JUMP_POS
byte 0 PLAYER_JUMP_TABLE ;byte 8,7,5,3,2,1,1,1,0,0 byte 18,18,17,17,15,13,12,12,11,11,11,10,10 byte 8,8,7,7,5,5,3,3,2,2,1,1,1,0,0 JUMP_TABLE_SIZE byte 10 PLAYER_FALL_POS byte 0 FALL_SPEED_TABLE byte 1,1,2,2,3,3,3,3,3,3 PLAYER_TIMER byte 0 PLAYER_TIMER2 byte 0 PLAYER_SPEED byte 0
[…] we arrive at subroutine (PlayerSetup). This area is used to set screen colors, sprite colors (also multicolors). It also sets up the X […]
[…] Previous Next […]