Games #10
@@ -129,3 +129,17 @@ Lists all files present in `initrd.tar`.
|
|||||||
#### `cat <file>`
|
#### `cat <file>`
|
||||||
|
|
||||||
Prints file content to terminal. Filename must be specified the same way as it is outputted when using `ls`.
|
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
|
||||||
|
|||||||
@@ -12,10 +12,8 @@ extern char* framebuffer;
|
|||||||
|
|
||||||
void putpixel(uint32_t* fb, int pitch, int bpp, int x, int y, uint32_t color)
|
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));
|
||||||
uint32_t* pixel_addr = (uint32_t*)((uint8_t*)fb + y * pitch + x *(bpp / 8));
|
*pixel_addr = color;
|
||||||
*pixel_addr = color;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void draw_char(unsigned short int c, int cx, int cy, uint32_t fg, uint32_t bg)
|
void draw_char(unsigned short int c, int cx, int cy, uint32_t fg, uint32_t bg)
|
||||||
|
|||||||
@@ -140,3 +140,19 @@ char keyboard_getchar()
|
|||||||
keyboard_buffer_start = (keyboard_buffer_start+1) % KEYBOARD_BUFFER_SIZE;
|
keyboard_buffer_start = (keyboard_buffer_start+1) % KEYBOARD_BUFFER_SIZE;
|
||||||
return c;
|
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;
|
||||||
|
}
|
||||||
|
|||||||
@@ -14,5 +14,7 @@
|
|||||||
#define RIGHT_SHIFT_RELEASED 0xB6
|
#define RIGHT_SHIFT_RELEASED 0xB6
|
||||||
|
|
||||||
char keyboard_getchar();
|
char keyboard_getchar();
|
||||||
|
int keyboard_has_input();
|
||||||
|
char keyboard_getchar_non_blocking();
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
#ifndef KMAIN_H
|
#ifndef KMAIN_H
|
||||||
#define KMAIN_H
|
#define KMAIN_H
|
||||||
|
|
||||||
#define BLANK_VERSION "0.3.107-alpha"
|
#define BLANK_VERSION "0.3.120-alpha"
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
|||||||
@@ -145,6 +145,7 @@ void shell_install()
|
|||||||
register_command("bmp", program_bmp);
|
register_command("bmp", program_bmp);
|
||||||
register_command("lspci", program_lspci);
|
register_command("lspci", program_lspci);
|
||||||
register_command("naval", program_navalbattle);
|
register_command("naval", program_navalbattle);
|
||||||
|
register_command("snake", program_snake);
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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()
|
void erase_cursor()
|
||||||
{
|
{
|
||||||
draw_cursor(black);
|
draw_cursor(black);
|
||||||
|
|||||||
@@ -22,8 +22,10 @@
|
|||||||
|
|
||||||
void draw_cursor(uint32_t color);
|
void draw_cursor(uint32_t color);
|
||||||
void erase_cursor();
|
void erase_cursor();
|
||||||
|
|
||||||
void move_cursor(int x, int y);
|
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 putchar(unsigned short int c, int x, int y, uint32_t fg, uint32_t bg);
|
||||||
void puts(const char* str);
|
void puts(const char* str);
|
||||||
void clear(void);
|
void clear(void);
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ void program_uptime()
|
|||||||
|
|
||||||
void program_help()
|
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
|
// Panic
|
||||||
|
|||||||
@@ -43,5 +43,6 @@ void program_lspci();
|
|||||||
// Games
|
// Games
|
||||||
void program_navalbattle();
|
void program_navalbattle();
|
||||||
void program_conway();
|
void program_conway();
|
||||||
|
void program_snake();
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
200
src/programs/snake.c
Normal file
200
src/programs/snake.c
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user