add directional characters display

This commit is contained in:
2026-05-01 21:13:55 +02:00
parent 425b83b1bb
commit 8b3b2aa20d
23 changed files with 417 additions and 283 deletions

View File

@@ -2,18 +2,3 @@ pub const game.direction_up = 0
pub const game.direction_right = 1
pub const game.direction_down = 2
pub const game.direction_left = 3
pub const game.direction_still = 4
/*
; 1_000_000_000 nano second = 0x0000_0000_3B9A_CA00
pub const game.tick_duration_0 = 0xCA00
pub const game.tick_duration_1 = 0x3B9A
pub const game.tick_duration_2 = 0x0000
pub const game.tick_duration_3 = 0x0000
*/
; 0.5 second = 500_000_000 nano second = 0x0000_0000_1DCD_6500
pub const game.tick_duration_0 = 0x6500
pub const game.tick_duration_1 = 0x1DCD
pub const game.tick_duration_2 = 0x0000
pub const game.tick_duration_3 = 0x0000

View File

@@ -7,12 +7,23 @@ pub const sprites.rotation_90 = 1
pub const sprites.rotation_180 = 2
pub const sprites.rotation_270 = 3
pub const sprites.empty = 0
pub const sprites.empty = 0 ; must stay 0 (some code avoid addition when it knows the tile is empty)
pub const sprites.unimplemented = 1
pub const sprites.wall_end = 2
pub const sprites.wall_straight = 3
pub const sprites.wall_corner = 4
pub const sprites.robot = 5
pub const sprites.ghost = 6
pub const sprites.coin = 7
pub const sprites.max = 7 ; for lookup table
pub const sprites.robot_up = 5
pub const sprites.robot_right = 6
pub const sprites.robot_down = 7
pub const sprites.robot_left = 8
pub const sprites.ghost = 9
pub const sprites.ghost_up = 9
pub const sprites.ghost_right = 10
pub const sprites.ghost_down = 11
pub const sprites.ghost_left = 12
pub const sprites.coin = 13
pub const sprites.max = 13 ; for lookup table

View File

@@ -41,6 +41,58 @@ pub drawing.draw_whole_map:
ret
/* Draw the tile corresponding to the given coordinate with it's map content
Inputs:
r1, r2: Map coordinates x, y
Locals:
r3: tile value / sprite id / sprite address offset
r9: pointer
r13: screen address
*/
pub drawing.clear_tile:
push r1
push r2
push r3
push r9
push r13
add r9, r1, map
push r2
pub drawing.clear_tile_row_loop:
cmp r2, 0
je drawing.clear_tile_row_loop_end
sub r2, r2, 1
add r9, r9, map.width
jmp drawing.clear_tile_row_loop
pub drawing.clear_tile_row_loop_end:
pop r2
load_8 r3, [r9]
cmp r3, map.tiles.coin
add r9, zr, ptr.textures_addresses
jne drawing.clear_tile_get_screen_address
; coin
mov r3, sprites.coin
lsl r3, r3, arch.instruction_increment_shift
add r9, r9, r3
pub drawing.clear_tile_get_screen_address:
call get_tile_address
mov r1, r13
load_32 r2, [r9]
mov r3, sprites.rotation_0
call draw_sprite
pop r13
pop r9
pop r3
pop r2
pop r1
ret
/* Return the top-left pixel address of the tile at the given map coordinates
Inputs:
@@ -100,6 +152,7 @@ get_tile_address:
pop r3
ret
/* Get address of given sprite id
Inputs:

18
src/lib/u64.asm Normal file
View File

@@ -0,0 +1,18 @@
/* Add two unsigned 64 bit
Input:
r1, r2: A.high, A.low
r3, r4: B.high, B.low
Output:
r5, r6: C.high, C.low
*/
pub u64.add:
add r5, r1, r3
add r6, r2, r4
cmp r6, r2
jae u64.add_no_low_overflow
add r5, r5, 1 ; overflow
pub u64.add_no_low_overflow:
ret

View File

