WIP player movement

This commit is contained in:
Rob McMullen 2017-07-20 09:48:26 -07:00
parent 5e7a46c5ff
commit c5882e7622
7 changed files with 460 additions and 61 deletions

View File

@ -1,6 +1,8 @@
level_enemies .byte 55, 4, 5, 6, 7, 8 ;# level starts counting from 1, so dummy zeroth level info
level_speeds .byte 255, 200, 210, 220, 230, 240 ;# increment of fractional pixel per game frame
player_score_row .byte 2, 7, 12, 17
player_score_l .byte 0, 0, 0, 0
player_score_h .byte 0, 0, 0, 0
;# sprites all use the same table. In the sample configuration, sprites 0 - 3
@ -20,10 +22,43 @@ AMIDAR_TYPE = 2
actor_type .byte PLAYER_TYPE, PLAYER_TYPE, PLAYER_TYPE, PLAYER_TYPE
.byte ORBITER_TYPE
.byte AMIDAR_TYPE, AMIDAR_TYPE, AMIDAR_TYPE, AMIDAR_TYPE, AMIDAR_TYPE, AMIDAR_TYPE
actor_active .byte 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, $ff
actor_init_func_l .byte <init_player, <init_orbiter, <init_amidar
actor_init_func_h .byte >init_player, >init_orbiter, >init_amidar
; Sprite data is interleaved so a simple indexed mode can be used. This is not
; convenient to set up but makes faster accessing because you don't have to
; increment the index register. For example, all the info about sprite #2 can
; be indexed using Y = 2 on the indexed operators, e.g. "lda sprite_active,y",
; "lda sprite_x,y", etc.
;
; Number of sprites must be a power of 2
actor_active .byte 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 , $ff ; 1 = active, 0 = skip
actor_l
.byte <APPLE_SPRITE9X11, <APPLE_SPRITE9X11, <APPLE_SPRITE9X11, <APPLE_SPRITE9X11
.byte <APPLE_SPRITE9X11, <APPLE_SPRITE9X11, <APPLE_SPRITE9X11, <APPLE_SPRITE9X11
.byte <APPLE_SPRITE9X11, <APPLE_SPRITE9X11, <APPLE_SPRITE9X11, <APPLE_SPRITE9X11
.byte <APPLE_SPRITE9X11, <APPLE_SPRITE9X11, <APPLE_SPRITE9X11, <APPLE_SPRITE9X11
actor_h
.byte >APPLE_SPRITE9X11, >APPLE_SPRITE9X11, >APPLE_SPRITE9X11, >APPLE_SPRITE9X11
.byte >APPLE_SPRITE9X11, >APPLE_SPRITE9X11, >APPLE_SPRITE9X11, >APPLE_SPRITE9X11
.byte >APPLE_SPRITE9X11, >APPLE_SPRITE9X11, >APPLE_SPRITE9X11, >APPLE_SPRITE9X11
.byte >APPLE_SPRITE9X11, >APPLE_SPRITE9X11, >APPLE_SPRITE9X11, >APPLE_SPRITE9X11
actor_x
.byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 , $ff
actor_y
.byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 , $ff
; [i*7 for i in range(40)]
player_col_to_x .byte 0, 7, 14, 21, 28, 35, 42, 49, 56, 63, 70, 77, 84, 91, 98, 105, 112, 119, 126, 133, 140, 147, 154, 161, 168, 175, 182, 189, 196, 203, 210, 217, 224, 231, 238, 245, 252, 259, 266, 273
; [i*8 for i in range(24)]
player_row_to_y .byte 0, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 88, 96, 104, 112, 120, 128, 136, 144, 152, 160, 168, 176, 184
STARTING_LIVES = 3
BONUS_LIFE = 10000
MAX_LIVES = 8
@ -44,8 +79,22 @@ GAME_OVER = 255
;
;# Scores
;
DOT_SCORE = 10
PAINT_SCORE_PER_LINE = 100
DOT_SCORE = 1
PAINT_SCORE_PER_LINE = 10
add_score nop
sed
clc
adc player_score_l,x
sta player_score_l,x
lda player_score_h,x
adc #0
sta player_score_h,x
cld
rts
; level number in X, clobbers
init_level nop
@ -186,6 +235,9 @@ init_player nop
sta player_lives,x
lda #BONUS_LIFE
sta player_next_target_score,x
lda #0
sta player_score_l
sta player_score_h
rts
@ -232,7 +284,7 @@ init_actors nop
sta current_actor
init_actors_loop inc current_actor
ldx current_actor
lda actor_status,x
lda actor_active,x
bpl ?2 ; negative = end
rts
?2 beq init_actors_loop ; zero = skip

