Initial commit

This commit is contained in:
Daniel Cortes
2020-05-22 01:54:52 -04:00
commit 242e60ff40
42 changed files with 1557 additions and 0 deletions

25
snake2/Makefile Executable file
View File

@@ -0,0 +1,25 @@
CC = g++
FILES = game.cpp renderer.cpp events.cpp main.cpp
OBJS = $(FILES:.cpp=.o)
CFLAGS = -Wall -Wextra -std=c++17 -O3 -pedantic
LFLAGS =
EXE = snake
CFLAGS += $(shell pkg-config --cflags sdl2)
CFLAGS += $(shell pkg-config --cflags SDL2_image)
LFLAGS += $(shell pkg-config --libs sdl2)
LFLAGS += $(shell pkg-config --libs SDL2_image)
all: $(EXE)
$(EXE): $(OBJS)
$(CC) $(OBJS) $(LFLAGS) -o $(EXE)
$(OBJS): $(FILES)
$(CC) -c $(FILES) $(CFLAGS)
clean:
rm *.o $(EXE)

39
snake2/events.cpp Executable file
View File

@@ -0,0 +1,39 @@
#include <SDL2/SDL.h>
#include "game.hpp"
#include "renderer.hpp"
#include "events.hpp"
Events::Events(Game *game, Renderer *renderer): game(game), renderer(renderer) {}
bool Events::process()
{
while (SDL_PollEvent(&event)) {
if(event.type == SDL_QUIT) {
return false;
} else if (event.type == SDL_KEYDOWN) {
switch(event.key.keysym.sym) {
case SDLK_LEFT:
game->snake.turn(DIR_LEFT);
break;
case SDLK_UP:
game->snake.turn(DIR_UP);
break;
case SDLK_RIGHT:
game->snake.turn(DIR_RIGHT);
break;
case SDLK_DOWN:
game->snake.turn(DIR_DOWN);
break;
case SDLK_r:
game->reset();
break;
}
} else if (event.type == SDL_WINDOWEVENT) {
if(event.window.event == SDL_WINDOWEVENT_RESIZED) {
renderer->updateSize();
}
}
}
return true;
}

19
snake2/events.hpp Executable file
View File

@@ -0,0 +1,19 @@
#ifndef EVENTS_H
#define EVENTS_H
#include <SDL2/SDL.h>
#include "game.hpp"
#include "renderer.hpp"
class Events
{
private:
SDL_Event event;
Game *game;
Renderer *renderer;
public:
Events(Game *game, Renderer *renderer);
bool process();
};
#endif

137
snake2/game.cpp Executable file
View File