@@ -17,10 +17,34 @@ include sections/init_timers
game_loop:
include sections/handle_event
include sections/characters_movement
/*
For all timers:
r1, r2: tick duration high, low
r7, r8: now high, low
*/
add r9, zr, ptr.tick_duration_high
load_32 r1, [r9]
add r9, zr, ptr.tick_duration_low
load_32 r2, [r9]
time_0 r8
time_1 r7
push r1
push r2
push r7
push r8
include sections/timer_robot
pop r8
pop r7
pop r2
pop r1
include sections/timer_ghost
jmp game_loop
include lib/u64
include lib/game
include lib/drawing
include lib/sprite_rotation
@@ -30,8 +54,14 @@ include dist/placeholder
include dist/wall_end
include dist/wall_straight
include dist/wall_corner
include dist/robot
include dist/ghost
include dist/robot_up
include dist/robot_right
include dist/robot_down
include dist/robot_left
include dist/ghost_up
include dist/ghost_right
include dist/ghost_down
include dist/ghost_left
include dist/coin
include dist/map

View File

@@ -5,8 +5,14 @@ U32 0 ; placeholder
U32 0 ; wall_end
U32 0 ; wall_straight
U32 0 ; wall_corner
U32 0 ; robot
U32 0 ; ghost
U32 0 ; robot up
U32 0 ; robot right
U32 0 ; robot down
U32 0 ; robot left
U32 0 ; ghost up
U32 0 ; ghost right
U32 0 ; ghost down
U32 0 ; ghost left
U32 0 ; coin
; 0.5 second = 500_000_000 nano second = 0x0000_0000_1DCD_6500
@@ -17,8 +23,11 @@ pub ptr.tick_duration_low: U32 0x1DCD_6500
; pub ptr.tick_duration_high: U32 0x0000_0000
; pub ptr.tick_duration_low: U32 0x3B9A_CA00
pub ptr.next_tick_high: U32 0
pub ptr.next_tick_low: U32 0
pub ptr.timer_robot_next_tick_high: U32 0x0000_0000
pub ptr.timer_robot_next_tick_low: U32 0x1DCD_6500
pub ptr.timer_ghost_next_tick_high: U32 0
pub ptr.timer_ghost_next_tick_low: U32 0
pub ptr.state_robot:
U8 0 ; x coord

View File