View File

@ -1,24 +1,3 @@
; ##### Collision detection
;
; # Check possible collisions between the current player and any enemies
; def check_collisions():
; r = actor_row[zp.current_actor]
; c = actor_col[zp.current_actor]
; enemy_index = FIRST_AMIDAR
; while enemy_index <= zp.last_enemy:
; # Will provide pac-man style bug where they could pass through each
; # other because it's only checking tiles
; if actor_row[enemy_index] == r and actor_col[enemy_index] == c:
; start_exploding()
; break
; enemy_index += 1
;
; def start_exploding():
; actor_status[zp.current_actor] = PLAYER_EXPLODING
; actor_frame_counter[zp.current_actor] = EXPLODING_TIME
;
;
; ##### Scoring routines
;
; def check_dots():
; r = actor_row[zp.current_actor]
@ -32,6 +11,38 @@
; addr[c] &= ~TILE_DOT
;
; player_score[zp.current_actor] += DOT_SCORE
check_dots nop
lda actor_row,x
sta r
lda actor_col,x
sta c
jsr has_dot
beq ?1
lda r
sta dot_eaten_row,x
lda c
sta dot_eaten_col,x
ldy r
jsr mazerow
ldy c
lda (mazeaddr),y
and #CLEAR_TILE_DOT
sta (mazeaddr),y
; update damage! Needs to update both screens
jsr damage_maze
lda #DOT_SCORE
jsr add_score
?1 rts
; update both screens!
damage_maze nop
rts
;
; def update_background():
; zp.current_actor = 0

23
debug.s
View File

@ -6,3 +6,26 @@ debugtext nop
cmp #$A0 ; space?
bne ?1
rts
printhex ; A = hex byte, X = column, Y = row; A is clobbered, X&Y are not
pha
stx param_x
lsr
lsr
lsr
lsr
tax
lda hexdigit,x
ldx param_x
jsr fastfont
pla
and #$0f
tax
lda hexdigit,x
ldx param_x
inx
jsr fastfont
rts
hexdigit .byte "0123456789ABCDEF"

129
logic.s
View File