@@ -0,0 +1,137 @@
#include "game.hpp"
#include "random.hpp"
Food::Food(): max_x(0), max_y(0) {}
Food::Food(int max_x, int max_y): max_x(max_x), max_y(max_y)
{
relocate();
}
void Food::relocate()
{
x = random_generator() % max_x;
y = random_generator() % max_y;
}
Snake::Snake()
{
body.push_back({0, 0});
last_direction = DIR_LEFT;
direction = DIR_LEFT;
alive = true;
}
Snake::Snake(int start_x, int start_y)
{
body.push_back({start_x, start_y});
direction = DIR_LEFT;
alive = true;
}
void Snake::turn(Direction direction)
{
switch(direction)
{
case DIR_UP : if(last_direction != DIR_DOWN) this->direction = DIR_UP ; break;
case DIR_DOWN : if(last_direction != DIR_UP) this->direction = DIR_DOWN ; break;
case DIR_RIGHT: if(last_direction != DIR_LEFT) this->direction = DIR_RIGHT; break;
case DIR_LEFT : if(last_direction != DIR_RIGHT) this->direction = DIR_LEFT ; break;
}
}
void Snake::move()
{
if(!alive) return;
int x = body.front().x;
int y = body.front().y;
switch(direction){
case DIR_UP: body.push_front({x, y - 1}); break;
case DIR_DOWN: body.push_front({x, y + 1}); break;
case DIR_LEFT: body.push_front({x - 1, y}); break;
case DIR_RIGHT: body.push_front({x + 1, y}); break;
}
last_direction = direction;
body.pop_back();
}
void Snake::eat()
{
int x = body.back().x;
int y = body.back().y;
body.push_back({x, y});
}
Game::Game(int tiles_x, int tiles_y) : tiles_x(tiles_x), tiles_y(tiles_y)
{
dificulty_multiplier = 0;
points = 0;
food = Food(tiles_x, tiles_y);
snake = Snake(tiles_x/2, tiles_y/2);
}
void Game::update()
{
snake.move();
Body head = snake.body.front();
//Check if snake was killed by the walls
if(head.x >= tiles_x || head.x < 0 || head.y >= tiles_y || head.y < 0)
{
snake.alive = false;
}
//Check if snake was killed by itself
for(std::list<Body>::iterator b = snake.body.begin(); b != snake.body.end(); b++)
{
if(b != snake.body.begin() && b->x == head.x && b->y == head.y)
{
snake.alive = false;
break;
}
}
//Check if snake eated some food
if(head.x == food.x && head.y == food.y)
{
snake.eat();
//Update points and dificulty
points++;
if(points % 20 == 0)
{
dificulty_multiplier++;
}
//Move the food to a valid place
while(true)
{
food.relocate();
bool intersects = false;
for(auto body_part: snake.body)
{
if(food.x == body_part.x && food.y == body_part.y)
{
intersects = true;
break;
}
}
if(!intersects) break;
}
}
}
void Game::reset()
{
snake = Snake(tiles_x/2, tiles_y/2);
food = Food(tiles_x, tiles_y);
dificulty_multiplier = 1;
points = 0;
}

63
snake2/game.hpp Executable file
View File

@@ -0,0 +1,63 @@
#ifndef GAME_H
#define GAME_H
#include <list>
enum Direction { DIR_UP, DIR_DOWN, DIR_LEFT, DIR_RIGHT };
class Food
{
private:
int max_x;
int max_y;
public:
int x;
int y;
Food();
Food(int max_x, int max_y);
void relocate();
};
struct Body
{
int x;
int y;
};
class Snake
{
public:
Direction last_direction;
Direction direction;
std::list<Body> body;
bool alive;
Snake();
Snake(int start_x, int start_y);
void move();
void turn(Direction direction);
void eat();
};
class Game
{
public:
Snake snake;
Food food;
int tiles_x;
int tiles_y;
int dificulty_multiplier;
int points;
Game(int tiles_x, int tiles_y);
void update();
void reset();
};
#endif

42
snake2/main.cpp Executable file
View File

@@ -0,0 +1,42 @@
#include <chrono>
#include "game.hpp"
#include "renderer.hpp"
#include "events.hpp"
Game game(20, 20);
Renderer renderer("snake", 600, 600, 20, 20);
Events events(&game, &renderer);
bool running = true;
auto tp1 = std::chrono::system_clock::now();
auto tp2 = std::chrono::system_clock::now();
std::chrono::duration<float> elapsed_time = tp2 - tp1;
float acumulated_time = 0;
int main()
{
while(running)
{
tp2 = std::chrono::system_clock::now();
elapsed_time = tp2 - tp1;
acumulated_time += elapsed_time.count();
tp1 = tp2;
running = events.process();
if(acumulated_time >= 0.1)
{
game.update();
renderer.clear();
renderer.renderArena();
renderer.renderSnake(game.snake);
renderer.renderFood(game.food);
renderer.render();
acumulated_time = 0;
}
}
}

11
snake2/random.hpp Executable file
View File

@@ -0,0 +1,11 @@
#ifndef RANDOM_H
#define RANDOM_H
#include <chrono>
#include <random>
unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
std::minstd_rand0 random_generator(seed);
#endif

96
snake2/renderer.cpp Executable file
View File

