Initial commit
This commit is contained in:
25
snake2/Makefile
Executable file
25
snake2/Makefile
Executable 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
39
snake2/events.cpp
Executable 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
19
snake2/events.hpp
Executable 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
137
snake2/game.cpp
Executable 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
63
snake2/game.hpp
Executable 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
42
snake2/main.cpp
Executable 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
11
snake2/random.hpp
Executable 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
96
snake2/renderer.cpp
Executable 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
37
snake2/renderer.hpp
Executable 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
|
||||
Reference in New Issue
Block a user