@ -60,12 +60,30 @@ TITLE_SCREEN_TIME = 100
; addr = mazerow(r)
; allowed = addr[c] & DIR_MASK
; return allowed
;
get_allowed_dirs nop
ldy r
jsr mazerow
ldy c
lda (mazeaddr),y
and #DIR_MASK
sta allowed
rts
; # See if current tile has a dot
; def has_dot(r, c):
; addr = mazerow(r)
; return addr[c] & TILE_DOT
;
has_dot nop
ldy r
jsr mazerow
ldy c
lda (mazeaddr),y
and #TILE_DOT
rts
; # clear a dot
; def clear_dot(r, c):
; addr = mazerow(r)
@ -84,6 +102,30 @@ TITLE_SCREEN_TIME = 100
; else:
; logic_log.error("bad direction % dir")
; return r, c
get_next_tile nop
lda actor_dir,x
sta scratch_0
and #TILE_UP
beq ?down
dec r
rts
?down lda scratch_0
and #TILE_DOWN
beq ?left
inc r
rts
?left lda scratch_0
and #TILE_LEFT
beq ?right
dec c
rts
?right lda scratch_0
and #TILE_RIGHT
beq ?end
inc c
?end rts
;
; # Choose a target column for the next up/down direction at a bottom or top T
; def get_next_round_robin(rr_table, x):
@ -124,10 +166,16 @@ TITLE_SCREEN_TIME = 100
; else:
; sub = actor_xpixel[zp.current_actor]
; return sub == X_MIDPOINT
;
; # Move enemy given the enemy index
; def move_enemy():
move_enemy nop
; current = actor_dir[zp.current_actor]
lda actor_dir,x
sta current
;
; # check sub-pixel location to see if we've reached a decision point
; temp = check_midpoint(current)
@ -156,6 +204,8 @@ TITLE_SCREEN_TIME = 100
; decide_orbiter()
; else:
; decide_direction()
rts
;
; def pixel_move(current):
; if current & TILE_UP:
@ -340,21 +390,40 @@ set_speed nop
; actor_updown[zp.current_actor] = updown
; actor_dir[zp.current_actor] = current
; set_speed(current)
;
; def move_player():
move_player nop
; r = actor_row[zp.current_actor]
; c = actor_col[zp.current_actor]
lda actor_row,x
sta r
lda actor_col,x
sta c
; allowed = get_allowed_dirs(r, c)
jsr get_allowed_dirs
; current = actor_dir[zp.current_actor]
lda actor_dir,x
sta current
; d = actor_input_dir[zp.current_actor]
lda actor_input_dir,x
sta d
; pad.addstr(26, 0, "r=%d c=%d allowed=%s d=%s current=%s " % (r, c, str_dirs(allowed), str_dirs(d), str_dirs(current)))
; if d:
beq ?end
; if allowed & d:
and allowed
beq ?illegal
; # player wants to go in an allowed direction, so go!
; actor_dir[zp.current_actor] = d
; r, c = get_next_tile(r, c, d)
; actor_row[zp.current_actor] = r
; actor_col[zp.current_actor] = c
lda d
sta actor_dir,x
jmp ?continue
; else:
; # player wants to go in an illegal direction. instead, continue in
; # direction that was last requested
@ -363,6 +432,32 @@ set_speed nop
; r, c = get_next_tile(r, c, current)
; actor_row[zp.current_actor] = r
; actor_col[zp.current_actor] = c
?illegal lda allowed
and current
bne ?continue
rts
?continue jsr get_next_tile
lda r
sta actor_row,x
lda c
sta actor_col,x
; update pixel position
ldy r
lda player_row_to_y,y
clc
adc actor_ypixel,x
sta actor_y,x
ldy c
lda player_col_to_x,y
clc
adc actor_xpixel,x
sta actor_x,x
?end
rts
;
;
; ##### Collision detection
@ -379,8 +474,32 @@ set_speed nop
; start_exploding()
; break
; enemy_index += 1
;
check_collisions nop
lda actor_row,x
sta r
lda actor_col,x
sta c
ldy #FIRST_AMIDAR-1
?enemy iny
lda actor_active,y
bmi end_collisions ; negative = end
beq ?enemy ; zero = skip
lda actor_row,y
cpy r
beq start_exploding
lda actor_col,y
cpy c
bne ?enemy
; def start_exploding():
; actor_status[zp.current_actor] = PLAYER_EXPLODING
; actor_frame_counter[zp.current_actor] = EXPLODING_TIME
start_exploding lda #PLAYER_EXPLODING
sta actor_status,x
lda #EXPLODING_TIME
sta actor_frame_counter,x
end_collisions rts

5
maze.s
View File

