Compare commits

...

7 Commits

Author SHA1 Message Date
Juhani Krekelä f3e5856ac4 Add scoring 2023-01-14 22:43:49 +02:00
Juhani Krekelä 65a8c4cc1a Run sipsi-8 at 900Hz for full-speed experience 2023-01-14 22:43:25 +02:00
Juhani Krekelä 2368fa7b7f Tune snake speed and fix a bug with turning code 2023-01-14 22:14:07 +02:00
Juhani Krekelä 4a63bf5467 Lengthen the snake when it eats a fruit 2023-01-14 22:11:39 +02:00
Juhani Krekelä 76ceb71e93 Store snake's movement to allow longer snake 2023-01-14 22:02:59 +02:00
Juhani Krekelä c632573f90 Play a short beep whenever fruit is eaten 2023-01-14 21:40:43 +02:00
Juhani Krekelä c81dee26f2 Use a direction value instead of dx, dy pair for movement 2023-01-14 21:40:43 +02:00
2 changed files with 202 additions and 44 deletions

View File

@ -17,5 +17,5 @@ clean:
distclean: clean
test: $(BIN)
sipsi-8.py $<
sipsi-8.py $< 900
chip8 $<

244
mato8.asm
View File

@ -4,18 +4,26 @@
; Under Creative Commons Zero 1.0
; Assemble with c8asm (https://github.com/wernsey/chip8)
define frames_wait 4
define frames_wait 5
define up_key 2
define down_key 8
define left_key 4
define right_key 6
define game_over_reg v8
define fruit_x_reg v9
define fruit_y_reg va
define head_dx_reg vb
define head_dy_reg vc
define direction_up 0
define direction_down 6
define direction_left 12
define direction_right 18
define score_high_reg v5
define score_low_reg v6
define game_over_reg v7
define fruit_x_reg v8
define fruit_y_reg v9
define tail_x_reg va
define tail_y_reg vb
define head_direction_reg vc
define head_x_reg vd
define head_y_reg ve
@ -23,11 +31,16 @@ start:
cls
ld game_over_reg, 0
ld score_high_reg, 0
ld score_low_reg, 0
rnd head_x_reg, 63
rnd head_y_reg, 31
ld head_dx_reg, 1
ld head_dy_reg, 0
ld tail_x_reg, head_x_reg
ld tail_y_reg, head_y_reg
ld head_direction_reg, direction_right
ld i, single_pixel
drw head_x_reg, head_y_reg, 1
@ -38,21 +51,23 @@ mainloop:
ld v0, frames_wait
ld dt, v0
ld v1, head_direction_reg
ld v0, up_key
sknp v0
call dir_up
call turn_up
ld v0, down_key
sknp v0
call dir_down
call turn_down
ld v0, left_key
sknp v0
call dir_left
call turn_left
ld v0, right_key
sknp v0
call dir_right
call turn_right
call move_snake
@ -70,6 +85,8 @@ game_over:
ld st, v0
call wait
call display_score
ld v0, 30
call wait
@ -86,6 +103,42 @@ game_over:
jp start
display_score:
cls
ld i, score_high_bcd
ld b, score_high_reg
ld i, score_low_bcd
ld b, score_low_reg
ld i, score_low_bcd
ld v2, [i]
; v0 and v1 are zero, v2 is ones
ld v3, v2
ld i, score_high_bcd
ld v2, [i]
; v0 is thousands, v1 is hundreds, v2 is tens
; Score is a four-digit number stored in v0 to v3
ld v4, 0
ld v5, 0
ld f, v0
drw v4, v5, 5
add v4, 5
ld f, v1
drw v4, v5, 5
add v4, 5
ld f, v2
drw v4, v5, 5
add v4, 5
ld f, v3
drw v4, v5, 5
ret
wait:
ld dt, v0
wait_loop:
@ -106,54 +159,142 @@ spawn_fruit:
ret
dir_up:
; Allow only 90° turns
se head_dy_reg, 0
ret
ld head_dx_reg, 0
ld head_dy_reg, #ff
turn_up:
; Don't allow 180° turns (which would kill the snake instantly)
se v1, direction_down
ld head_direction_reg, direction_up
ret
dir_down:
se head_dy_reg, 0
ret
ld head_dx_reg, 0
ld head_dy_reg, 1
turn_down:
se v1, direction_up
ld head_direction_reg, direction_down
ret
dir_left:
se head_dx_reg, 0
ret
ld head_dx_reg, #ff
ld head_dy_reg, 0
turn_left:
se v1, direction_right
ld head_direction_reg, direction_left
ret
dir_right:
se head_dx_reg, 0
ret
ld head_dx_reg, 1
ld head_dy_reg, 0
turn_right:
se v1, direction_left
ld head_direction_reg, direction_right
ret
move_snake:
; Save the direction the snake is moving at head's location
ld v0, head_x_reg
add head_x_reg, head_dx_reg
ld v2, 63
and head_x_reg, v2
ld v1, head_y_reg
add head_y_reg, head_dy_reg
ld v2, 31
and head_y_reg, v2
call direction_table_index
ld v0, head_direction_reg
ld [i], v0
; Move the snake's head
call unpack_direction
add head_x_reg, v0
ld v0, 63
and head_x_reg, v0
add head_y_reg, v1
ld v0, 31
and head_y_reg, v0
; Draw head location and erase tail location
ld i, single_pixel
drw head_x_reg, head_y_reg, 1
se vf, 0
call collision
drw v0, v1, 1
jp collision
drw tail_x_reg, tail_y_reg, 1
; Load the direction the snake was moving at tail's location
ld v0, tail_x_reg
ld v1, tail_y_reg
call direction_table_index
ld v0, [i]
; Move the snake's tail
call unpack_direction
add tail_x_reg, v0
ld v0, 63
and tail_x_reg, v0
add tail_y_reg, v1
ld v0, 31
and tail_y_reg, v0
ret
direction_table_index:
; v0 is the X coördinate, from 0 to 63, 00xxxxxx
; v1 is the Y coördinate, from 0 to 31, 000yyyyy
shl v0, v0
shl v0, v0
; v0 is the X coördinate shifted left by two, xxxxxx00
ld v2, %11100000
and v2, v0
or v1, v2
; v1 is combination of high 3 bits of X coördinate and the Y coördinate, xxxyyyyy
ld v2, %00011100
and v0, v2
; v0 is the low 3 bits of the X coördinate shifted left by two, 000xxx00
jp v0, direction_table_index_table
direction_table_index_table:
; 0
ld i, #400
jp direction_table_index_end
; 1
ld i, #500
jp direction_table_index_end
; 2
ld i, #600
jp direction_table_index_end
; 3
ld i, #700
jp direction_table_index_end
; 4
ld i, #800
jp direction_table_index_end
; 5
ld i, #900
jp direction_table_index_end
; 6
ld i, #a00
jp direction_table_index_end
; 7
ld i, #b00
direction_table_index_end:
add i, v1
ret
unpack_direction:
jp v0, unpack_direction_table
unpack_direction_table:
; Up
ld v0, 0
ld v1, #ff
ret
; Down
ld v0, 0
ld v1, 1
ret
; Left
ld v0, #ff
ld v1, 0
ret
; Right
ld v0, 1
ld v1, 0
ret
collision:
se head_x_reg, fruit_x_reg
jp tail_collision
@ -161,13 +302,30 @@ collision:
jp tail_collision
eat_fruit:
; TODO: Lenghten snake
; Jumping to collision skips tail moving code, so we get the snake
; lengthening for free
call increment_score
ld v0, 1
ld st, v0
ld i, single_pixel
drw fruit_x_reg, fruit_y_reg, 1
jp spawn_fruit
increment_score:
; Low register stores 0…9
add score_low_reg, 1
se score_low_reg, 10
ret
ld score_low_reg, 0
add score_high_reg, 1
ret
tail_collision:
ld game_over_reg, 1
ret
single_pixel: db #80
score_high_bcd: db 0, 0, 0
score_low_bcd: db 0, 0, 0