@@ -1,231 +0,0 @@
/* Elapsed time check
r1: address
r2: now low / delay low
r3: now high / delay high
r4: next tick low
r5: next tick high
*/
time_0 r2
time_1 r3
add r1, zr, ptr.next_tick_low
load_32 r4, [r1]
add r1, zr, ptr.next_tick_high
load_32 r5, [r1]
cmp r3, r5
jb game_loop
ja update_next_tick
cmp r2, r4
jb game_loop
update_next_tick:
add r1, zr, ptr.tick_duration_low
load_32 r2, [r1]
add r1, zr, ptr.tick_duration_high
load_32 r3, [r1]
add r4, r4, r2
add r5, r5, r3
cmp r4, r2
jae store_next_tick
add r5, r5, 1
store_next_tick:
add r1, zr, ptr.next_tick_low
store_32 [r1], r4
add r1, zr, ptr.next_tick_high
store_32 [r1], r5
/* Robot movement
r1 = robot's state address
r2 = x
r3 = y
r4 = direction
r5 = new x
r6 = new y
r7 = new position address
r8 = new position content
r9 = jump address
*/
add r1, zr, ptr.state_robot
load_8 r2, [r1]
add r1, r1, 1
load_8 r3, [r1]
add r1, r1, 1
load_8 r4, [r1]
mov r5, r2
mov r6, r3
lsl r9, r4, 3 ; 2 * instruction size = 8
add r9, r9, game_loop_robot_movement_jump_table_start
jmp r9
game_loop_robot_movement_jump_table_start:
; direction_up
sub r6, r6, 1
jmp game_loop_robot_movement_try_move
; direction_right
add r5, r5, 1
jmp game_loop_robot_movement_try_move
; direction_down
add r6, r6, 1
jmp game_loop_robot_movement_try_move
; direction_left
sub r5, r5, 1
jmp game_loop_robot_movement_try_move
; direction_still
jmp game_loop_robot_movement_none
game_loop_robot_movement_try_move:
push r2
mov r1, r5
mov r2, r6
call game.get_tile_address_from_map_coord
mov r7, r13
pop r2
/*
Collision handling
*/
load_8 r8, [r7]
cmp r8, map.tiles.wall
jne game_loop_robot_movement_some
; hit wall
add r1, zr, ptr.state_robot
add r1, r1, 2
mov r4, game.direction_still
store_8 [r1], r4
jmp game_loop_robot_movement_none
game_loop_robot_movement_some:
; TODO: handle coin and empty differently
mov r8, map.tiles.empty
store_8 [r7], r8
add r1, zr, ptr.state_robot
store_8 [r1], r5
add r1, r1, 1
store_8 [r1], r6
; clear old position
mov r1, r2
mov r2, r3
mov r3, sprites.rotation_0
mov r4, sprites.empty
call drawing.draw_sprite_at_map_coord
; draw robot on new position
mov r1, r5
mov r2, r6
mov r3, sprites.rotation_0
mov r4, sprites.robot
call drawing.draw_sprite_at_map_coord
game_loop_robot_movement_none:
/* Ghost movement
r1: ghost's state address
r2: x
r3: y
r4: direction
r5: x increment
r6: y increment
r7: new x
r8: new y
r9: new position address
r10: new position content
r11: jump address
*/
add r1, zr, ptr.state_ghost
load_8 r2, [r1]
add r1, r1, 1
load_8 r3, [r1]
add r1, r1, 1
load_8 r4, [r1]
mov r5, 0
mov r6, 0
lsl r11, r4, 3 ; 2 * instruction size = 8
add r11, r11, game_loop_ghost_movement_jump_table_start
jmp r11
game_loop_ghost_movement_jump_table_start:
; direction_up
sub r6, r6, 1
jmp game_loop_ghost_movement_make_move
; direction_right
add r5, r5, 1
jmp game_loop_ghost_movement_make_move
; direction_down
add r6, r6, 1
jmp game_loop_ghost_movement_make_move
; direction_left
sub r5, r5, 1
;jmp game_loop_ghost_movement_make_move
; direction_still (should never happen)
game_loop_ghost_movement_make_move:
add r7, r2, r5
add r8, r3, r6
add r1, zr, ptr.state_ghost
store_8 [r1], r7
add r1, r1, 1
store_8 [r1], r8
; get tile at previous position
push r2
mov r1, r2
mov r2, r3
call game.get_tile_address_from_map_coord
mov r9, r13
pop r2
; draw tile at previous position
load_8 r1, [r9]
cmp r1, map.tiles.coin
je game_loop_ghost_movement_old_tile_coin
; old tile empty
mov r4, sprites.empty
jmp game_loop_ghost_movement_draw_old_tile
game_loop_ghost_movement_old_tile_coin:
mov r4, sprites.coin
game_loop_ghost_movement_draw_old_tile:
mov r1, r2
mov r2, r3
mov r3, sprites.rotation_0
call drawing.draw_sprite_at_map_coord
; draw ghost on new position
mov r1, r7
mov r2, r8
mov r3, sprites.rotation_0
mov r4, sprites.ghost
call drawing.draw_sprite_at_map_coord
/*
Check ahead for direction change
*/
add r1, r7, r5
add r2, r8, r6
call game.get_tile_address_from_map_coord
load_8 r10, [r13]
cmp r10, map.tiles.wall
jne game_loop_ghost_movement_end
; increment direction
add r1, zr, ptr.state_ghost
add r1, r1, 2
load_8 r4, [r1]
add r4, r4, 1
and r4, r4, 0b11 ; modulo 3
store_8 [r1], r4
game_loop_ghost_movement_end:

View File

@@ -13,5 +13,5 @@ add r6, r6, 1
store_8 [r6], r5
mov r3, sprites.rotation_0
mov r4, sprites.ghost
mov r4, sprites.ghost_down
call drawing.draw_sprite_at_map_coord

View File

@@ -13,5 +13,5 @@ add r6, r6, 1
store_8 [r6], r5
mov r3, sprites.rotation_0
mov r4, sprites.robot
mov r4, sprites.robot_down
call drawing.draw_sprite_at_map_coord

View File

