Games #10

Merged
xamidev merged 3 commits from games into main 2024-09-13 14:25:13 +02:00
11 changed files with 260 additions and 7 deletions

View File

@@ -129,3 +129,17 @@ Lists all files present in `initrd.tar`.
#### `cat <file>`
Prints file content to terminal. Filename must be specified the same way as it is outputted when using `ls`.
### Games
#### `naval`
Starts a simplified naval battle game with 5 ships, one position each.
#### `snake <ticks>`
Starts a simplified and buggy snake game. You can choose the speed by setting the `ticks` argument, or let it default to a normal speed.
Controls:
- `q` to quit
- `wasd` to move

View File

@@ -12,10 +12,8 @@ extern char* framebuffer;
void putpixel(uint32_t* fb, int pitch, int bpp, int x, int y, uint32_t color)
{
if (bpp == 32) {
uint32_t* pixel_addr = (uint32_t*)((uint8_t*)fb + y * pitch + x *(bpp / 8));
*pixel_addr = color;
}
uint32_t* pixel_addr = (uint32_t*)((uint8_t*)fb + y * pitch + x *(bpp / 8));
*pixel_addr = color;
}
void draw_char(unsigned short int c, int cx, int cy, uint32_t fg, uint32_t bg)

View File

@@ -140,3 +140,19 @@ char keyboard_getchar()
keyboard_buffer_start = (keyboard_buffer_start+1) % KEYBOARD_BUFFER_SIZE;
return c;
}
int keyboard_has_input()
{
return keyboard_buffer_start != keyboard_buffer_end;
}
char keyboard_getchar_non_blocking()
{
if (keyboard_has_input())
{
char c = keyboard_buffer[keyboard_buffer_start];
keyboard_buffer_start = (keyboard_buffer_start+1)%KEYBOARD_BUFFER_SIZE;
return c;
}
return 0;
}

View File

@@ -14,5 +14,7 @@
#define RIGHT_SHIFT_RELEASED 0xB6
char keyboard_getchar();
int keyboard_has_input();
char keyboard_getchar_non_blocking();
#endif

View File

@@ -6,7 +6,7 @@
#ifndef KMAIN_H
#define KMAIN_H
#define BLANK_VERSION "0.3.107-alpha"
#define BLANK_VERSION "0.3.120-alpha"
#include <stdint.h>

View File

