2022-08-15 23:51:18 -05:00
|
|
|
// GameState.cpp
|
2023-04-06 19:27:10 -05:00
|
|
|
#include <stdexcept>
|
2023-03-17 17:27:02 -05:00
|
|
|
#include <SFML/Graphics.hpp>
|
2023-08-19 12:56:40 -05:00
|
|
|
#include "botinterface.hpp"
|
2023-04-06 19:27:10 -05:00
|
|
|
#include "common.hpp"
|
|
|
|
#include "playerinterface.hpp"
|
|
|
|
#include "gamestate.hpp"
|
2022-07-28 15:18:24 -05:00
|
|
|
|
2024-08-02 19:45:07 -05:00
|
|
|
GameEngine::GameEngine()
|
2022-07-28 15:18:24 -05:00
|
|
|
{
|
2024-08-02 19:45:07 -05:00
|
|
|
InitializeGenerator();
|
|
|
|
return;
|
|
|
|
}
|
2023-03-17 20:13:50 -05:00
|
|
|
|
2024-08-02 19:45:07 -05:00
|
|
|
void GameEngine::Start()
|
|
|
|
{
|
|
|
|
PrepareGameBoard();
|
2024-08-02 21:23:49 -05:00
|
|
|
if (!state.m_bNoDisplay)
|
|
|
|
graphics.StartGameWindow();
|
2024-08-02 19:45:07 -05:00
|
|
|
Loop();
|
|
|
|
return;
|
|
|
|
}
|
2023-03-12 08:50:50 -05:00
|
|
|
|
2024-08-02 19:45:07 -05:00
|
|
|
void GameEngine::Reset()
|
|
|
|
{
|
2024-08-03 18:34:14 -05:00
|
|
|
if (!state.m_bIsBotControlled)
|
|
|
|
graphics.CheckContinue();
|
2024-08-02 19:45:07 -05:00
|
|
|
player.Reset();
|
|
|
|
PrepareGameBoard();
|
2024-08-02 21:23:49 -05:00
|
|
|
state.m_bIsGameOver = false;
|
2024-08-03 18:34:14 -05:00
|
|
|
if (state.m_bIsBotControlled) {
|
|
|
|
while (!bot.path.empty())
|
|
|
|
bot.path.pop();
|
|
|
|
if (state.m_bNoDisplay)
|
|
|
|
graphics.SetShowGame(false);
|
2024-08-03 01:26:10 -05:00
|
|
|
graphics.SetShowGame((bot.amountPlayed + 1) % 50 == 0);
|
2024-08-03 18:34:14 -05:00
|
|
|
bot.AddIteration(player.body.size());
|
|
|
|
}
|
2024-08-02 19:45:07 -05:00
|
|
|
}
|
2023-08-18 17:51:58 -05:00
|
|
|
|
2024-08-02 19:45:07 -05:00
|
|
|
void GameEngine::Loop(void)
|
|
|
|
{
|
|
|
|
int currentScore = 0;
|
2024-08-02 21:23:49 -05:00
|
|
|
while (graphics.IsOpen() || state.m_bNoDisplay)
|
2023-04-06 22:22:06 -05:00
|
|
|
{
|
2024-08-02 21:23:49 -05:00
|
|
|
if (state.m_bIsGameOver) { Reset(); }
|
2024-08-02 19:45:07 -05:00
|
|
|
UpdatePlayerSpeed();
|
|
|
|
PlaceNewSnakePart(MovePlayer());
|
|
|
|
RegenerateFood();
|
|
|
|
currentScore = player.body.size() * 100;
|
2024-08-02 21:23:49 -05:00
|
|
|
if (!state.m_bNoDisplay)
|
|
|
|
graphics.DisplayGameState(gameBoard, currentScore);
|
2023-04-06 22:22:06 -05:00
|
|
|
}
|
2024-08-02 19:45:07 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
sf::Vector2f GameEngine::MovePlayer(void)
|
|
|
|
{
|
|
|
|
return sf::Vector2f(player.headLocation.x + player.speed.x, player.headLocation.y + player.speed.y);
|
|
|
|
}
|
2023-03-17 21:07:58 -05:00
|
|
|
|
2024-02-01 12:50:10 -06:00
|
|
|
|
2024-08-02 19:45:07 -05:00
|
|
|
sf::Vector2f GameEngine::GetGameBoundaries(void)
|
|
|
|
{
|
|
|
|
return graphics.gameBoundaries;
|
|
|
|
}
|
2023-03-13 08:24:56 -05:00
|
|
|
|
2024-08-02 19:45:07 -05:00
|
|
|
void GameEngine::PlaceNewSnakePart(sf::Vector2f location) {
|
|
|
|
if (!player.speed.x && !player.speed.y) { return; }
|
|
|
|
try {
|
2024-08-02 21:23:49 -05:00
|
|
|
GameSpace* locationState = &gameBoard.at(location.y).at(location.x);
|
|
|
|
if (locationState->m_bSnake && (player.body.size() > 1)) {
|
|
|
|
state.m_bIsGameOver = true; // Game should end (Snake touching snake)
|
2023-04-06 19:27:10 -05:00
|
|
|
}
|
2024-08-02 21:23:49 -05:00
|
|
|
locationState->m_bSnake = true;
|
2024-08-02 19:45:07 -05:00
|
|
|
player.body.push(locationState);
|
|
|
|
player.headLocation = location;
|
|
|
|
if (playerFood.location != location)
|
|
|
|
player.Pop();
|
2024-08-03 01:26:10 -05:00
|
|
|
else {
|
2024-08-02 21:23:49 -05:00
|
|
|
locationState->m_bFood = false;
|
2024-08-03 01:26:10 -05:00
|
|
|
if (state.m_bIsBotControlled)
|
|
|
|
bot.ResetPath();
|
|
|
|
}
|
2024-08-02 19:45:07 -05:00
|
|
|
} catch (const std::out_of_range& error) {
|
2024-08-02 21:23:49 -05:00
|
|
|
state.m_bIsGameOver = true; // Snake ran into edge
|
2023-03-17 21:40:49 -05:00
|
|
|
}
|
2024-08-02 19:45:07 -05:00
|
|
|
return;
|
|
|
|
}
|
2022-08-02 21:17:23 -05:00
|
|
|
|
2024-02-01 12:50:10 -06:00
|
|
|
|
2024-08-02 19:45:07 -05:00
|
|
|
// Generates new food until not colliding with player
|
|
|
|
void GameEngine::RegenerateFood()
|
|
|
|
{
|
|
|
|
// Generate a new food location if the current one is occupied
|
2024-08-03 01:26:10 -05:00
|
|
|
while (gameBoard.at(playerFood.location.y).at(playerFood.location.x).m_bSnake) {
|
2024-08-02 19:45:07 -05:00
|
|
|
playerFood.GenerateNewFood(GetGameBoundaries());
|
2023-04-06 19:27:10 -05:00
|
|
|
}
|
2023-03-17 17:27:02 -05:00
|
|
|
|
2024-08-02 19:45:07 -05:00
|
|
|
// Update the game board with the new food location
|
2024-08-03 01:26:10 -05:00
|
|
|
gameBoard.at(playerFood.location.y).at(playerFood.location.x).m_bFood = 1;
|
2024-08-02 19:45:07 -05:00
|
|
|
}
|
|
|
|
|
2024-02-01 12:50:10 -06:00
|
|
|
|
2024-08-02 19:45:07 -05:00
|
|
|
void GameEngine::PrepareGameBoard(void)
|
|
|
|
{
|
|
|
|
gameBoard.clear();
|
|
|
|
sf::Vector2f boardDimensions = GetGameBoundaries();
|
2024-08-02 21:23:49 -05:00
|
|
|
gameBoard.resize(boardDimensions.y, std::vector<GameSpace>(boardDimensions.x));
|
2024-08-02 19:45:07 -05:00
|
|
|
// Snake setup
|
|
|
|
player.headLocation.x = GenerateRandomNumber(boardDimensions.x);
|
|
|
|
player.headLocation.y = GenerateRandomNumber(boardDimensions.y);
|
2022-08-02 21:17:23 -05:00
|
|
|
{
|
2024-08-03 01:26:10 -05:00
|
|
|
GameSpace* locationState = &gameBoard.at(player.headLocation.y).at(player.headLocation.x);
|
2024-08-02 19:45:07 -05:00
|
|
|
player.body.push(locationState);
|
2024-08-02 21:23:49 -05:00
|
|
|
locationState->m_bSnake = true;
|
2023-04-06 22:22:06 -05:00
|
|
|
}
|
2024-08-02 19:45:07 -05:00
|
|
|
// Food setup
|
|
|
|
playerFood.GenerateNewFood(boardDimensions);
|
2024-08-03 01:26:10 -05:00
|
|
|
gameBoard.at(playerFood.location.y).at(playerFood.location.x).m_bFood = true;
|
2024-08-02 19:45:07 -05:00
|
|
|
return;
|
|
|
|
}
|
2023-04-06 22:22:06 -05:00
|
|
|
|
2024-08-02 19:45:07 -05:00
|
|
|
void GameEngine::UpdatePlayerSpeed(void)
|
|
|
|
{
|
|
|
|
PlayerDirection controller;
|
2024-08-02 21:23:49 -05:00
|
|
|
if (state.m_bIsBotControlled) {
|
2024-08-02 19:45:07 -05:00
|
|
|
if (bot.path.empty()) {
|
2024-08-03 01:26:10 -05:00
|
|
|
bot.GetNewPath(player.headLocation, GetGameBoundaries(), player.body.size());
|
2023-04-06 22:22:06 -05:00
|
|
|
}
|
2024-08-02 19:45:07 -05:00
|
|
|
controller = bot.GetInput(&player.headLocation);
|
2022-08-02 21:17:23 -05:00
|
|
|
}
|
2024-08-02 19:45:07 -05:00
|
|
|
else { controller = GetPlayerInput(); }
|
|
|
|
switch (controller) {
|
|
|
|
case kUp:
|
|
|
|
if (player.speed.y == kUnitSpeed) { break; }
|
|
|
|
player.speed.x = 0;
|
|
|
|
player.speed.y = -kUnitSpeed;
|
|
|
|
break;
|
|
|
|
case kLeft:
|
|
|
|
if (player.speed.x == kUnitSpeed) { break; }
|
|
|
|
player.speed.x = -kUnitSpeed;
|
|
|
|
player.speed.y = 0;
|
|
|
|
break;
|
|
|
|
case kRight:
|
|
|
|
if (player.speed.x == -kUnitSpeed) { break; }
|
|
|
|
player.speed.x = kUnitSpeed;
|
|
|
|
player.speed.y = 0;
|
|
|
|
break;
|
|
|
|
case kDown:
|
|
|
|
if (player.speed.y == -kUnitSpeed) { break; }
|
|
|
|
player.speed.x = 0;
|
|
|
|
player.speed.y = kUnitSpeed;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
2024-02-01 12:50:10 -06:00
|
|
|
}
|
2024-08-02 19:45:07 -05:00
|
|
|
return;
|
|
|
|
}
|