@@ -35,18 +35,57 @@ lsl r2, r1, arch.instruction_increment_shift
add r2, r2, ptr.textures_addresses
add r3, zr, sprite_wall_corner
store_32 [r2], r3
; sprite_robot
add r1, zr, sprites.robot
; sprite_robot_up
add r1, zr, sprites.robot_up
lsl r2, r1, arch.instruction_increment_shift
add r2, r2, ptr.textures_addresses
add r3, zr, sprite_robot
add r3, zr, sprite_robot_up
store_32 [r2], r3
; sprite_ghost
add r1, zr, sprites.ghost
; sprite_robot_right
add r1, zr, sprites.robot_right
lsl r2, r1, arch.instruction_increment_shift
add r2, r2, ptr.textures_addresses
add r3, zr, sprite_ghost
add r3, zr, sprite_robot_right
store_32 [r2], r3
; sprite_robot_down
add r1, zr, sprites.robot_down
lsl r2, r1, arch.instruction_increment_shift
add r2, r2, ptr.textures_addresses
add r3, zr, sprite_robot_down
store_32 [r2], r3
; sprite_robot_left
add r1, zr, sprites.robot_left
lsl r2, r1, arch.instruction_increment_shift
add r2, r2, ptr.textures_addresses
add r3, zr, sprite_robot_left
store_32 [r2], r3
; sprite_ghost_up
add r1, zr, sprites.ghost_up
lsl r2, r1, arch.instruction_increment_shift
add r2, r2, ptr.textures_addresses
add r3, zr, sprite_ghost_up
store_32 [r2], r3
; sprite_ghost_right
add r1, zr, sprites.ghost_right
lsl r2, r1, arch.instruction_increment_shift
add r2, r2, ptr.textures_addresses
add r3, zr, sprite_ghost_right
store_32 [r2], r3
; sprite_ghost_down
add r1, zr, sprites.ghost_down
lsl r2, r1, arch.instruction_increment_shift
add r2, r2, ptr.textures_addresses
add r3, zr, sprite_ghost_down
store_32 [r2], r3
; sprite_ghost_left
add r1, zr, sprites.ghost_left
lsl r2, r1, arch.instruction_increment_shift
add r2, r2, ptr.textures_addresses
add r3, zr, sprite_ghost_left
store_32 [r2], r3
; sprite_coin
add r1, zr, sprites.coin
lsl r2, r1, arch.instruction_increment_shift

View File

@@ -1,18 +1,34 @@
add r1, zr, ptr.tick_duration_low
load_32 r2, [r1]
add r1, zr, ptr.tick_duration_high
load_32 r3, [r1]
/*
r1, r2: now high, low
r3, r4: initial delay high, low
r5, r6: next tick high, low
r7: pointer
*/
time_0 r2
time_1 r1
time_0 r4
time_1 r5
add r4, r4, r2
add r5, r5, r3
cmp r4, r2
jae init_store_next_tick
add r5, r5, 1 ; overflow
; Robot
add r7, zr, ptr.timer_robot_next_tick_high
load_32 r3, [r7]
add r7, zr, ptr.timer_robot_next_tick_low
load_32 r4, [r7]
init_store_next_tick:
add r1, zr, ptr.next_tick_low
store_32 [r1], r4
add r1, zr, ptr.next_tick_high
store_32 [r1], r5
call u64.add
add r7, zr, ptr.timer_robot_next_tick_high
store_32 [r7], r5
add r7, zr, ptr.timer_robot_next_tick_low
store_32 [r7], r6
; Ghost
add r7, zr, ptr.timer_ghost_next_tick_high
load_32 r3, [r7]
add r7, zr, ptr.timer_ghost_next_tick_low
load_32 r4, [r7]
call u64.add
add r7, zr, ptr.timer_ghost_next_tick_high
store_32 [r7], r5
add r7, zr, ptr.timer_ghost_next_tick_low
store_32 [r7], r6

View File

