From 8341d82660ac779446a00cad7d3c3d4ace91c56e Mon Sep 17 00:00:00 2001 From: Syntriax Date: Tue, 9 Jun 2020 20:12:26 +0300 Subject: [PATCH] Basic Movements Basic Movement Interface classes renamed Fixed few bugs --- Cell.hpp | 2 +- GameManager.hpp | 39 +++++++- GameWindow.hpp | 32 +++++-- Grid.hpp | 8 +- IBehaviour.hpp | 7 ++ Drawable.hpp => IDrawable.hpp | 2 +- Snake.hpp | 175 ++++++++++++++++++++++++++++++++++ SynEngine.hpp | 5 +- main.cpp | 8 +- 9 files changed, 255 insertions(+), 23 deletions(-) create mode 100644 IBehaviour.hpp rename Drawable.hpp => IDrawable.hpp (85%) create mode 100644 Snake.hpp diff --git a/Cell.hpp b/Cell.hpp index 33c5644..b5146ed 100644 --- a/Cell.hpp +++ b/Cell.hpp @@ -1,6 +1,6 @@ #include "SynEngine.hpp" -class Cell : public Drawable +class Cell : public IDrawable { private: unsigned int spriteIndex; diff --git a/GameManager.hpp b/GameManager.hpp index 736acd4..69ac8cb 100644 --- a/GameManager.hpp +++ b/GameManager.hpp @@ -1,39 +1,68 @@ #include "SynEngine.hpp" class GameConfiguration; +class Grid; class GameManager { private: static GameConfiguration *config; static unsigned lastInputDirection; + static sf::Vector2i lastInputVector; + static Grid *grid; public: + static Timer timer; static void KeyPress(sf::Keyboard::Key); static void SetConfig(GameConfiguration &); static GameConfiguration *GetConfig(); + static void SetGrid(Grid &); + static Grid &GetGrid(); + static sf::Vector2i GetInputVector(); + static unsigned GetInputDirection(); }; GameConfiguration *GameManager::config = NULL; +Grid *GameManager::grid = NULL; unsigned GameManager::lastInputDirection = 0; +sf::Vector2i GameManager::lastInputVector = sf::Vector2i(1, 0); void GameManager::KeyPress(sf::Keyboard::Key keycode) { switch (keycode) { - case sf::Keyboard::Key::Right: case sf::Keyboard::Key::D: GameManager::lastInputDirection = 0; break; - case sf::Keyboard::Key::Down: case sf::Keyboard::Key::S: GameManager::lastInputDirection = 1; break; - case sf::Keyboard::Key::Left: case sf::Keyboard::Key::A: GameManager::lastInputDirection = 2; break; - case sf::Keyboard::Key::Up: case sf::Keyboard::Key::W: GameManager::lastInputDirection = 3; break; + case sf::Keyboard::Key::Up: case sf::Keyboard::Key::W: GameManager::lastInputDirection = 3; GameManager::lastInputVector = sf::Vector2i(0, 1); break; + case sf::Keyboard::Key::Left: case sf::Keyboard::Key::A: GameManager::lastInputDirection = 2; GameManager::lastInputVector = sf::Vector2i(-1, 0); break; + case sf::Keyboard::Key::Down: case sf::Keyboard::Key::S: GameManager::lastInputDirection = 1; GameManager::lastInputVector = sf::Vector2i(0, -1); break; + case sf::Keyboard::Key::Right: case sf::Keyboard::Key::D: GameManager::lastInputDirection = 0; GameManager::lastInputVector = sf::Vector2i(1, 0); break; } } +sf::Vector2i GameManager::GetInputVector() +{ + return GameManager::lastInputVector; +} + +unsigned GameManager::GetInputDirection() +{ + return GameManager::lastInputDirection; +} + void GameManager::SetConfig(GameConfiguration &config) { GameManager::config = &config; } - GameConfiguration *GameManager::GetConfig() { return GameManager::config; } + +void GameManager::SetGrid(Grid &grid) +{ + GameManager::grid = &grid; +} + +Grid &GameManager::GetGrid() +{ + return *GameManager::grid; +} diff --git a/GameWindow.hpp b/GameWindow.hpp index eb0526b..599d0bf 100644 --- a/GameWindow.hpp +++ b/GameWindow.hpp @@ -1,5 +1,7 @@ #include "SynEngine.hpp" +Timer GameManager::timer; + class GameWindow { private: @@ -8,17 +10,20 @@ class GameWindow std::string title; sf::Uint32 style; sf::RenderWindow window; - Timer timer; + Timer *timer; GameConfiguration *config; - Drawable *drawable; - void (Drawable::*draw)(sf::RenderWindow *); + IDrawable *drawable; + void (IDrawable::*draw)(sf::RenderWindow *); + IBehaviour *behaviour; + void (IBehaviour::*behaviourUpdate)(); bool isFocused; bool fullscreen; void CreateWindow(); void CloseWindow(); public: GameWindow(std::string = "Window", sf::Uint32 = sf::Style::Titlebar | sf::Style::Close); - void BindDrawable(Drawable *, void (Drawable::*)(sf::RenderWindow *)); + void BindDrawable(IDrawable *, void (IDrawable::*)(sf::RenderWindow *)); + void BindBehaviour(IBehaviour *, void (IBehaviour::*)()); void Update(); bool IsOpen(); ~GameWindow(); @@ -39,13 +44,17 @@ void GameWindow::Update() break; } - timer.UpdateTime(); + timer -> UpdateTime(); if(!isFocused) return; window.clear(config -> GetBackgroundColor()); - ((drawable)->*(draw))(&window); + + if(behaviour) + ((behaviour)->*(behaviourUpdate))(); + if(drawable) + ((drawable)->*(draw))(&window); window.display(); } @@ -59,7 +68,8 @@ void GameWindow::CreateWindow() window.create(videoMode, title, fullscreen ? sf::Style::Fullscreen : style); window.setVerticalSyncEnabled(true); window.setFramerateLimit(60); - timer.ResetTimer(); + timer = &GameManager::timer; + timer -> ResetTimer(); } void GameWindow::CloseWindow() @@ -70,12 +80,18 @@ void GameWindow::CloseWindow() window.close(); } -void GameWindow::BindDrawable(Drawable *drawable, void (Drawable::*draw)(sf::RenderWindow *)) +void GameWindow::BindDrawable(IDrawable *drawable, void (IDrawable::*draw)(sf::RenderWindow *)) { this -> drawable = drawable; this -> draw = draw; } +void GameWindow::BindBehaviour(IBehaviour *behaviour, void (IBehaviour::*behaviourUpdate)()) +{ + this -> behaviour = behaviour; + this -> behaviourUpdate = behaviourUpdate; +} + GameWindow::GameWindow(std::string title, sf::Uint32 style) { config = GameManager::GetConfig(); diff --git a/Grid.hpp b/Grid.hpp index 36ddcb1..bf9b939 100644 --- a/Grid.hpp +++ b/Grid.hpp @@ -1,6 +1,6 @@ #include "SynEngine.hpp" -class Grid : public Drawable +class Grid : public IDrawable { private: sf::Vector2i offset; @@ -12,7 +12,7 @@ class Grid : public Drawable public: Grid(); bool SetGrid(); - void UpdateCell(unsigned int, unsigned int, unsigned int, int = -1); + void UpdateCell(int, int, unsigned int, int = -1); void Draw(sf::RenderWindow *); ~Grid(); }; @@ -63,8 +63,10 @@ bool Grid::SetGrid() return true; } -void Grid::UpdateCell(unsigned int x, unsigned int y, unsigned int spriteIndex, int direction) +void Grid::UpdateCell(int x, int y, unsigned int spriteIndex, int direction) { + x %= gridSize.x; if(x < 0) x += gridSize.x; + y %= gridSize.y; if(y < 0) y += gridSize.y; int index = x + gridSize.x * y; Cell *cell = cellArray + index; diff --git a/IBehaviour.hpp b/IBehaviour.hpp new file mode 100644 index 0000000..7bae640 --- /dev/null +++ b/IBehaviour.hpp @@ -0,0 +1,7 @@ +#include "SynEngine.hpp" + +class IBehaviour +{ + public: + virtual void Update() = 0; +}; \ No newline at end of file diff --git a/Drawable.hpp b/IDrawable.hpp similarity index 85% rename from Drawable.hpp rename to IDrawable.hpp index b5778bf..8dd65d2 100644 --- a/Drawable.hpp +++ b/IDrawable.hpp @@ -1,6 +1,6 @@ #include "SynEngine.hpp" -class Drawable +class IDrawable { public: virtual void Draw(sf::RenderWindow *) = 0; diff --git a/Snake.hpp b/Snake.hpp new file mode 100644 index 0000000..91d4904 --- /dev/null +++ b/Snake.hpp @@ -0,0 +1,175 @@ +#include "SynEngine.hpp" + +enum PlayerSprite +{ + Empty, + Point, + Straight, + Curved, + Back, + Head, + PointGot, + GameOver +}; + +struct SnakePart +{ + sf::Vector2i cellPosition; + unsigned direction; +}; + +class Snake : public IBehaviour +{ + private: + std::vector snake; + unsigned int lenght; + SnakePart *head; + Timer *timer; + Grid *grid; + float timeCountdown; + float timeResetValue; + unsigned TickPerSec; + GameConfiguration *config; + + void Move(); + void Grow(); + unsigned GetDirection(sf::Vector2i, sf::Vector2i); + unsigned GetBackDirection(); + sf::Vector2i GetDirectionVector(unsigned); + PlayerSprite GetNewSprite(unsigned &); + public: + Snake(); + void Update(); + ~Snake(); +}; + +Snake::Snake() +{ + TickPerSec = 4; + timeResetValue = 1.0 / (float)TickPerSec; + timeCountdown = timeResetValue; + lenght = 2; + snake.reserve(lenght); + + for (unsigned i = 0; i < lenght; i++) + snake.push_back({ sf::Vector2i(1 - i, 0), 0}); + + timer = &GameManager::timer; + head = &snake[0]; + config = GameManager::GetConfig(); + grid = &GameManager::GetGrid(); + + grid -> UpdateCell(snake[0].cellPosition.x, snake[0].cellPosition.y, PlayerSprite::Head, 0); + grid -> UpdateCell(snake[1].cellPosition.x, snake[1].cellPosition.y, PlayerSprite::Straight, 0); +} + +void Snake::Move() +{ + sf::Vector2i *backPosition = &snake[lenght - 1].cellPosition; + sf::Vector2i *secondPosition = &snake[1].cellPosition; + sf::Vector2i headPosition = head -> cellPosition; + unsigned direction; + unsigned headDirection; + PlayerSprite sprite; + + grid -> UpdateCell(backPosition -> x, -backPosition -> y, PlayerSprite::Empty); + + headDirection = head -> direction; + snake.pop_back(); + + // Check if the new direction is opposite to the head's direction + if((GameManager::GetInputDirection() + 2) % 4 == headDirection) + headPosition += GetDirectionVector(headDirection); + else + { + headPosition += GameManager::GetInputVector(); + headDirection = GameManager::GetInputDirection(); + } + snake.insert(snake.begin(), { headPosition, headDirection }); + + direction = snake[1].direction; + sprite = GetNewSprite(direction); + + grid -> UpdateCell(headPosition.x, -headPosition.y, PlayerSprite::Head, headDirection); + grid -> UpdateCell(secondPosition -> x, -secondPosition -> y, sprite, (int)direction); + grid -> UpdateCell(backPosition -> x, -backPosition -> y, PlayerSprite::Back, GetBackDirection()); +} + +void Snake::Update() +{ + if(timeCountdown > 0.0) + { + timeCountdown -= timer -> GetDeltaTime(); + return; + } + + Move(); + timeCountdown = timeResetValue; +} + +sf::Vector2i Snake::GetDirectionVector(unsigned direction) +{ + switch (direction) + { + case 0: return sf::Vector2i(1, 0); + case 1: return sf::Vector2i(0, -1); + case 2: return sf::Vector2i(-1, 0); + case 3: return sf::Vector2i(0, 1); + default: return sf::Vector2i(1, 0); + } +} + +PlayerSprite Snake::GetNewSprite(unsigned &direction) +{ + SnakePart *third = &snake[2]; + SnakePart *second = &snake[1]; + sf::Vector2i vector = third -> cellPosition - head -> cellPosition; + unsigned newDirection = GameManager::GetInputDirection(); + + + // I need to update this. It look so bad + if(vector.x != 0 && vector.y != 0) + { + direction += 2; + direction %= 4; + if(direction > newDirection) + { + unsigned temp; + temp = direction; + direction = newDirection; + newDirection = temp; + } + + // 0 - 1 -> 0 + // 1 - 2 -> 1 + // 2 - 3 -> 2 + // 0 - 3 -> 3 + if(direction == 0 && newDirection == 3) + direction = 3; + + return PlayerSprite::Curved; + } + + direction = GetDirection(head -> cellPosition, second -> cellPosition); + return PlayerSprite::Straight; +} + +unsigned Snake::GetDirection(sf::Vector2i first, sf::Vector2i second) +{ + first -= second; + + if(first.x > 0) return 0; + if(first.y < 0) return 1; + if(first.x < 0) return 2; + if(first.y > 0) return 3; + return 0; +} + +unsigned Snake::GetBackDirection() +{ + return GetDirection(snake[lenght - 2].cellPosition, snake[lenght - 1].cellPosition); +} + +Snake::~Snake() +{ +} diff --git a/SynEngine.hpp b/SynEngine.hpp index fe19b24..f9654ce 100644 --- a/SynEngine.hpp +++ b/SynEngine.hpp @@ -4,12 +4,15 @@ #include #include #include + #include #include #include "Timer.hpp" #include "GameManager.hpp" #include "GameConfiguration.hpp" - #include "Drawable.hpp" + #include "IDrawable.hpp" #include "Cell.hpp" #include "Grid.hpp" + #include "IBehaviour.hpp" + #include "Snake.hpp" #include "GameWindow.hpp" #endif diff --git a/main.cpp b/main.cpp index 19ec67c..ccfec10 100644 --- a/main.cpp +++ b/main.cpp @@ -6,12 +6,12 @@ int main(int argc, char const *argv[]) GameManager::SetConfig(config); GameWindow window("Long Starlight"); Grid grid = Grid(); - + GameManager::SetGrid(grid); grid.SetGrid(); - window.BindDrawable(&grid, &Drawable::Draw); + Snake player; - grid.UpdateCell(0, 0, 2); - grid.UpdateCell(0, 1, 2, 1); + window.BindDrawable(&grid, &IDrawable::Draw); + window.BindBehaviour(&player, &IBehaviour::Update); while (window.IsOpen()) window.Update();