@ -8,6 +8,7 @@ TILE_HORZ = TILE_LEFT|TILE_RIGHT
TILE_VERT = TILE_UP|TILE_DOWN
DIR_MASK = $0f
TILE_DOT = $10
CLEAR_TILE_DOT = %11101111
LEFT_TILE = TILE_DOT|TILE_RIGHT
MIDDLE_TILE = TILE_DOT|TILE_LEFT|TILE_RIGHT
@ -456,6 +457,10 @@ finish_boxes nop
; level_boxes[x] = 0 # Set flag so we don't check this box again
;
; x += 3
check_boxes nop
rts
;
;def mark_box_for_painting(r1, r2, c):
; box_log.debug("Marking box, player $%d @ %d,%d -> %d,%d" % (zp.current_actor, r1, c, r2, c + BOX_WIDTH))

View File

@ -243,8 +243,6 @@ renderstart
ldy #0
sty damageindex
lda #sprite_l - sprite_active
sta param_count
inc renderroundrobin_smc+1
renderroundrobin_smc
@ -253,17 +251,18 @@ renderroundrobin_smc
renderloop
lda param_index
and #sprite_l - sprite_active - 1
and #actor_l - actor_active - 1
tay
lda sprite_active,y
lda actor_active,y
beq renderskip ; skip if zero
lda sprite_l,y
bmi renderend ; end if negative
lda actor_l,y
sta jsrsprite_smc+1
lda sprite_h,y
lda actor_h,y
sta jsrsprite_smc+2
lda sprite_x,y
lda actor_x,y
sta param_x
lda sprite_y,y
lda actor_y,y
sta param_y
jmp jsrsprite_smc
jsrsprite_smc
@ -304,27 +303,7 @@ renderend
rts
damage_text nop
rts
; Sprite data is interleaved so a simple indexed mode can be used. This is not
; convenient to set up but makes faster accessing because you don't have to
; increment the index register. For example, all the info about sprite #2 can
; be indexed using Y = 2 on the indexed operators, e.g. "lda sprite_active,y",
; "lda sprite_x,y", etc.
;
; Number of sprites must be a power of 2
sprite_active
.byte 1, 1, 1, 1, 1, 1, 1, 1 ; 1 = active, 0 = skip
sprite_l
.byte <APPLE_SPRITE9X11, <APPLE_SPRITE9X11, <APPLE_SPRITE9X11, <APPLE_SPRITE9X11, <APPLE_SPRITE9X11, <APPLE_SPRITE9X11, <APPLE_SPRITE9X11, <APPLE_SPRITE9X11
sprite_h
.byte >APPLE_SPRITE9X11, >APPLE_SPRITE9X11, >APPLE_SPRITE9X11, >APPLE_SPRITE9X11, >APPLE_SPRITE9X11, >APPLE_SPRITE9X11, >APPLE_SPRITE9X11, >APPLE_SPRITE9X11
sprite_x
.byte 80, 164, 33, 45, 4, 9, 180, 18
sprite_y
.byte 116, 126, 40, 60, 80, 100, 9, 140

212
working.s
View File