@@ -0,0 +1,99 @@
/* Timer comparison / update
r1, r2: tick duration high, low [IN]
r3, r4: next tick high, low
r5, r6: tick after this one high, low
r7, r8: now high, low [IN]
r9: pointer
*/
add r9, zr, ptr.timer_ghost_next_tick_high
load_32 r3, [r9]
add r9, zr, ptr.timer_ghost_next_tick_low
load_32 r4, [r9]
cmp r7, r3
jb timer_ghost.end
ja timer_ghost.trigger
cmp r8, r4
jb timer_ghost.end
pub timer_ghost.trigger:
; udate next_tick
call u64.add
add r9, zr, ptr.timer_ghost_next_tick_high
store_32 [r9], r5
add r9, zr, ptr.timer_ghost_next_tick_low
store_32 [r9], r6
/* Movement
r1, r2: x, y
r3: rotation
r4: direction / sprite id
r5, r6: increments x, y
r7, r8: [RESERVED]
r9: pointer
r10: tile content
r13: tile address
*/
add r9, zr, ptr.state_ghost
load_8 r1, [r9]
add r9, r9, 1
load_8 r2, [r9]
add r9, r9, 1
load_8 r4, [r9]
call drawing.clear_tile
mov r5, 0
mov r6, 0
lsl r9, r4, 3 ; 2 * instruction size = 8
add r9, r9, timer_ghost.direction_jump_table
jmp r9
pub timer_ghost.direction_jump_table:
; direction_up
sub r6, r6, 1
jmp timer_ghost.move
; direction_right
add r5, r5, 1
jmp timer_ghost.move
; direction_down
add r6, r6, 1
jmp timer_ghost.move
; direction_left
sub r5, r5, 1
;jmp timer_ghost.move
pub timer_ghost.move:
add r1, r1, r5
add r2, r2, r6
add r9, zr, ptr.state_ghost
store_8 [r9], r1
add r9, r9, 1
store_8 [r9], r2
; draw ghost on new position
mov r3, sprites.rotation_0
add r4, r4, sprites.ghost
call drawing.draw_sprite_at_map_coord
/*
Check ahead for direction change
*/
add r1, r1, r5
add r2, r2, r6
call game.get_tile_address_from_map_coord
load_8 r10, [r13]
cmp r10, map.tiles.wall
jne timer_ghost.end
; increment direction
add r9, zr, ptr.state_ghost
add r9, r9, 2
load_8 r4, [r9]
add r4, r4, 1
and r4, r4, 0b11 ; modulo 3
store_8 [r9], r4
pub timer_ghost.end:

View File

@@ -0,0 +1,99 @@
/* Timer comparison / update
r1, r2: tick duration high, low [IN]
r3, r4: next tick high, low
r5, r6: tick after this one high, low
r7, r8: now high, low [IN]
r9: pointer
*/
add r9, zr, ptr.timer_robot_next_tick_high
load_32 r3, [r9]
add r9, zr, ptr.timer_robot_next_tick_low
load_32 r4, [r9]
cmp r7, r3
jb timer_robot.end
ja timer_robot.trigger
cmp r8, r4
jb timer_robot.end
pub timer_robot.trigger:
; udate next_tick
call u64.add
add r9, zr, ptr.timer_robot_next_tick_high
store_32 [r9], r5
add r9, zr, ptr.timer_robot_next_tick_low
store_32 [r9], r6
/* Movement
r1, r2: x, y
r3: rotation
r4: direction / sprite id
r5, r6: increments x, y
r7, r8: [RESERVED]
r9: pointer
r10: tile content
r13: tile address
*/
add r9, zr, ptr.state_robot
load_8 r1, [r9]
add r9, r9, 1
load_8 r2, [r9]
add r9, r9, 1
load_8 r4, [r9]
call drawing.clear_tile
mov r5, 0
mov r6, 0
lsl r9, r4, 3 ; 2 * instruction size = 8
add r9, r9, timer_robot.direction_jump_table
jmp r9
pub timer_robot.direction_jump_table:
; direction_up
sub r6, r6, 1
jmp timer_robot.try_move
; direction_right
add r5, r5, 1
jmp timer_robot.try_move
; direction_down
add r6, r6, 1
jmp timer_robot.try_move
; direction_left
sub r5, r5, 1
;jmp timer_robot.try_move
/*
Collision handling
*/
pub timer_robot.try_move:
add r1, r1, r5
add r2, r2, r6
call game.get_tile_address_from_map_coord
load_8 r10, [r13]
cmp r10, map.tiles.wall
jne timer_robot.move
; hit wall -> cancel movement
sub r1, r1, r5
sub r2, r2, r6
jmp timer_robot.draw
pub timer_robot.move:
; TODO: handle coin and empty differently
mov r10, map.tiles.empty
store_8 [r13], r10
add r9, zr, ptr.state_robot
store_8 [r9], r1
add r9, r9, 1
store_8 [r9], r2
pub timer_robot.draw:
; draw robot on new position
mov r3, sprites.rotation_0
add r4, r4, sprites.robot
call drawing.draw_sprite_at_map_coord
pub timer_robot.end: