Working menu. The only thing left is gaming
This commit is contained in:
parent
82e3c6211d
commit
d2de8e71c4
2
Makefile
2
Makefile
@ -108,7 +108,7 @@ debug-nox: image.bin
|
|||||||
-ex "break _start" \
|
-ex "break _start" \
|
||||||
-ex "continue"
|
-ex "continue"
|
||||||
|
|
||||||
USERPROGS=./user/false ./user/greet ./user/div0 ./user/shout ./user/badputs ./user/bss ./user/player ./snake/snake
|
USERPROGS=./user/false ./user/greet ./user/div0 ./user/shout ./user/badputs ./user/bss ./user/player ./user/getc ./snake/snake
|
||||||
|
|
||||||
fs.img: ./kernel.bin ./tools/mkfs $(USERPROGS)
|
fs.img: ./kernel.bin ./tools/mkfs $(USERPROGS)
|
||||||
./tools/mkfs $@ $< $(USERPROGS)
|
./tools/mkfs $@ $< $(USERPROGS)
|
||||||
|
|||||||
@ -84,3 +84,39 @@ const char* StringBuilder_get_cstr(StringBuilder* self) {
|
|||||||
StringBuilder_putc(self, 0);
|
StringBuilder_putc(self, 0);
|
||||||
return self->buf;
|
return self->buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* We still have beef with keyboard, even in userspace */
|
||||||
|
#define KEYCODE_SHIFT 42
|
||||||
|
#define KEYCODE_ENTER 28
|
||||||
|
#define KEYCODE_BACKSPACE 14
|
||||||
|
#define KEYCODE_SPACE 57
|
||||||
|
#define KEYCODE_ESCAPE 1
|
||||||
|
#define KEYCODE_A 30
|
||||||
|
#define KEYCODE_S 31
|
||||||
|
#define KEYCODE_D 32
|
||||||
|
#define KEYCODE_W 17
|
||||||
|
#define KEYCODE_Q 16
|
||||||
|
#define KEYCODE_ENTER 28
|
||||||
|
#define KEYCODE_LEFT 75
|
||||||
|
#define KEYCODE_RIGHT 77
|
||||||
|
#define KEYCODE_UP 72
|
||||||
|
#define KEYCODE_DOWN 80
|
||||||
|
#define KEYCODE_1 2
|
||||||
|
#define KEYCODE_2 3
|
||||||
|
|
||||||
|
bool is_keycode_for_press_left(uint8_t keycode) {
|
||||||
|
return keycode == KEYCODE_LEFT || keycode == KEYCODE_A;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_keycode_for_press_right(uint8_t keycode) {
|
||||||
|
return keycode == KEYCODE_RIGHT || keycode == KEYCODE_D;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_keycode_for_press_up(uint8_t keycode) {
|
||||||
|
return keycode == KEYCODE_UP || keycode == KEYCODE_W;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_keycode_for_press_down(uint8_t keycode) {
|
||||||
|
return keycode == KEYCODE_DOWN || keycode == KEYCODE_S;
|
||||||
|
}
|
||||||
|
|||||||
BIN
snake/snake
BIN
snake/snake
Binary file not shown.
134
snake/snake.c
134
snake/snake.c
@ -50,7 +50,18 @@ typedef enum {
|
|||||||
#define WALKING_ANIM_TIME_FAST 200
|
#define WALKING_ANIM_TIME_FAST 200
|
||||||
#define HATCHING_ANIM_TIME_FAST 80
|
#define HATCHING_ANIM_TIME_FAST 80
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
waiting_reason_step,
|
||||||
|
waiting_reason_p1,
|
||||||
|
waiting_reason_p2,
|
||||||
|
waiting_reason_cross,
|
||||||
|
waiting_reason_m2,
|
||||||
|
waiting_reason_m1,
|
||||||
|
waiting_reason_zero_pupa,
|
||||||
|
} WaitingReason;
|
||||||
|
|
||||||
struct Snake {
|
struct Snake {
|
||||||
|
bool is_space_pressed;
|
||||||
GameScreen game_screen;
|
GameScreen game_screen;
|
||||||
bool have_game;
|
bool have_game;
|
||||||
/* from 0 to PLAYABLE_MAPS_COUNT - 1 */
|
/* from 0 to PLAYABLE_MAPS_COUNT - 1 */
|
||||||
@ -62,7 +73,6 @@ struct Snake {
|
|||||||
uint8_t ghost_apples[WORLD_WIDTH][WORLD_HEIGHT];
|
uint8_t ghost_apples[WORLD_WIDTH][WORLD_HEIGHT];
|
||||||
ivec2 snake_head;
|
ivec2 snake_head;
|
||||||
ivec2 snake_pupa;
|
ivec2 snake_pupa;
|
||||||
bool is_time_sped_up;
|
|
||||||
SnakeDirection cur_snake_direction;
|
SnakeDirection cur_snake_direction;
|
||||||
SnakeDirection new_snake_direction;
|
SnakeDirection new_snake_direction;
|
||||||
/* If we are about to make a step into a wall, we start dying,
|
/* If we are about to make a step into a wall, we start dying,
|
||||||
@ -78,9 +88,14 @@ struct Snake {
|
|||||||
bool is_dead;
|
bool is_dead;
|
||||||
int score;
|
int score;
|
||||||
|
|
||||||
|
/* This stuff regulates game flow and animation progress */
|
||||||
|
WaitingReason waiting_reason;
|
||||||
|
uint32_t waiting_time;
|
||||||
|
bool is_time_sped_up;
|
||||||
} snake = {1};
|
} snake = {1};
|
||||||
|
|
||||||
void init_snake() {
|
void init_snake() {
|
||||||
|
snake.is_space_pressed = false;
|
||||||
snake.game_screen = game_screen_pause;
|
snake.game_screen = game_screen_pause;
|
||||||
snake.have_game = false;
|
snake.have_game = false;
|
||||||
snake.selected_map_index = 0;
|
snake.selected_map_index = 0;
|
||||||
@ -104,6 +119,10 @@ void start_snake_game() {
|
|||||||
snake.is_dying = false;
|
snake.is_dying = false;
|
||||||
snake.is_dead = false;
|
snake.is_dead = false;
|
||||||
snake.score = 0;
|
snake.score = 0;
|
||||||
|
|
||||||
|
snake.waiting_reason = waiting_reason_step;
|
||||||
|
snake.waiting_time = 0;
|
||||||
|
snake.is_time_sped_up = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -205,7 +224,7 @@ void draw_game_world() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void draw_frame() {
|
void draw_frame() {
|
||||||
clear_frame(0);
|
clear_frame(226);
|
||||||
draw_game_world();
|
draw_game_world();
|
||||||
|
|
||||||
StringBuilder hud = { 0 };
|
StringBuilder hud = { 0 };
|
||||||
@ -213,52 +232,117 @@ void draw_frame() {
|
|||||||
StringBuilder_append_u32(&hud, snake.score);
|
StringBuilder_append_u32(&hud, snake.score);
|
||||||
} else if (snake.game_screen == game_screen_pause) {
|
} else if (snake.game_screen == game_screen_pause) {
|
||||||
if (snake.have_game) {
|
if (snake.have_game) {
|
||||||
StringBuilder_append_cstr(&hud, "PAUSED");
|
StringBuilder_append_cstr(&hud, "PAUSED\n");
|
||||||
}
|
}
|
||||||
StringBuilder_append_cstr(&hud, "PRESS 1 FOR NEW GAME");
|
StringBuilder_append_cstr(&hud, "PRESS 1 FOR NEW GAME\n");
|
||||||
if (snake.have_game) {
|
if (snake.have_game) {
|
||||||
StringBuilder_append_cstr(&hud, "PRESS 2 TO CONTINUE");
|
StringBuilder_append_cstr(&hud, "PRESS ESC TO CONTINUE\n");
|
||||||
}
|
}
|
||||||
StringBuilder_append_cstr(&hud, "PRESS Q TO QUIT");
|
StringBuilder_append_cstr(&hud, "PRESS Q TO QUIT\n");
|
||||||
} else if (snake.game_screen == game_screen_select_map) {
|
} else if (snake.game_screen == game_screen_select_map) {
|
||||||
StringBuilder_append_cstr(&hud, "SELECT LEVEL\nCURRENTLY SELECTED:\n");
|
StringBuilder_append_cstr(&hud, "SELECT LEVEL\nCURRENTLY SELECTED\n");
|
||||||
check(snake.selected_map_index < PLAYABLE_MAPS_COUNT);
|
check(snake.selected_map_index < PLAYABLE_MAPS_COUNT);
|
||||||
StringBuilder_append_cstr(&hud, map_list.maps[snake.selected_map_index].name);
|
StringBuilder_append_cstr(&hud, map_list.maps[snake.selected_map_index].name);
|
||||||
} else if (snake.game_screen == game_screen_select_apple_count) {
|
} else if (snake.game_screen == game_screen_select_apple_count) {
|
||||||
StringBuilder_append_cstr(&hud, "SELECT DIFFICULTY\n"
|
StringBuilder_append_cstr(&hud, "SELECT DIFFICULTY\n"
|
||||||
"HOW MANY APPLES ON MAP\nCURRENTLY SELECTED:\n");
|
"HOW MANY APPLES ON MAP\nCURRENTLY SELECTED\n");
|
||||||
StringBuilder_append_u32(&hud, snake.gamemode_apples_count);
|
StringBuilder_append_u32(&hud, snake.gamemode_apples_count);
|
||||||
}
|
}
|
||||||
draw_hud(StringBuilder_get_cstr(&hud));
|
draw_hud(StringBuilder_get_cstr(&hud));
|
||||||
}
|
}
|
||||||
|
|
||||||
void wait_until(uint32_t deadline_ms) {
|
/* Called when game_screen is game_screen_gaming */
|
||||||
while ((int32_t)(time_ms() - deadline_ms) < 0) {
|
void handle_gaming_keycode(uint8_t keycode) {
|
||||||
syscall(SYS_halt, 0);
|
if (keycode == KEYCODE_ESCAPE) {
|
||||||
|
snake.game_screen = game_screen_pause;
|
||||||
}
|
}
|
||||||
|
if (!snake.is_dying) {
|
||||||
|
if (is_keycode_for_press_left(keycode) &&
|
||||||
|
snake.cur_snake_direction != snake_direction_right) {
|
||||||
|
snake.new_snake_direction = snake_direction_left;
|
||||||
|
} else if (is_keycode_for_press_right(keycode) &&
|
||||||
|
snake.cur_snake_direction != snake_direction_left) {
|
||||||
|
snake.new_snake_direction = snake_direction_right;
|
||||||
|
} else if (is_keycode_for_press_up(keycode) &&
|
||||||
|
snake.cur_snake_direction != snake_direction_bottom) {
|
||||||
|
snake.new_snake_direction = snake_direction_top;
|
||||||
|
} else if (is_keycode_for_press_down(keycode) &&
|
||||||
|
snake.cur_snake_direction != snake_direction_top) {
|
||||||
|
snake.new_snake_direction = snake_direction_bottom;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* return 1 if we are quitting */
|
||||||
|
int handle_incoming_keycode_after_halt(uint8_t keycode) {
|
||||||
|
if (keycode == KEYCODE_SPACE) {
|
||||||
|
snake.is_space_pressed = true;
|
||||||
|
} else if (keycode == (KEYCODE_SPACE | 0x80)) {
|
||||||
|
snake.is_space_pressed = false;
|
||||||
|
}
|
||||||
|
if (keycode == KEYCODE_Q && snake.game_screen != game_screen_gaming) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (snake.game_screen == game_screen_gaming) {
|
||||||
|
handle_gaming_keycode(keycode);
|
||||||
|
} else if (snake.game_screen == game_screen_pause) {
|
||||||
|
if (keycode == KEYCODE_1) {
|
||||||
|
snake.game_screen = game_screen_select_map;
|
||||||
|
} else if (keycode == KEYCODE_ESCAPE && snake.have_game) {
|
||||||
|
snake.game_screen = game_screen_gaming;
|
||||||
|
}
|
||||||
|
} else if (snake.game_screen == game_screen_select_map) {
|
||||||
|
if (keycode == KEYCODE_ESCAPE) {
|
||||||
|
snake.game_screen = game_screen_pause;
|
||||||
|
} else if (is_keycode_for_press_left(keycode)) {
|
||||||
|
snake.selected_map_index--;
|
||||||
|
if (snake.selected_map_index < 0)
|
||||||
|
snake.selected_map_index = PLAYABLE_MAPS_COUNT - 1;
|
||||||
|
} else if (is_keycode_for_press_right(keycode)) {
|
||||||
|
snake.selected_map_index++;
|
||||||
|
if (snake.selected_map_index >= PLAYABLE_MAPS_COUNT)
|
||||||
|
snake.selected_map_index = 0;
|
||||||
|
} else if (keycode == KEYCODE_ENTER) {
|
||||||
|
snake.game_screen = game_screen_select_apple_count;
|
||||||
|
}
|
||||||
|
} else if (snake.game_screen == game_screen_select_apple_count) {
|
||||||
|
if (keycode == KEYCODE_ESCAPE) {
|
||||||
|
snake.game_screen = game_screen_select_map;
|
||||||
|
} else if (is_keycode_for_press_left(keycode)) {
|
||||||
|
if (snake.gamemode_apples_count > 1)
|
||||||
|
snake.gamemode_apples_count--;
|
||||||
|
} else if (is_keycode_for_press_right(keycode)) {
|
||||||
|
if (snake.gamemode_apples_count < SNAKE_GAMEMODE_MAX_APPLES)
|
||||||
|
snake.gamemode_apples_count++;
|
||||||
|
} else if (keycode == KEYCODE_ENTER) {
|
||||||
|
start_snake_game();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
init_snake();
|
init_snake();
|
||||||
syscall(SYS_switch_to_graphics, 0);
|
syscall(SYS_switch_to_graphics, 0);
|
||||||
|
|
||||||
snake.selected_map_index = 5;
|
|
||||||
start_snake_game();
|
|
||||||
|
|
||||||
uint32_t next_frame_ms = time_ms();
|
|
||||||
while (1) {
|
while (1) {
|
||||||
// while (true) {
|
/* Returned from halt, we can enjoy keyboard input and animation progress*/
|
||||||
// int ch = syscall(SYS_getc, 0);
|
for (int ch;(ch = syscall(SYS_getc, 0)) >= 0;) {
|
||||||
// if (ch < 0)
|
int ret = handle_incoming_keycode_after_halt((uint8_t)ch);
|
||||||
// break;
|
if (ret == 1)
|
||||||
// uint8_t keycode = (uint8_t)ch;
|
goto quit;
|
||||||
//
|
}
|
||||||
// }
|
/* As an additional benefit, we can check if is_space_pressed here */
|
||||||
|
if (snake.is_space_pressed) {
|
||||||
|
snake.is_time_sped_up = true;
|
||||||
|
}
|
||||||
|
/* snake.is_time_sped_up will be relevant when checking animation end */
|
||||||
draw_frame();
|
draw_frame();
|
||||||
|
|
||||||
syscall(SYS_swap_frame, (uintptr_t)frame);
|
syscall(SYS_swap_frame, (uintptr_t)frame);
|
||||||
|
|
||||||
next_frame_ms += 500;
|
|
||||||
wait_until(next_frame_ms);
|
|
||||||
}
|
}
|
||||||
|
quit:
|
||||||
|
syscall(SYS_switch_to_text, 0);
|
||||||
|
syscall(SYS_puts, (uintptr_t)"Quit from game\n");
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
1120
snake/sprite_data.h
1120
snake/sprite_data.h
File diff suppressed because it is too large
Load Diff
18
user/getc.c
Normal file
18
user/getc.c
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#include "../snake/misc_utils.h"
|
||||||
|
#include "../syscall.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
while (1) {
|
||||||
|
int keycode = syscall(SYS_getc, 0);
|
||||||
|
if (keycode == -1) {
|
||||||
|
syscall(SYS_halt, 0);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringBuilder sb = {0};
|
||||||
|
StringBuilder_append_u32(&sb, (uint32_t)keycode);
|
||||||
|
StringBuilder_putc(&sb, '\n');
|
||||||
|
syscall(SYS_puts, (uintptr_t)StringBuilder_get_cstr(&sb));
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user