@ -70,10 +70,16 @@ box_row_save .ds 1
box_col_save .ds 1
maze_gen_col .ds 1
config_num_players .ds 1
config_quit .ds 1
frame_count .ds 2
countdown_time .ds 1
still_alive .ds 1
*= $50
current_actor .ds 1
current_dir .ds 1
current .ds 1 ; current direction
allowed .ds 1 ; allowed directions
d .ds 1 ; actor input dir
r .ds 1
c .ds 1
round_robin_index .ds 2
@ -100,6 +106,7 @@ debug_a .ds 1
debug_x .ds 1
debug_y .ds 1
debug_last_key .ds 1
frame_count .ds 2
*= $6000
@ -144,17 +151,220 @@ init_game nop
lda #1
sta config_num_players
jsr init_actors
lda #0
sta frame_count
sta frame_count+1
sta countdown_time
sta config_quit
rts
game_loop nop
inc frame_count
bne ?1
inc frame_count+1
?1 jsr userinput
lda config_quit
beq ?2
rts
?2 lda #FIRST_AMIDAR-1
sta current_actor
?enemy inc current_actor
ldx current_actor
lda actor_active,x
bpl ?player ; negative = end
beq ?enemy ; zero = skip
jsr move_enemy
jmp ?enemy
?player lda #0
sta still_alive
lda #$ff
sta current_actor
?p1 inc current_actor
ldx current_actor
lda actor_type,x
cmp #PLAYER_TYPE
bne ?alive
lda actor_active,x
beq ?p1 ; zero = skip
jsr handle_player
jmp ?p1
?alive lda still_alive
bne ?draw
dec countdown_time
bne ?draw
rts
; erase_sprites()
; update_background()
; draw_actors()
; show_screen()
?draw jsr restorebg_driver
jsr renderstart
jsr pageflip
jsr wait
jmp game_loop
handle_player nop
; if actor_status[zp.current_actor] == PLAYER_REGENERATING:
; # If regenerating, change to alive if the player starts to move
; if actor_input_dir[zp.current_actor] > 0:
; actor_status[zp.current_actor] = PLAYER_ALIVE
lda actor_status,x
cmp #PLAYER_REGENERATING
bne ?alive
lda actor_input_dir,x
beq ?final
lda #PLAYER_ALIVE
sta actor_status,x
; if actor_status[zp.current_actor] == PLAYER_ALIVE:
; # only move and check collisions if alive
; move_player()
; check_collisions()
?alive lda actor_status,x
cmp #PLAYER_ALIVE
bne ?dots
jsr move_player
jsr check_collisions
; if actor_status[zp.current_actor] == PLAYER_ALIVE:
; # only check for points if still alive
; check_dots()
; check_boxes()
?dots lda actor_status,x
cmp #PLAYER_ALIVE
bne ?final
jsr check_dots
jsr check_boxes
; if actor_status[zp.current_actor] != GAME_OVER:
; still_alive += 1
; zp.current_actor += 1
?final lda actor_status,x
cmp #GAME_OVER
beq ?end
inc still_alive
?end rts
userinput
lda KEYBOARD
pha
ldx #38
ldy #22
jsr printhex
pla
bpl input_not_movement ; stop movement of player if no direction input
; setting the keyboard strobe causes the key to enter repeat mode if held
; down, which causes a pause after the initial movement. Not setting the
; strobe allows smooth movement from the start, but there's no way to stop
;sta KBDSTROBE
ldx #0
check_up cmp #$8d ; up arrow
beq input_up
cmp #$c9 ; I
bne check_down
input_up lda #TILE_UP
sta actor_input_dir,x
rts
check_down cmp #$af ; down arrow
beq input_down
cmp #$d4 ; K
bne check_left
input_down lda #TILE_DOWN
sta actor_input_dir,x
rts
check_left cmp #$88 ; left arrow
beq input_left
cmp #$c8 ; J
bne check_right
input_left lda #TILE_LEFT
sta actor_input_dir,x
rts
check_right cmp #$95 ; right arrow
beq input_right
cmp #$ce ; L
bne input_not_movement
input_right lda #TILE_RIGHT
sta actor_input_dir,x
rts
input_not_movement lda #0
sta actor_input_dir,x
check_special cmp #$80 + 32
beq input_space
cmp #$80 + '.'
beq input_period
cmp #$80 + 'P'
beq input_period
rts
input_space
jmp debugflipscreens
input_period
jsr wait
lda KEYBOARD
bpl input_period
cmp #$80 + 'P'
beq input_period
rts
debugflipscreens
lda #20
sta scratch_count
debugloop
jsr pageflip
jsr wait
jsr pageflip
jsr wait
dec scratch_count
bne debugloop
rts
wait
ldy #$06 ; Loop a bit
wait_outer
ldx #$ff
wait_inner
nop
nop
nop
nop
nop
nop
nop
dex
bne wait_inner
dey
bne wait_outer
rts
.include "working-sprite-driver.s"
.include "rand.s"
.include "screen.s"
.include "maze.s"
.include "actors.s"
.include "logic.s"
.include "background.s"
.include "debug.s"
; vars must be last