Merge pull request #20 from Trimutex/development

Update to current progress
This commit is contained in:
Gregory 2023-08-19 00:09:12 -05:00 committed by GitHub
commit 2969fd89db
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 111 additions and 99 deletions

View File

@ -5,6 +5,7 @@ add_executable(snakeplusplus
./gamestate.cpp ./gamestate.cpp
./snake.cpp ./snake.cpp
./playerinterface.cpp ./playerinterface.cpp
./common.cpp
) )
target_include_directories(snakeplusplus PUBLIC ${CMAKE_CURRENT_LIST_DIR}) target_include_directories(snakeplusplus PUBLIC ${CMAKE_CURRENT_LIST_DIR})

21
src/common.cpp Executable file
View File

@ -0,0 +1,21 @@
// common.cpp
#include <random>
#include "common.hpp"
namespace snakeplusplus
{
std::default_random_engine generator;
void InitializeGenerator(void)
{
generator.seed(std::random_device{}());
}
// Returns a newly generated number
int GenerateRandomNumber(int generationLimit)
{
int generatedNumber;
std::uniform_int_distribution<> distribution(0, generationLimit - 1);
generatedNumber = distribution(snakeplusplus::generator);
return generatedNumber;
}
}

View File

@ -1,13 +1,20 @@
#ifndef COMMON_HPP #ifndef COMMON_HPP
#define COMMON_HPP #define COMMON_HPP
enum PlayerDirection namespace snakeplusplus
{ {
void InitializeGenerator(void);
int GenerateRandomNumber(int generationLimit);
enum PlayerDirection
{
kNone = 0, kNone = 0,
kLeft = 1, kLeft = 1,
kUp = 2, kUp = 2,
kDown = 3, kDown = 3,
kRight = 4 kRight = 4
}; };
}
#endif #endif

View File

