Initial commit

This commit is contained in:
2023-05-06 18:33:58 +02:00
commit c9500a5548
18 changed files with 790 additions and 0 deletions
+14
View File
@@ -0,0 +1,14 @@
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
!.vscode/*.code-snippets
# Local History for Visual Studio Code
.history/
# Built Visual Studio Code Extensions
*.vsix
*.exe
+60
View File
@@ -0,0 +1,60 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Debug",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/KleiaxSnake",
"args": [],
"stopAtEntry": false,
"cwd": "${workspaceFolder}",
"environment": [],
"externalConsole": false,
"MIMode": "gdb",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": false
}
],
"windows": {
"miDebuggerPath": "C:/raylib/w64devkit/bin/gdb.exe",
},
"osx": {
"MIMode": "lldb"
},
"linux": {
"miDebuggerPath": "/usr/bin/gdb",
},
"preLaunchTask": "build debug"
},
{
"name": "Run",
"type": "cppdbg",
"request": "launch",
"args": [],
"stopAtEntry": false,
"cwd": "${workspaceFolder}",
"environment": [],
"externalConsole": false,
"program": "${workspaceFolder}/${fileBasenameNoExtension}",
"MIMode": "gdb",
"windows": {
"program": "${workspaceFolder}/${fileBasenameNoExtension}.exe",
"miDebuggerPath": "C:/raylib/w64devkit/bin/gdb.exe"
},
"osx": {
"MIMode": "lldb"
},
"linux": {
"miDebuggerPath": "/usr/bin/gdb"
},
"preLaunchTask": "build release",
}
]
}
+11
View File
@@ -0,0 +1,11 @@
{
"files.exclude": {
"**/.git": true,
"**/.svn": true,
"**/.hg": true,
"**/CVS": true,
"**/.DS_Store": true,
"**/*.o": true,
"**/*.exe": true,
}
}
+58
View File
@@ -0,0 +1,58 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"label": "build debug",
"type": "process",
"command": "make",
"args": [
],
"windows": {
"command": "mingw32-make.exe",
"args": [
"RAYLIB_PATH=C:/raylib/raylib",
// "OBJS=${fileBasenameNoExtension}.cpp",
"BUILD_MODE=DEBUG"
],
},
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": [
"$g++"
]
},
{
"label": "build release",
"type": "process",
"command": "make",
"args": [
"PLATFORM=PLATFORM_DESKTOP",
// "PROJECT_NAME=${fileBasenameNoExtension}",
"OBJS=${fileBasenameNoExtension}.cpp"
],
"windows": {
"command": "mingw32-make.exe",
"args": [
"RAYLIB_PATH=C:/raylib/raylib",
"PROJECT_NAME=${fileBasenameNoExtension}",
"OBJS=${fileBasenameNoExtension}.cpp"
],
},
"osx": {
"args": [
"RAYLIB_PATH=<path_to_raylib>/raylib",
"PROJECT_NAME=${fileBasenameNoExtension}",
"OBJS=${fileBasenameNoExtension}.c++"
],
},
"group": "build",
"problemMatcher": [
"$g++"
]
}
]
}
+113
View File
@@ -0,0 +1,113 @@
.PHONY: all clean
# Define required raylib variables
PROJECT_NAME ?= KleiaxSnake
RAYLIB_VERSION ?= 4.2.0
RAYLIB_PATH ?= ..\..
# Define compiler path on Windows
COMPILER_PATH ?= C:/raylib/w64devkit/bin
PLATFORM ?= PLATFORM_DESKTOP
DESTDIR ?= /usr/local
RAYLIB_INSTALL_PATH ?= $(DESTDIR)/lib
RAYLIB_H_INSTALL_PATH ?= $(DESTDIR)/include
# Library type used for raylib: STATIC (.a) or SHARED (.so/.dll)
RAYLIB_LIBTYPE ?= STATIC
# Build mode for project: DEBUG or RELEASE
BUILD_MODE ?= DEBUG
ifeq ($(OS),Windows_NT)
PLATFORM_OS=WINDOWS
export PATH := $(COMPILER_PATH):$(PATH)
endif
RAYLIB_RELEASE_PATH ?= $(RAYLIB_PATH)/src
EXAMPLE_RUNTIME_PATH ?= $(RAYLIB_RELEASE_PATH)
# Define default C compiler: gcc
# NOTE: define g++ compiler if using C++
CC = g++
# Define default make program: Mingw32-make
MAKE = mingw32-make
# Define compiler flags:
# -O0 defines optimization level (no optimization, better for debugging)
# -O1 defines optimization level
# -g include debug information on compilation
# -s strip unnecessary data from build -> do not use in debug builds
# -Wall turns on most, but not all, compiler warnings
# -std=c99 defines C language mode (standard C from 1999 revision)
# -std=gnu99 defines C language mode (GNU C from 1999 revision)
# -Wno-missing-braces ignore invalid warning (GCC bug 53119)
# -D_DEFAULT_SOURCE use with -std=c99 on Linux and PLATFORM_WEB, required for timespec
CFLAGS += -Wall -Wno-missing-braces
ifeq ($(BUILD_MODE),DEBUG)
CFLAGS += -g -O0
else
CFLAGS += -s -O1
endif
# Define include paths for required headers
# NOTE: Several external required libraries (stb and others)
INCLUDE_PATHS = -I. -I$(RAYLIB_PATH)/src -I$(RAYLIB_PATH)/src/external
INCLUDE_PATHS += -I./include
# INCLUDE_PATHS += -I./src
# Define library paths containing required libs.
LDFLAGS = -L. -L$(RAYLIB_RELEASE_PATH) -L$(RAYLIB_PATH)/src
# Define any libraries required on linking
# if you want to link libraries (libname.so or libname.a), use the -lname
ifeq ($(PLATFORM_OS),WINDOWS)
# Libraries for Windows desktop compilation
# NOTE: WinMM library required to set high-res timer resolution
LDLIBS = -lraylib -lopengl32 -lgdi32 -lwinmm
endif
# Define a recursive wildcard function
rwildcard=$(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2) $(filter $(subst *,%,$2),$d))
# Define all source files required
SRC_DIR = src
OBJ_DIR = obj
# Define all object files from source files
# SRC = $(call rwildcard, *.c, *.h)
SRC = $(call rwildcard, *.cpp, *.h)
# OBJS = $(SRC:$(SRC_DIR)/%.cpp=$(OBJ_DIR)/%.o)
OBJS ?= main.cpp
OBJS += src/Game.cpp
OBJS += src/Board.cpp
OBJS += src/raylibCpp.cpp
OBJS += src/Snake.cpp
MAKEFILE_PARAMS = $(PROJECT_NAME)
all:
$(MAKE) $(MAKEFILE_PARAMS)
# Project target defined by PROJECT_NAME
$(PROJECT_NAME): $(OBJS)
$(CC) -o $(PROJECT_NAME)$(EXT) $(OBJS) $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM)
# Compile source files
# NOTE: This pattern will compile every module defined on $(OBJS)
#%.o: %.c
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp
$(CC) -c $< -o $@ $(CFLAGS) $(INCLUDE_PATHS) -D$(PLATFORM)
# Clean everything
clean:
ifeq ($(PLATFORM_OS),WINDOWS)
del *.o *.exe /s
endif
@echo Cleaning done
+21
View File
@@ -0,0 +1,21 @@
#pragma once
#include "raylibCpp.h"
#include <vector>
#include "Vec2.h"
#include "Settings.h"
class Board {
public:
Board(Vec2<int> screenPos, Vec2<int> widthHeight, int padding);
void DrawBorder() const;
void Draw() const;
int GetWidth() const;
int GetHeight() const;
private:
int width;
int height;
const int padding;
Vec2<int> size;
Vec2<int> screenPos;
};
+21
View File
@@ -0,0 +1,21 @@
#pragma once
#include <string>
#include "Board.h"
#include "Snake.h"
class Game {
public:
Game(int width, int height, int fps, std::string title);
Game(const Game& other) = delete;
Game& operator=(const Game& other) = delete;
~Game() noexcept;
bool GameShouldClose() const;
void Tick();
private:
void Update();
void Draw();
Board board;
Snake snake;
};
+15
View File
@@ -0,0 +1,15 @@
#pragma once
#include "Vec2.h"
namespace settings
{
//Board settings
inline constexpr Vec2<int> gridSize{30, 15};
inline constexpr Vec2<int> gridPos{50, 50};
inline constexpr int gridCellSize = 30;
inline constexpr int gridInnerPadding = 2;
inline constexpr int gridBorderWidth = 15;
//Window settings
inline constexpr int fps = 60;
}
+72
View File
@@ -0,0 +1,72 @@
#pragma once
#include "raylibCpp.h"
#include <vector>
#include <list>
#include <string>
#include "Vec2.h"
#include "Settings.h"
class Snake {
public:
enum Direction {
Up,
Down,
Left,
Right,
None
};
private:
class Body {
public:
Body(Vec2<int> pos);
void draw(Color color = WHITE) const;
void move(Vec2<int> pos) { this->pos = pos; };
Vec2<int> getPos() const { return this->pos; }
static void setSize(Vec2<int> size) { Body::size = size; }
private:
Vec2<int> pos;
static Vec2<int> size;
Snake::Direction nextPart;
};
class Food {
public:
Food();
void draw() const;
void newPosition();
Vec2<int> getPosition() { return this->pos; }
private:
Vec2<int> pos;
Vec2<int> size;
};
public:
Snake();
void update();
void draw() const;
void setDirection(Direction dir);
private:
void move();
void eat();
Direction dir = Direction::None;
Food food;
bool hasEaten = false;
bool hasBitten = false;
int score = 0;
double lastMoveTime = 0;
double moveDelay = 0.15;
std::list<Snake::Body> bodyList;
};
+66
View File
@@ -0,0 +1,66 @@
#pragma once
template <typename T>
class Vec2
{
public:
Vec2() = default;
constexpr Vec2(T x, T y)
:
x(x),
y(y)
{}
constexpr T GetX() const {return x;};
constexpr T GetY() const {return y;};
constexpr void SetX(T x_in) { x = x_in;};
constexpr void SetY(T y_in) { y = y_in;};
public:
constexpr bool operator==(const Vec2& rhs) const
{
return (x == rhs.x && y == rhs.y);
}
constexpr bool operator!=(const Vec2& rhs) const
{
return !(*this == rhs);
}
constexpr Vec2 operator+(const Vec2& rhs) const
{
return {x + rhs.x, y + rhs.y};
}
constexpr Vec2 operator+(const int rhs) const
{
return {x + rhs, y + rhs};
}
constexpr Vec2& operator+=(const Vec2& rhs)
{
return *this = *this + rhs;
}
constexpr Vec2 operator-(const Vec2& rhs) const
{
return {x - rhs.x, y - rhs.y};
}
constexpr Vec2 operator-(const int rhs) const
{
return { x - rhs, y - rhs};
}
constexpr Vec2& operator-=(const Vec2& rhs)
{
return *this = *this - rhs;
}
constexpr Vec2 operator*(const Vec2& rhs) const
{
return {x * rhs.x, y * rhs.y};
}
constexpr Vec2 operator*(const int rhs) const
{
return { x * rhs, y * rhs };
}
constexpr Vec2& operator*=(const Vec2& rhs)
{
return *this = *this * rhs;
}
private:
T x;
T y;
};
+8
View File
@@ -0,0 +1,8 @@
#pragma once
#include <raylib.h>
#include "Vec2.h"
namespace raycpp
{
void DrawRectangle(Vec2<int> pos, Vec2<int> widthHeight, Color color);
void DrawRectangleLinesEx(Vec2<int> pos, Vec2<int> widthHeight, int lineThick, Color color);
}
+24
View File
@@ -0,0 +1,24 @@
{
"folders": [
{
"path": "."
}
],
"settings": {
"files.associations": {
"raylib.h": "c",
"math.h": "c",
"blocks.h": "c",
"stdio.h": "c",
"*.m": "c"
},
"cSpell.words": [
"DARKGRAY",
"fovy",
"Kleiax",
"raycpp",
"raylib",
"RAYWHITE"
]
}
}
+25
View File
@@ -0,0 +1,25 @@
#include "Game.h"
#include "Settings.h"
int main(void) {
int width = 2 * settings::gridPos.GetX()
+ 2 * settings::gridBorderWidth
+ settings::gridSize.GetX() * settings::gridCellSize
+ (settings::gridSize.GetX() + 1) * settings::gridInnerPadding;
int height = 2 * settings::gridPos.GetY()
+ 2 * settings::gridBorderWidth
+ settings::gridSize.GetY() * settings::gridCellSize
+ (settings::gridSize.GetY() + 1) * settings::gridInnerPadding;
Game game{width,
height,
settings::fps,
"Snake Kleiax Raylib"};
while (!game.GameShouldClose())
{
game.Tick();
}
return 0;
}
+1
View File
@@ -0,0 +1 @@
Assets license.
+41
View File
@@ -0,0 +1,41 @@
#include "Board.h"
#include <assert.h>
Board::Board(Vec2<int> screenPos, Vec2<int> widthHeight, int padding) :
screenPos(screenPos),
size(widthHeight),
padding(padding) {
this->width = 2 * settings::gridBorderWidth
+ settings::gridSize.GetX() * settings::gridCellSize
+ (settings::gridSize.GetX() + 1) * settings::gridInnerPadding;
this->height = 2 * settings::gridBorderWidth
+ settings::gridSize.GetY() * settings::gridCellSize
+ (settings::gridSize.GetY() + 1) * settings::gridInnerPadding;
assert(width > 0 && height > 0); //If assertion triggers : The width or height is smaller than 1
}
void Board::DrawBorder() const
{
raycpp::DrawRectangleLinesEx(screenPos,
Vec2<int>{width,height},
settings::gridBorderWidth,
WHITE);
}
void Board::Draw() const
{
DrawBorder();
}
int Board::GetWidth() const
{
return width;
}
int Board::GetHeight() const
{
return height;
}
+58
View File
@@ -0,0 +1,58 @@
#include <assert.h>
#include "Game.h"
#include "raylibCpp.h"
#include "Settings.h"
Game::Game(int width, int height, int fps, std::string title) :
board(settings::gridPos,
settings::gridSize,
settings::gridInnerPadding)
{
assert(!GetWindowHandle()); //If assertion triggers : Window is already opened
SetTargetFPS(fps);
InitWindow(width, height, title.c_str());
}
Game::~Game() noexcept
{
assert(GetWindowHandle()); //If assertion triggers : Window is already closed
CloseWindow();
}
bool Game::GameShouldClose() const
{
return WindowShouldClose();
}
void Game::Tick()
{
BeginDrawing();
Update();
Draw();
EndDrawing();
}
void Game::Update()
{
if (IsKeyPressed(KEY_UP))
snake.setDirection(Snake::Direction::Up);
else if (IsKeyPressed(KEY_DOWN))
snake.setDirection(Snake::Direction::Down);
else if (IsKeyPressed(KEY_LEFT))
snake.setDirection(Snake::Direction::Left);
else if (IsKeyPressed(KEY_RIGHT))
snake.setDirection(Snake::Direction::Right);
else if (IsKeyPressed(KEY_SPACE))
snake.setDirection(Snake::Direction::None);
snake.update();
}
void Game::Draw()
{
ClearBackground(BLACK);
board.Draw();
snake.draw();
}
+166
View File
@@ -0,0 +1,166 @@
#include "Snake.h"
Vec2<int> Snake::Body::size;
Snake::Body::Body(Vec2<int> pos) {
this->pos = pos;
}
void Snake::Body::draw(Color color) const{
int offsetX = settings::gridPos.GetX() + settings::gridBorderWidth + settings::gridInnerPadding;
int offsetY = settings::gridPos.GetY() + settings::gridBorderWidth + settings::gridInnerPadding;
Vec2<int> pixelPos;
pixelPos.SetX(offsetX + this->pos.GetX() * (settings::gridCellSize + settings::gridInnerPadding));
pixelPos.SetY(offsetY + this->pos.GetY() * (settings::gridCellSize + settings::gridInnerPadding));
raycpp::DrawRectangle(pixelPos, this->size, color);
}
Snake::Food::Food() {
this->newPosition();
this->size.SetX(settings::gridCellSize);
this->size.SetY(settings::gridCellSize);
}
void Snake::Food::newPosition() {
int x = GetRandomValue(0, settings::gridSize.GetX() - 1);
int y = GetRandomValue(0, settings::gridSize.GetY() - 1);
this->pos.SetX(x);
this->pos.SetY(y);
}
void Snake::Food::draw() const {
int offsetX = settings::gridPos.GetX() + settings::gridBorderWidth + settings::gridInnerPadding;
int offsetY = settings::gridPos.GetY() + settings::gridBorderWidth + settings::gridInnerPadding;
Vec2<int> pixelPos;
pixelPos.SetX(offsetX + this->pos.GetX() * (settings::gridCellSize + settings::gridInnerPadding));
pixelPos.SetY(offsetY + this->pos.GetY() * (settings::gridCellSize + settings::gridInnerPadding));
raycpp::DrawRectangle(pixelPos, this->size, RED);
}
Snake::Snake() {
Body::setSize(Vec2<int>{settings::gridCellSize, settings::gridCellSize});
this->bodyList.push_back(Body{Vec2<int>{5, 5}});
this->bodyList.push_back(Body{Vec2<int>{5, 6}});
this->bodyList.push_back(Body{Vec2<int>{5, 7}});
}
void Snake::update() {
if (GetTime() - this->lastMoveTime < this->moveDelay || this->hasBitten)
return;
this->lastMoveTime = GetTime();
this->move();
Vec2<int> head = (*this->bodyList.cbegin()).getPos();
if (head == this->food.getPosition())
this->eat();
bool firstSkip = true;
for (const Body & body : this->bodyList) {
if (firstSkip) {
firstSkip = false;
continue;
}
if (head == body.getPos())
this->hasBitten = true;
}
}
void Snake::draw() const {
for (const Body & body : this->bodyList)
body.draw();
(*this->bodyList.cbegin()).draw(GREEN);
this->food.draw();
std::string scoreString;
scoreString += "Score: ";
scoreString += std::to_string(this->score);
DrawText(scoreString.c_str(), 10, 10, 30, WHITE);
if (this->hasBitten)
DrawText("Game over!", 10, 70, 50, BLUE);
}
void Snake::setDirection(Direction dir) {
if (this->dir == Direction::Up && dir == Direction::Down)
return;
if (this->dir == Direction::Down && dir == Direction::Up)
return;
if (this->dir == Direction::Left && dir == Direction::Right)
return;
if (this->dir == Direction::Right && dir == Direction::Left)
return;
this->dir = dir;
}
void Snake::move() {
if (this->dir == Direction::None)
return;
Vec2<int> head = (*this->bodyList.cbegin()).getPos();
if (this->hasEaten)
this->hasEaten = false;
else
this->bodyList.pop_back();
switch (this->dir)
{
case Direction::Up:
head.SetY(head.GetY() - 1);
break;
case Direction::Down:
head.SetY(head.GetY() + 1);
break;
case Direction::Left:
head.SetX(head.GetX() - 1);
break;
case Direction::Right:
head.SetX(head.GetX() + 1);
break;
default:
break;
}
if (head.GetX() >= settings::gridSize.GetX())
head.SetX(0);
else if (head.GetX() < 0)
head.SetX(settings::gridSize.GetX() - 1);
if (head.GetY() >= settings::gridSize.GetY())
head.SetY(0);
else if (head.GetY() < 0)
head.SetY(settings::gridSize.GetY() - 1);
this->bodyList.push_front(Snake::Body(head));
}
void Snake::eat() {
this->hasEaten = true;
this->food.newPosition();
this->score++;
bool newFoodPlaceFound = false;
while (!newFoodPlaceFound) {
this->food.newPosition();
newFoodPlaceFound = true;
for (const Body & body : this->bodyList)
if (this->food.getPosition() == body.getPos()) {
newFoodPlaceFound = false;
break;
}
}
}
+16
View File
@@ -0,0 +1,16 @@
#include "raylibCpp.h"
#include <assert.h>
void raycpp::DrawRectangle(Vec2<int> pos, Vec2<int> widthHeight, Color color)
{
assert(pos.GetX() >= 0 && pos.GetY() >= 0 &&
pos.GetX() < GetScreenWidth() && pos.GetY() < GetScreenHeight()); //If assertion triggers : Trying to draw outisde of the screen
DrawRectangle(pos.GetX(),pos.GetY(),widthHeight.GetX(),widthHeight.GetY(),color);
}
void raycpp::DrawRectangleLinesEx(Vec2<int> pos, Vec2<int> widthHeight, int lineThick, Color color)
{
assert(pos.GetX() >= 0 && pos.GetY() >= 0 &&
pos.GetX() < GetScreenWidth() && pos.GetY() < GetScreenHeight()); //If assertion triggers : Trying to draw outisde of the screen
assert(lineThick > 0); //If assertion triggers : line thickness is less than 1
DrawRectangleLinesEx({(float)pos.GetX(),(float)pos.GetY(), (float)widthHeight.GetX(), (float)widthHeight.GetY()}, (float)lineThick, color);
}