@@ -0,0 +1,96 @@
#include <iostream>
#include <algorithm>
#include "renderer.hpp"
#include "game.hpp"
const SDL_Color BACKGROUND_COLOR = {0, 64, 88, SDL_ALPHA_OPAQUE};
const SDL_Color SNAKE_COLOR = {0, 184, 0, SDL_ALPHA_OPAQUE};
const SDL_Color FOOD_COLOR = {248, 56, 0, SDL_ALPHA_OPAQUE};
Renderer::Renderer(std::string name, int screen_width, int screen_height, int tiles_x, int tiles_y) :
screen_width(screen_width),
screen_height(screen_height),
tiles_x(tiles_x),
tiles_y(tiles_y)
{
tile_size = std::min(screen_width/tiles_x, screen_height/tiles_y);
if (SDL_Init(SDL_INIT_VIDEO) < 0){
std::cout << "SDL_Init Error: " << SDL_GetError() << std::endl;
}
window = SDL_CreateWindow(name.c_str(), SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, screen_width, screen_height, SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE);
if(window == nullptr) {
std::cout << "SDL_CreateWindow Error: " << SDL_GetError() << std::endl;
}
renderer = SDL_CreateRenderer(window, -1, 0);
if(renderer == nullptr) {
std::cout << "SDL_CreateRenderer Error: " << SDL_GetError() << std::endl;
}
}
Renderer::~Renderer()
{
SDL_DestroyWindow(window);
window = nullptr;
SDL_DestroyRenderer(renderer);
renderer = nullptr;
SDL_Quit();
}
void Renderer::updateSize()
{
SDL_GetWindowSize(window, &screen_width, &screen_height);
tile_size = std::min(screen_width/tiles_x, screen_height/tiles_y);
}
void Renderer::clear()
{
SDL_RenderClear(renderer);
}
void Renderer::renderSnake(Snake snake)
{
for(auto body: snake.body){
SDL_Rect snake_rect = getRectInScreen(body.x, body.y);
SDL_SetRenderDrawColor(renderer, SNAKE_COLOR.r, SNAKE_COLOR.g, SNAKE_COLOR.b, SNAKE_COLOR.a);
SDL_RenderFillRect(renderer, &snake_rect);
}
}
void Renderer::renderFood(Food food)
{
SDL_Rect food_rect = getRectInScreen(food.x, food.y);
SDL_SetRenderDrawColor(renderer, FOOD_COLOR.r, FOOD_COLOR.g, FOOD_COLOR.b, FOOD_COLOR.a);
SDL_RenderFillRect(renderer, &food_rect);
}
void Renderer::renderArena()
{
SDL_Rect background_rect = {0, 0, screen_width, screen_height};
SDL_SetRenderDrawColor(renderer, 0, 0, 0, SDL_ALPHA_OPAQUE);
SDL_RenderFillRect(renderer, &background_rect);
SDL_Rect arena_rect = getRectInScreen(0,0);
arena_rect.w = tile_size * tiles_x;
arena_rect.h = tile_size * tiles_y;
SDL_SetRenderDrawColor(renderer, BACKGROUND_COLOR.r, BACKGROUND_COLOR.g, BACKGROUND_COLOR.b, BACKGROUND_COLOR.a);
SDL_RenderFillRect(renderer, &arena_rect);
}
void Renderer::render()
{
SDL_RenderPresent(renderer);
}
SDL_Rect Renderer::getRectInScreen(int x, int y){
int rect_x = (x * tile_size) + ((screen_width / 2) - (tile_size * tiles_x / 2));
int rect_y = (y * tile_size) + ((screen_height / 2) - (tile_size * tiles_y / 2));
SDL_Rect rect = {rect_x, rect_y, tile_size, tile_size};
return rect;
}

37
snake2/renderer.hpp Executable file
View File

@@ -0,0 +1,37 @@
#ifndef RENDER_H
#define RENDER_H
#include <SDL2/SDL.h>
#include <string>
#include "game.hpp"
class Renderer
{
private:
SDL_Window *window;
SDL_Renderer *renderer;
SDL_Event event;
int screen_width;
int screen_height;
int tile_size;
int tiles_x;
int tiles_y;
SDL_Rect getRectInScreen(int x, int y);
public:
Renderer(std::string name, int screen_width, int screen_height, int tiles_x, int tiles_y);
~Renderer();
void updateSize();
void clear();
void renderSnake(Snake snake);
void renderFood(Food food);
void renderArena();
void render();
};
#endif