@ -1,9 +1,7 @@
// GameState.cpp // GameState.cpp
#include <iostream>
#include <memory>
#include <stdexcept> #include <stdexcept>
#include <string>
#include <SFML/Graphics.hpp> #include <SFML/Graphics.hpp>
#include <tuple>
#include "common.hpp" #include "common.hpp"
#include "playerinterface.hpp" #include "playerinterface.hpp"
#include "gamestate.hpp" #include "gamestate.hpp"
@ -12,27 +10,32 @@ namespace snakeplusplus
{ {
GameEngine::GameEngine() GameEngine::GameEngine()
{ {
snakeplusplus::InitializeGenerator();
return; return;
} }
void GameEngine::StartGame() void GameEngine::Start()
{ {
//ApplySettings();
PrepareGameBoard(); PrepareGameBoard();
graphics.StartGameWindow(); graphics.StartGameWindow();
GameLoop(); Loop();
return; return;
} }
void GameEngine::GameLoop(void) void GameEngine::Reset()
{
graphics.CheckContinue();
player.Reset();
PrepareGameBoard();
isGameOver = 0;
return;
}
void GameEngine::Loop(void)
{ {
while (graphics.IsOpen()) while (graphics.IsOpen())
{ {
if (isGameOver) if (isGameOver) {Reset();}
{
graphics.CheckContinue();
isGameOver = 0;
}
UpdatePlayerSpeed(); UpdatePlayerSpeed();
PlaceNewSnakePart(MovePlayer()); PlaceNewSnakePart(MovePlayer());
RegenerateFood(); RegenerateFood();
@ -56,11 +59,12 @@ namespace snakeplusplus
void GameEngine::PlaceNewSnakePart(sf::Vector2f location) void GameEngine::PlaceNewSnakePart(sf::Vector2f location)
{ {
if (!player.speed.x && !player.speed.y) { return; }
try try
{ {
char* locationState; char* locationState;
locationState = &gameBoard.at(location.y).at(location.x); locationState = &gameBoard.at(location.y).at(location.x);
if (*locationState == 'O' && player.body.size() > 1) if (*locationState == 'O' && (player.body.size() > 1))
isGameOver = true; // Game should end (Snake touching snake) isGameOver = true; // Game should end (Snake touching snake)
*locationState = 'O'; *locationState = 'O';
player.body.push(locationState); player.body.push(locationState);
@ -69,8 +73,8 @@ namespace snakeplusplus
player.Pop(); player.Pop();
} catch (const std::out_of_range& error) { } catch (const std::out_of_range& error) {
isGameOver = true; // Snake ran into edge isGameOver = true; // Snake ran into edge
exit(0);
} }
return;
} }
// Generates new food until not colliding with player // Generates new food until not colliding with player
@ -78,7 +82,6 @@ namespace snakeplusplus
{ {
sf::Vector2f newLocation = playerFood.location; sf::Vector2f newLocation = playerFood.location;
bool isUpdated = false; bool isUpdated = false;
// Keep making new food until generating a valid spot
while (gameBoard.at(newLocation.y).at(newLocation.x) == 'O') while (gameBoard.at(newLocation.y).at(newLocation.x) == 'O')
{ {
isUpdated = true; isUpdated = true;
@ -95,22 +98,26 @@ namespace snakeplusplus
gameBoard.clear(); gameBoard.clear();
sf::Vector2f boardDimensions = GetGameBoundaries(); sf::Vector2f boardDimensions = GetGameBoundaries();
gameBoard.resize(boardDimensions.y, std::vector<char> (boardDimensions.x, ' ')); gameBoard.resize(boardDimensions.y, std::vector<char> (boardDimensions.x, ' '));
player.headLocation.x = 4; // Snake setup
player.headLocation.y = 5; {
player.headLocation.x = GenerateRandomNumber(boardDimensions.x);
player.headLocation.y = GenerateRandomNumber(boardDimensions.y);
char* locationState = &gameBoard.at(player.headLocation.y).at(player.headLocation.x); char* locationState = &gameBoard.at(player.headLocation.y).at(player.headLocation.x);
player.body.push(locationState); player.body.push(locationState);
*player.body.front() = 'O'; *locationState = 'O';
playerFood.location.x = 2; }
playerFood.location.y = 2; // Food setup
playerFood.food = &gameBoard.at(2).at(2); {
*playerFood.food = 'X'; playerFood.GenerateNewFood(boardDimensions);
sf::Vector2f newLocation = playerFood.location;
gameBoard.at(newLocation.y).at(newLocation.x) = 'X';
}
return; return;
} }
void GameEngine::UpdatePlayerSpeed(void) void GameEngine::UpdatePlayerSpeed(void)
{ {
PlayerDirection input = controls.GetPlayerInput(); switch (GetPlayerInput()) {
switch (input) {
case kUp: case kUp:
player.speed.x = 0; player.speed.x = 0;
player.speed.y = -1; player.speed.y = -1;
@ -130,5 +137,6 @@ namespace snakeplusplus
default: default:
break; break;
} }
return;
} }
} }

View File

@ -2,7 +2,6 @@
#ifndef GAMESTATE_HPP #ifndef GAMESTATE_HPP
#define GAMESTATE_HPP #define GAMESTATE_HPP
#include <memory>
#include <SFML/Graphics.hpp> #include <SFML/Graphics.hpp>
#include "snake.hpp" #include "snake.hpp"
#include "playerinterface.hpp" #include "playerinterface.hpp"
@ -13,18 +12,17 @@ namespace snakeplusplus
{ {
public: public:
GameEngine(); GameEngine();
void StartGame(void); void Start(void);
void Reset(void);
sf::Vector2f GetGameBoundaries(void); sf::Vector2f GetGameBoundaries(void);
private: private:
std::vector< std::vector<char> > gameBoard; std::vector< std::vector<char> > gameBoard;
PlayerInput controls;
PlayerOutput graphics; PlayerOutput graphics;
Snake player; Snake player;
Food playerFood; Food playerFood;
bool useSFML = 1;
bool isGameOver = 0; bool isGameOver = 0;
void DisplayEndScreen(void); void DisplayEndScreen(void);
void GameLoop(void); void Loop(void);
sf::Vector2f MovePlayer(void); sf::Vector2f MovePlayer(void);
void PlaceNewSnakePart(sf::Vector2f location); void PlaceNewSnakePart(sf::Vector2f location);
void RegenerateFood(void); void RegenerateFood(void);

View File

@ -3,5 +3,6 @@
int main(void) int main(void)
{ {
snakeplusplus::GameEngine game; snakeplusplus::GameEngine game;
game.StartGame(); game.Start();
return 0;
} }

View File

@ -1,26 +1,24 @@
#include "playerinterface.hpp" #include "playerinterface.hpp"
#include <SFML/System/Vector2.hpp> #include <SFML/System/Vector2.hpp>
#include <cstdlib> #include <SFML/Window/Keyboard.hpp>
#include <iostream>
namespace snakeplusplus namespace snakeplusplus
{ {
PlayerInput::PlayerInput(void) PlayerDirection GetPlayerInput(void)
{ {
lastPlayerInput = kNone; if (sf::Keyboard::isKeyPressed(sf::Keyboard::Left)
} || sf::Keyboard::isKeyPressed(sf::Keyboard::A))
return kLeft;
PlayerDirection PlayerInput::GetPlayerInput(void) if (sf::Keyboard::isKeyPressed(sf::Keyboard::Up)
{ || sf::Keyboard::isKeyPressed(sf::Keyboard::W))
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Left)) return kUp;
lastPlayerInput = kLeft; if (sf::Keyboard::isKeyPressed(sf::Keyboard::Down)
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Up)) || sf::Keyboard::isKeyPressed(sf::Keyboard::S))
lastPlayerInput = kUp; return kDown;
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Down)) if (sf::Keyboard::isKeyPressed(sf::Keyboard::Right)
lastPlayerInput = kDown; || sf::Keyboard::isKeyPressed(sf::Keyboard::D))
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Right)) return kRight;
lastPlayerInput = kRight; return kNone;
return lastPlayerInput;
} }
bool PlayerOutput::IsOpen(void) bool PlayerOutput::IsOpen(void)
@ -47,8 +45,8 @@ namespace snakeplusplus
while (true) while (true)
{ {
gameWindow.pollEvent(event); gameWindow.pollEvent(event);
if ((event.type == sf::Event::Closed) || if ((event.type == sf::Event::Closed)
(sf::Keyboard::isKeyPressed(sf::Keyboard::Escape))) || (sf::Keyboard::isKeyPressed(sf::Keyboard::Escape)))
{ {
gameWindow.close(); gameWindow.close();
return; return;
@ -66,7 +64,7 @@ namespace snakeplusplus
textPosition.y = textPosition.y / 2; textPosition.y = textPosition.y / 2;
sf::Font font; sf::Font font;
font.loadFromFile("Arial.ttf"); font.loadFromFile("Arial.ttf");
sf::Text gameOverText("Game Over", font); sf::Text gameOverText("Game Over\nPress 'Enter' to play again", font);
gameOverText.setPosition(textPosition); gameOverText.setPosition(textPosition);
gameWindow.draw(gameOverText); gameWindow.draw(gameOverText);
gameWindow.display(); gameWindow.display();
@ -76,25 +74,22 @@ namespace snakeplusplus
void PlayerOutput::DisplayGameState(std::vector< std::vector<char> >& gameBoard) void PlayerOutput::DisplayGameState(std::vector< std::vector<char> >& gameBoard)
{ {
CheckWindowEvents(); CheckWindowEvents();
sf::Vector2f location;
char* letterOnBoard; char* letterOnBoard;
for (float y = 0; y < gameBoundaries.y; y++) for (float y = 0; y < gameBoundaries.y; y++)
{ {
for (float x = 0; x < gameBoundaries.x; x++) for (float x = 0; x < gameBoundaries.x; x++)
{ {
location.x = x; letterOnBoard = &gameBoard.at(y).at(x);
location.y = y;
letterOnBoard = &gameBoard.at(location.y).at(location.x);
switch (*letterOnBoard) switch (*letterOnBoard)
{ {
case 'O': case 'O':
DrawSnake(location); DrawSnake(sf::Vector2f(x, y));
break; break;
case 'X': case 'X':
DrawFood(location); DrawFood(sf::Vector2f(x,y));
break; break;
default: default:
DrawEmpty(location); DrawEmpty(sf::Vector2f(x,y));
break; break;
} }
} }
@ -116,8 +111,8 @@ namespace snakeplusplus
sf::Event event; sf::Event event;
while (gameWindow.pollEvent(event)) while (gameWindow.pollEvent(event))
{ {
if ((event.type == sf::Event::Closed) || if ((event.type == sf::Event::Closed)
(sf::Keyboard::isKeyPressed(sf::Keyboard::Escape))) || (sf::Keyboard::isKeyPressed(sf::Keyboard::Escape)))
gameWindow.close(); gameWindow.close();
} }
} }

View File

@ -8,14 +8,7 @@ const int kGridSize = 25;
namespace snakeplusplus namespace snakeplusplus
{ {
class PlayerInput
{
public:
PlayerInput(void);
PlayerDirection GetPlayerInput(void); PlayerDirection GetPlayerInput(void);
private:
PlayerDirection lastPlayerInput;
};
class PlayerOutput class PlayerOutput
{ {

View File

@ -1,9 +1,7 @@
// Snake.cpp // Snake.cpp
#include <algorithm>
#include <memory>
#include <queue> #include <queue>
#include <random>
#include <SFML/Graphics.hpp> #include <SFML/Graphics.hpp>
#include "common.hpp"
#include "snake.hpp" #include "snake.hpp"
namespace snakeplusplus namespace snakeplusplus
@ -12,26 +10,22 @@ namespace snakeplusplus
{ {
*(body.front()) = ' '; *(body.front()) = ' ';
body.pop(); body.pop();
return;
} }
Food::Food(void) void Snake::Reset(void)
{ {
generator.seed(std::random_device{}()); while (!body.empty()) Pop();
speed.x = 0;
speed.y = 0;
return;
} }
// Returns a new food object for the snakeFood // Returns a new food object for the snakeFood
void Food::GenerateNewFood(sf::Vector2f boundaries) void Food::GenerateNewFood(sf::Vector2f boundaries)
{ {
location.x = GenerateRandomNumber(boundaries.x); location.x = snakeplusplus::GenerateRandomNumber(boundaries.x);
location.y = GenerateRandomNumber(boundaries.y); location.y = snakeplusplus::GenerateRandomNumber(boundaries.y);
} return;
// Returns a newly generated number
int Food::GenerateRandomNumber(int generationLimit)
{
int generatedNumber;
std::uniform_int_distribution<> distribution(0, generationLimit - 1);
generatedNumber = distribution(generator);
return generatedNumber;
} }
} }

View File

@ -3,10 +3,7 @@
#define SNAKE_HPP #define SNAKE_HPP
#include <SFML/System/Vector2.hpp> #include <SFML/System/Vector2.hpp>
#include <memory>
#include <queue> #include <queue>
#include <random>
#include <SFML/Graphics.hpp>
namespace snakeplusplus namespace snakeplusplus
{ {
@ -17,18 +14,15 @@ namespace snakeplusplus
sf::Vector2f speed; sf::Vector2f speed;
std::queue<char*> body; std::queue<char*> body;
void Pop(void); void Pop(void);
void Reset(void);
}; };
struct Food struct Food
{ {
public: public:
Food(void);
sf::Vector2f location; sf::Vector2f location;
char* food; char* food;
void GenerateNewFood(sf::Vector2f boundaries); void GenerateNewFood(sf::Vector2f boundaries);
private:
std::default_random_engine generator;
int GenerateRandomNumber(int generationLimit);
}; };
} }