first
This commit is contained in:
parent
bb007f68ab
commit
6c91d899d2
54
final/.gitignore
vendored
Normal file
54
final/.gitignore
vendored
Normal file
@ -0,0 +1,54 @@
|
||||
game
|
||||
|
||||
# Prerequisites
|
||||
*.d
|
||||
|
||||
# Object files
|
||||
*.o
|
||||
*.ko
|
||||
*.obj
|
||||
*.elf
|
||||
|
||||
# Linker output
|
||||
*.ilk
|
||||
*.map
|
||||
*.exp
|
||||
|
||||
# Precompiled Headers
|
||||
*.gch
|
||||
*.pch
|
||||
|
||||
# Libraries
|
||||
*.lib
|
||||
*.a
|
||||
*.la
|
||||
*.lo
|
||||
|
||||
# Shared objects (inc. Windows DLLs)
|
||||
*.dll
|
||||
*.so
|
||||
*.so.*
|
||||
*.dylib
|
||||
|
||||
# Executables
|
||||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
*.i*86
|
||||
*.x86_64
|
||||
*.hex
|
||||
|
||||
# Debug files
|
||||
*.dSYM/
|
||||
*.su
|
||||
*.idb
|
||||
*.pdb
|
||||
|
||||
# Kernel Module Compile Results
|
||||
*.mod*
|
||||
*.cmd
|
||||
.tmp_versions/
|
||||
modules.order
|
||||
Module.symvers
|
||||
Mkfile.old
|
||||
dkms.conf
|
29
final/LICENSE
Normal file
29
final/LICENSE
Normal file
@ -0,0 +1,29 @@
|
||||
BSD 3-Clause License
|
||||
|
||||
Copyright (c) 2019, Daniel Hládek
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
12
final/Makefile
Normal file
12
final/Makefile
Normal file
@ -0,0 +1,12 @@
|
||||
CFLAGS=-std=c99 -Wall -g
|
||||
|
||||
all: game
|
||||
|
||||
|
||||
|
||||
clean:
|
||||
rm game
|
||||
|
||||
game: main.c game.c game.h commands.c commands.h
|
||||
gcc main.c game.c game.h commands.c commands.h -lcurses -lm -o game
|
||||
|
66
final/README.md
Normal file
66
final/README.md
Normal file
@ -0,0 +1,66 @@
|
||||
# World Game Library
|
||||
|
||||
Learn asycnronous C programming by a game.
|
||||
|
||||
## Installation and Running
|
||||
|
||||
Make sure, that `ncurses` is installed.
|
||||
|
||||
Clone this repository.
|
||||
|
||||
Compile:
|
||||
|
||||
```c
|
||||
make
|
||||
```
|
||||
|
||||
Run:
|
||||
|
||||
```c
|
||||
./game
|
||||
```
|
||||
|
||||
## Make your own game
|
||||
|
||||
The game happens in a rectangular world of colorful characters.
|
||||
Your goal as a programmer is to modify the world according to the pressed keys and the internal game state.
|
||||
The library implements the game loop and draws the world to screen.
|
||||
|
||||
Your game consists of two functions:
|
||||
|
||||
- `void* init_game(struct world* g)` is called in the beginning. Here you can initialize the internal state of the game.
|
||||
The function should return a pointer to an instance of the initial game state `game`.
|
||||
- `int world_event(struct world* world,void* game)`
|
||||
is called by the game loop in periodic interval or when a key was pressed. Non-zero return value or `Ctrl+C` key interrupts the game loop.
|
||||
|
||||
The world variable represents state of two-dimensional grid of characters on the screen. The screen matrix looks like this:
|
||||
|
||||
```
|
||||
origin
|
||||
[0,0] width
|
||||
+--------------------+
|
||||
h | |
|
||||
e | |
|
||||
i | |
|
||||
g | |
|
||||
h | |
|
||||
t | |
|
||||
+--------------------+
|
||||
```
|
||||
|
||||
The world has the following parameters:
|
||||
|
||||
- `int height`: y-dimension of the grid.
|
||||
- `int width`: x-dimension of the grid.
|
||||
- `int interval`: maximum time between steps in milliseconds.
|
||||
|
||||
### The World Event Function
|
||||
|
||||
The `int world_event(struct world* world,void* game)`
|
||||
function should:
|
||||
|
||||
1. Read the game state (from the `void* game`) pointer.
|
||||
1. Examine the pressed key. If the `key` variable is non-zero, a key was pressed. According to the pressed key, modify the game state `game`.
|
||||
1. Draw the game state. In the beginning of the step function the screen is empty.
|
||||
1. Returning non-zero value ends the game loop.
|
||||
|
231
final/commands.c
Normal file
231
final/commands.c
Normal file
@ -0,0 +1,231 @@
|
||||
#include "commands.h"
|
||||
#include "game.h"
|
||||
#include <curses.h>
|
||||
#include <time.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
void welcome_screen(){
|
||||
box(stdscr, ACS_VLINE, ACS_HLINE);
|
||||
mvprintw(LINES / 2 - 8, COLS / 2 - 12, "Use WASD to change direction");
|
||||
mvprintw(LINES / 2 - 6, COLS / 2 - 15, "Dont touch the walls or your path");
|
||||
mvprintw(LINES / 2 - 4, COLS / 2 - 10, "To exit anytime use 'q'");
|
||||
mvprintw(LINES / 2 - 2, COLS / 2 - 11, "Press any key to continue");
|
||||
getch();
|
||||
erase();
|
||||
}
|
||||
|
||||
int pick_color(){
|
||||
mvprintw(LINES / 2 - 11, COLS / 2 - 20, "Pick color. To change use 's' and 'w'");
|
||||
mvprintw(LINES / 2 - 9, COLS / 2 - 13, "To confirm use 'space'");
|
||||
int color = 2;
|
||||
while(1){
|
||||
init_pair(1, COLOR_BLACK, (color == 5) ? 7 : color);
|
||||
attron(COLOR_PAIR(1));
|
||||
for(int i = 0; i < 10; i++){
|
||||
for(int q = 0; q < 20; q++){
|
||||
mvaddch(LINES / 2 - 3 + i, COLS / 2 - 2 + q - 10, ' ');
|
||||
}
|
||||
}
|
||||
int ch = getch();
|
||||
if(ch == ' ') break;
|
||||
else if(ch == 's'){
|
||||
color++;
|
||||
if(color > 6) color = 1;
|
||||
}
|
||||
else if(ch == 'w'){
|
||||
color--;
|
||||
if(color < 1) color = 6;
|
||||
}
|
||||
else if(ch == 'q'){
|
||||
endwin();
|
||||
exit(0);
|
||||
}
|
||||
flushinp();
|
||||
}
|
||||
return (color == 5) ? 7 : color;
|
||||
}
|
||||
|
||||
int pick_speed(){
|
||||
box(stdscr, ACS_VLINE, ACS_HLINE);
|
||||
mvprintw(LINES / 2 - 8, COLS / 2 - 12, "Pick speed. To change use 's'");
|
||||
mvprintw(LINES / 2 - 6, COLS / 2 - 8, "To confirm use 'space'");
|
||||
|
||||
int speed = 60;
|
||||
while(1){
|
||||
mvprintw(LINES / 2 - 3, COLS / 2 + 2, "%d", 70 - speed);
|
||||
int ch = getch();
|
||||
if(ch == ' ') break;
|
||||
else if(ch == 's'){
|
||||
speed -= 10;
|
||||
if(speed == 10) speed = 60;
|
||||
}
|
||||
}
|
||||
erase();
|
||||
box(stdscr, ACS_VLINE, ACS_HLINE);
|
||||
return speed;
|
||||
}
|
||||
|
||||
void init_screen(struct game* game){
|
||||
initscr();
|
||||
resize_term(LINES, (COLS % 2) ? COLS : COLS - 1);
|
||||
curs_set(0);
|
||||
noecho();
|
||||
welcome_screen();
|
||||
game->speed = pick_speed();
|
||||
srand(time(NULL));
|
||||
if(has_colors() == true){
|
||||
start_color();
|
||||
init_pair(7, COLOR_BLACK, COLOR_MAGENTA);
|
||||
int color = pick_color();
|
||||
init_pair(8, color, COLOR_BLACK);
|
||||
init_pair(9, COLOR_WHITE, COLOR_BLACK);
|
||||
erase();
|
||||
attron(COLOR_PAIR(9));
|
||||
box(stdscr, ACS_VLINE, ACS_HLINE);
|
||||
attron(COLOR_PAIR(8));
|
||||
}
|
||||
game->y = rand() % (LINES - 5) + 2;
|
||||
game->x = (rand() % (COLS - 5) + 2) / 2 * 2;
|
||||
mvaddch(game->y, game->x, '@');
|
||||
mvaddch(game->y + 1, game->x, ACS_HLINE);
|
||||
mvaddch(game->y - 1, game->x, ACS_HLINE);
|
||||
mvaddch(game->y, game->x + 2, ACS_VLINE);
|
||||
mvaddch(game->y, game->x - 2, ACS_VLINE);
|
||||
mvaddch(game->y + 1, game->x + 2, '+');
|
||||
mvaddch(game->y + 1, game->x - 2, '+');
|
||||
mvaddch(game->y - 1, game->x - 2, '+');
|
||||
mvaddch(game->y - 1, game->x + 2, '+');
|
||||
timeout(game->speed);
|
||||
}
|
||||
|
||||
void draw_path(struct game* game){
|
||||
static char save;
|
||||
char line;
|
||||
getyx(stdscr, game->y, game->x);
|
||||
if(save != game->direction){
|
||||
if(save == 'w' && game->direction == 'd') mvaddch(game->y, game->x - 1, ACS_ULCORNER);
|
||||
else if(save == 'w' && game->direction == 'a') mvaddch(game->y, game->x - 1, ACS_URCORNER);
|
||||
else if(save == 's' && game->direction == 'd') mvaddch(game->y, game->x - 1, ACS_LLCORNER);
|
||||
else if(save == 's' && game->direction == 'a') mvaddch(game->y, game->x - 1, ACS_LRCORNER);
|
||||
else if(save == 'a' && game->direction == 's'){
|
||||
mvaddch(game->y, game->x, ACS_HLINE);
|
||||
mvaddch(game->y, game->x - 1, ACS_ULCORNER);
|
||||
}
|
||||
else if(save == 'a' && game->direction == 'w'){
|
||||
mvaddch(game->y, game->x, ACS_HLINE);
|
||||
mvaddch(game->y, game->x - 1, ACS_LLCORNER);
|
||||
}
|
||||
else if(save == 'd' && game->direction == 's'){
|
||||
mvaddch(game->y, game->x - 2, ACS_HLINE);
|
||||
mvaddch(game->y, game->x - 1, ACS_URCORNER);
|
||||
}
|
||||
else if(save == 'd' && game->direction == 'w'){
|
||||
mvaddch(game->y, game->x - 2, ACS_HLINE);
|
||||
mvaddch(game->y, game->x - 1, ACS_LRCORNER);
|
||||
}
|
||||
save = game->direction;
|
||||
}
|
||||
else if(game->direction == 'w' || game->direction == 's'){
|
||||
mvaddch(game->y, game->x - 1, ACS_VLINE);
|
||||
}
|
||||
else if(game->direction == 'd'){
|
||||
mvaddch(game->y, game->x - 1, ACS_HLINE);
|
||||
mvaddch(game->y, game->x - 2, ACS_HLINE);
|
||||
}
|
||||
else if(game->direction == 'a'){
|
||||
mvaddch(game->y, game->x - 1, ACS_HLINE);
|
||||
mvaddch(game->y, game->x, ACS_HLINE);
|
||||
}
|
||||
}
|
||||
|
||||
int direction_check(struct game* game ){
|
||||
getyx(stdscr, game->y, game->x);
|
||||
int read = -1;
|
||||
switch(game->direction){
|
||||
case 'w':
|
||||
read = mvinch(game->y - 1, game->x - 1) & A_CHARTEXT;
|
||||
break;
|
||||
case 'a':
|
||||
read = mvinch(game->y, game->x - 3) & A_CHARTEXT;
|
||||
break;
|
||||
case 's':
|
||||
read = mvinch(game->y + 1, game->x - 1) & A_CHARTEXT;
|
||||
break;
|
||||
case 'd':
|
||||
read = mvinch(game->y, game->x + 1) & A_CHARTEXT;
|
||||
break;
|
||||
}
|
||||
usleep(100);
|
||||
move(game->y, game->x);
|
||||
if(read == (ACS_HLINE & A_CHARTEXT) || read == (ACS_VLINE & A_CHARTEXT) || read == ('#' & A_CHARTEXT) ) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int movement(struct game* game){
|
||||
static char save;
|
||||
if((game->direction == 'w' && save == 's') || (game->direction == 's' && save == 'w') || (game->direction == 'a' && save == 'd') || (game->direction == 'd' && save == 'a')) game->direction = save;
|
||||
if(direction_check(game)) return 0;
|
||||
switch(game->direction){
|
||||
case 'w':
|
||||
draw_path(game);
|
||||
mvaddch(game->y - 1, game->x - 1, '^');
|
||||
break;
|
||||
case 'a':
|
||||
draw_path(game);
|
||||
mvaddch(game->y, game->x - 3, '<');
|
||||
break;
|
||||
case 's':
|
||||
draw_path(game);
|
||||
mvaddch(game->y + 1, game->x - 1, 'v');
|
||||
break;
|
||||
case 'd':
|
||||
draw_path(game);
|
||||
mvaddch(game->y, game->x + 1, '>');
|
||||
break;
|
||||
}
|
||||
save = game->direction;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void spawn_blocks(struct game* game){
|
||||
int y = (rand() % LINES - 4) + 2;
|
||||
int x = (rand() % (COLS - 5) + 2) / 2 * 2;
|
||||
if(abs(y - game->y) < 10 || abs(x - game->x) < 20) return;
|
||||
attron(COLOR_PAIR(7));
|
||||
for(int i = 0; i < 3; i++){
|
||||
for(int q = 0; q < 6; q++){
|
||||
mvaddch(y + i, x + q, '#');
|
||||
}
|
||||
}
|
||||
attron(COLOR_PAIR(8));
|
||||
}
|
||||
|
||||
void game_over(struct game* game){
|
||||
timeout(9);
|
||||
for(int i = 0, cycle = 0; i < LINES; i++){
|
||||
flushinp();
|
||||
for(int q = 0; q < COLS; q += 4){
|
||||
attron(COLOR_PAIR(7));
|
||||
mvaddch(i, q - (i % 2), ' ');
|
||||
addch(' ');
|
||||
attron(COLOR_PAIR(9));
|
||||
addch(' ');
|
||||
addch(' ');
|
||||
refresh();
|
||||
}
|
||||
if(getch() != ERR) break;
|
||||
}
|
||||
attron(COLOR_PAIR(9));
|
||||
timeout(-1);
|
||||
flushinp();
|
||||
erase();
|
||||
mvprintw(LINES / 2 - 2, COLS / 2 - 5, "Score: %d", game->score);
|
||||
mvprintw(LINES / 2, COLS / 2 - 10, "Press any key to exit");
|
||||
getch();
|
||||
endwin();
|
||||
printf("\033[33mScore: %d\n\033[32mThanks for playing!\033[35m\n@Corupt Runner \033[37mby \033[36mArtem Horbunov\033[0m\n", game->score);
|
||||
free(game);
|
||||
}
|
27
final/commands.h
Normal file
27
final/commands.h
Normal file
@ -0,0 +1,27 @@
|
||||
#ifndef _COMMANDS_H_INCLUDE_
|
||||
#define _COMMANDS_H_INCLUDE_
|
||||
|
||||
#include "game.h"
|
||||
|
||||
//Shows user a guide how to play
|
||||
void welcome_screen();
|
||||
|
||||
//Initialize the screen with all configurations
|
||||
void init_screen();
|
||||
|
||||
//Draw path after the player
|
||||
void draw_path(struct game* game);
|
||||
|
||||
//Check there is something on the way
|
||||
int direction_check(struct game* game );
|
||||
|
||||
//Change the direction of player
|
||||
int movement(struct game* game);
|
||||
|
||||
//Spawn the blocking structure
|
||||
void spawn_blocks(struct game* game);
|
||||
|
||||
//Show the score and destroy the game
|
||||
void game_over(struct game* game);
|
||||
|
||||
#endif
|
48
final/game.c
Normal file
48
final/game.c
Normal file
@ -0,0 +1,48 @@
|
||||
#include <curses.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include "game.h"
|
||||
#include "commands.h"
|
||||
|
||||
// Start is called one in the beginning
|
||||
struct game* init_game(){
|
||||
// Allocate memory for the state
|
||||
struct game* st = calloc(1,(sizeof(struct game)));
|
||||
// Initialize state
|
||||
st->score = 0;
|
||||
st->x = (rand() % (COLS - 5) + 2) / 2 * 2;
|
||||
st->y = rand() % (LINES - 5) + 2;
|
||||
// Store pointer to the state to the world variable
|
||||
return st;
|
||||
}
|
||||
|
||||
// It should modify the state and draw it.
|
||||
int world_event(struct game* game){
|
||||
//Wait for input to start the game
|
||||
do{
|
||||
game->direction = getch();
|
||||
}while(game->direction != 'w' && game->direction != 'a' && game->direction != 's' && game->direction != 'd');
|
||||
for(int i = -1; i < 2; i++){
|
||||
for(int q = -2; q < 4; q += 2){
|
||||
mvaddch(game->y + i, game->x + q, ' ');
|
||||
}
|
||||
}
|
||||
//The loop of the game
|
||||
while(1){
|
||||
if(rand() % 10 == 0){
|
||||
spawn_blocks(game);
|
||||
move(game->y, game->x);
|
||||
}
|
||||
int save = game->direction;
|
||||
flushinp();
|
||||
game->direction = getch();
|
||||
//If wrong input- ignore it and change to the old one
|
||||
if(game->direction != 'w' && game->direction != 'a' && game->direction != 's' && game->direction != 'd' && game->direction != 'q') game->direction = save;
|
||||
if(game->direction == 'q') break;
|
||||
if(movement(game) == 0) break;
|
||||
game->score += 1;
|
||||
}
|
||||
getch();
|
||||
game_over(game);
|
||||
}
|
25
final/game.h
Normal file
25
final/game.h
Normal file
@ -0,0 +1,25 @@
|
||||
#ifndef _GAME_H_INCLUDE_
|
||||
#define _GAME_H_INCLUDE_
|
||||
|
||||
// Set of variables that expresses state of the game.
|
||||
//
|
||||
struct game {
|
||||
//X position of the player
|
||||
int x;
|
||||
//Y position of the player
|
||||
int y;
|
||||
//Score
|
||||
int score;
|
||||
//Direction
|
||||
int direction;
|
||||
//Speed
|
||||
int speed;
|
||||
};
|
||||
|
||||
// Returns pointer to newly allocated player
|
||||
struct game* init_game();
|
||||
|
||||
// Changes world according to the game state (pressed key, screen size or other event)
|
||||
int world_event(struct game* game);
|
||||
|
||||
#endif
|
9
final/main.c
Normal file
9
final/main.c
Normal file
@ -0,0 +1,9 @@
|
||||
#include "game.h"
|
||||
#include "commands.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
int main(int argc, char** argv){
|
||||
struct game* game = init_game();
|
||||
init_screen(game);
|
||||
world_event(game);
|
||||
}
|
Loading…
Reference in New Issue
Block a user