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 "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)
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
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 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;
|
||||
}
|
||||
|
||||
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