@@ -145,6 +145,7 @@ void shell_install()
register_command("bmp", program_bmp);
register_command("lspci", program_lspci);
register_command("naval", program_navalbattle);
register_command("snake", program_snake);
for (;;)
{

View File

@@ -39,6 +39,25 @@ void draw_cursor(uint32_t color)
}
}
void draw_pixel(int x, int y, uint32_t color) //high level wrapper for putpixel
{
putpixel(framebuffer, scanline, 32, x, y, color);
}
void draw_square(int x, int y, uint32_t color, int size)
{
int startx = x*size;
int starty = y*size;
for (int i=0; i<size; i++)
{
for (int j=0; j<size; j++)
{
draw_pixel(startx+i, starty+j, color);
}
}
}
void erase_cursor()
{
draw_cursor(black);

View File

@@ -22,8 +22,10 @@
void draw_cursor(uint32_t color);
void erase_cursor();
void move_cursor(int x, int y);
void draw_pixel(int x, int y, uint32_t color);
void draw_square(int x, int y, uint32_t color, int size);
void putchar(unsigned short int c, int x, int y, uint32_t fg, uint32_t bg);
void puts(const char* str);
void clear(void);

View File

@@ -74,7 +74,7 @@ void program_uptime()
void program_help()
{
printf("help\tpanic\twords\tprimes\trainbow\tclear\nmath\tbf\t uptime echo\t sysinfo\tconway\nrot13 morse\tcowsay time\t read\t reboot\npi\t ls\t cat\t bmp\t lspci\t naval\n");
printf("help\tpanic\twords\tprimes\trainbow\tclear\nmath\tbf\t uptime echo\t sysinfo\tconway\nrot13 morse\tcowsay time\t read\t reboot\npi\t ls\t cat\t bmp\t lspci\t naval\nsnake\n");
}
// Panic

View File

@@ -43,5 +43,6 @@ void program_lspci();
// Games
void program_navalbattle();
void program_conway();
void program_snake();
#endif

200
src/programs/snake.c Normal file
View File

@@ -0,0 +1,200 @@
// Snake game
// Author: xamidev
// Licensed under the Unlicense. See the repo below.
// https://github.com/xamidev/blankos
#include "../kernel/system.h"
#include "../libc/stdio.h"
#include "../drivers/framebuffer.h"
#include "../drivers/kb.h"
#include "../libc/string.h"
#include "../libc/crypto.h"
#define WIDTH 25
#define HEIGHT 25
#define PIXEL_SIZE 20
#define MAX_SNAKE_LENGTH 256
// to add:
// sound
// optimization (shit)
typedef struct
{
int x;
int y;
} SnakeSegment;
typedef struct
{
SnakeSegment segments[MAX_SNAKE_LENGTH];
int length;
int dx;
int dy;
} Snake;
typedef struct
{
int x;
int y;
} Food;
Snake snake;
Food food;
int score = 0;
bool onSnake;
int is_snake(int x, int y);
void init_game()
{
snake.length = 1;
snake.segments[0].x = WIDTH/2;
snake.segments[0].y = HEIGHT/2;
snake.dx = 1;
snake.dy = 0;
food.x = rand() % (WIDTH-1);
food.y = rand() % (HEIGHT-1);
}
void draw_board()
{
for (int y=0; y<=HEIGHT; y++)
{
for (int x=0; x<=WIDTH; x++)
{
if (x == 0 || x == WIDTH || y == 0 || y == HEIGHT)
{
draw_square(x, y, white, PIXEL_SIZE);
}
else if (is_snake(x, y)) {
draw_square(x, y, green, PIXEL_SIZE);
} else if(x == food.x && y == food.y) {
draw_square(x, y, red, PIXEL_SIZE);
} else {
draw_square(x, y, black, PIXEL_SIZE);
}
}
}
move_cursor(WIDTH+42, 2);
colorputs("Snake Game!", black, green);
move_cursor(WIDTH+42, 4);
colorprintf(yellow, black, "Score: %d", score);
move_cursor(WIDTH+42, 5);
puts("Use WASD keys to move");
move_cursor(WIDTH+42, 6);
puts("Press Q to quit");
}
int is_snake(int x, int y)
{
for (int i=0; i<snake.length; i++)
{
if (snake.segments[i].x == x && snake.segments[i].y == y)
{
return 1;
}
}
return 0;
}
void move_snake()
{
for (int i=snake.length-1; i>0; i--)
{
snake.segments[i] = snake.segments[i-1];
}
snake.segments[0].x += snake.dx;
snake.segments[0].y += snake.dy;
if (snake.segments[0].x < 0) snake.segments[0].x = WIDTH-1;
if (snake.segments[0].x >= WIDTH) snake.segments[0].x = 0;
if (snake.segments[0].y < 0) snake.segments[0].y = HEIGHT-1;
if (snake.segments[0].y >= HEIGHT) snake.segments[0].y = 0;
if (snake.segments[0].x == food.x && snake.segments[0].y == food.y)
{
snake.length++;
score++;
do
{
onSnake = false;
food.x = rand() % (WIDTH-1) + 1;
food.y = rand() % (HEIGHT-1) + 1;
for (int i=0; i<snake.length; i++)
{
if (snake.segments[i].x == food.x && snake.segments[i].y == food.y)
{
onSnake = true;
break;
}
}
} while (onSnake);
}
for (int i=1; i<snake.length; i++)
{
if (snake.segments[0].x == snake.segments[i].x && snake.segments[0].y == snake.segments[i].y)
{
move_cursor(WIDTH+42, 8);
colorputs("Game Over!\n", white, red);
move_cursor(0, HEIGHT+10);
shell_install();
}
}
}
void handle_input(char key)
{
if (key == 'w' && snake.dy == 0) {
snake.dx = 0;
snake.dy = -1;
} else if (key == 's' && snake.dy == 0) {
snake.dx = 0;
snake.dy = 1;
} else if (key == 'a' && snake.dx == 0) {
snake.dx = -1;
snake.dy = 0;
} else if (key == 'd' && snake.dx == 0) {
snake.dx = 1;
snake.dy = 0;
} else if (key =='q') {
move_cursor(0, HEIGHT+10);
shell_install();
}
}
void program_snake(int argc, char* argv[])
{
int game_speed;
if (argc < 2)
{
game_speed = 4;
} else {
game_speed = atoi(argv[1]);
}
clear();
init_game();
for(;;)
{
char key = keyboard_getchar_non_blocking();
if (key)
{
handle_input(key);
}
move_snake();
draw_board();
delay(game_speed);
}
}