Working menu. The only thing left is gaming

This commit is contained in:
Андреев Григорий 2026-04-07 13:38:44 +03:00
parent 82e3c6211d
commit d2de8e71c4
6 changed files with 724 additions and 586 deletions

View File

@ -108,7 +108,7 @@ debug-nox: image.bin
-ex "break _start" \
-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)
./tools/mkfs $@ $< $(USERPROGS)

View File

@ -84,3 +84,39 @@ const char* StringBuilder_get_cstr(StringBuilder* self) {
StringBuilder_putc(self, 0);
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;
}

Binary file not shown.

View File

@ -50,7 +50,18 @@ typedef enum {
#define WALKING_ANIM_TIME_FAST 200
#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 {
bool is_space_pressed;
GameScreen game_screen;
bool have_game;
/* from 0 to PLAYABLE_MAPS_COUNT - 1 */
@ -62,7 +73,6 @@ struct Snake {
uint8_t ghost_apples[WORLD_WIDTH][WORLD_HEIGHT];
ivec2 snake_head;
ivec2 snake_pupa;
bool is_time_sped_up;
SnakeDirection cur_snake_direction;
SnakeDirection new_snake_direction;
/* If we are about to make a step into a wall, we start dying,
@ -78,9 +88,14 @@ struct Snake {
bool is_dead;
int score;
/* This stuff regulates game flow and animation progress */
WaitingReason waiting_reason;
uint32_t waiting_time;
bool is_time_sped_up;
} snake = {1};
void init_snake() {
snake.is_space_pressed = false;
snake.game_screen = game_screen_pause;
snake.have_game = false;
snake.selected_map_index = 0;
@ -104,6 +119,10 @@ void start_snake_game() {
snake.is_dying = false;
snake.is_dead = false;
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() {
clear_frame(0);
clear_frame(226);
draw_game_world();
StringBuilder hud = { 0 };
@ -213,52 +232,117 @@ void draw_frame() {
StringBuilder_append_u32(&hud, snake.score);
} else if (snake.game_screen == game_screen_pause) {
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) {
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) {
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);
StringBuilder_append_cstr(&hud, map_list.maps[snake.selected_map_index].name);
} else if (snake.game_screen == game_screen_select_apple_count) {
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);
}
draw_hud(StringBuilder_get_cstr(&hud));
}
void wait_until(uint32_t deadline_ms) {
while ((int32_t)(time_ms() - deadline_ms) < 0) {
syscall(SYS_halt, 0);
/* Called when game_screen is game_screen_gaming */
void handle_gaming_keycode(uint8_t keycode) {
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) {
init_snake();
syscall(SYS_switch_to_graphics, 0);
snake.selected_map_index = 5;
start_snake_game();
uint32_t next_frame_ms = time_ms();
while (1) {
// while (true) {
// int ch = syscall(SYS_getc, 0);
// if (ch < 0)
// break;
// uint8_t keycode = (uint8_t)ch;
//
// }
/* Returned from halt, we can enjoy keyboard input and animation progress*/
for (int ch;(ch = syscall(SYS_getc, 0)) >= 0;) {
int ret = handle_incoming_keycode_after_halt((uint8_t)ch);
if (ret == 1)
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();
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;
}

File diff suppressed because it is too large Load Diff

18
user/getc.c Normal file
View 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));
}
}