snakeplusplus/src/gamestate.cpp

159 lines
4.8 KiB
C++
Raw Normal View History

// GameState.cpp
#include <stdexcept>
#include <SFML/Graphics.hpp>
#include "botinterface.hpp"
#include "common.hpp"
#include "playerinterface.hpp"
#include "gamestate.hpp"
namespace snakeplusplus
{
GameEngine::GameEngine()
2023-03-17 20:13:50 -05:00
{
2023-08-19 23:32:53 -05:00
InitializeGenerator();
return;
2023-03-17 20:13:50 -05:00
}
void GameEngine::Start()
{
PrepareGameBoard();
graphics.StartGameWindow();
Loop();
return;
}
2023-03-12 08:50:50 -05:00
void GameEngine::Reset()
{
2023-08-19 23:32:53 -05:00
graphics.CheckContinue(isBotControlled);
player.Reset();
2023-10-13 19:07:08 -05:00
if (isBotControlled) {
while (!bot.path.empty()) { bot.path.pop(); }
}
PrepareGameBoard();
2023-08-19 23:32:53 -05:00
isGameOver = false;
2023-08-18 18:09:09 -05:00
return;
}
void GameEngine::Loop(void)
{
2023-10-23 21:33:47 -05:00
int currentScore = 0;
while (graphics.IsOpen())
{
if (isGameOver) { Reset(); }
UpdatePlayerSpeed();
PlaceNewSnakePart(MovePlayer());
2023-04-15 05:15:11 -05:00
RegenerateFood();
2023-10-23 21:33:47 -05:00
currentScore = player.body.size() * 100;
bot.UpdateProbability(player.body.size());
2023-10-23 21:33:47 -05:00
graphics.DisplayGameState(gameBoard, currentScore);
}
return;
}
2023-05-17 20:20:01 -05:00
sf::Vector2f GameEngine::MovePlayer(void)
{
sf::Vector2f newHeadPosition;
newHeadPosition.x = player.headLocation.x + player.speed.x;
newHeadPosition.y = player.headLocation.y + player.speed.y;
return newHeadPosition;
}
sf::Vector2f GameEngine::GetGameBoundaries(void)
{
return graphics.gameBoundaries;
}
void GameEngine::PlaceNewSnakePart(sf::Vector2f location)
{
2023-08-18 22:36:47 -05:00
if (!player.speed.x && !player.speed.y) { return; }
try
{
2023-04-15 05:15:11 -05:00
char* locationState;
locationState = &gameBoard.at(location.y).at(location.x);
2023-08-18 18:09:09 -05:00
if (*locationState == 'O' && (player.body.size() > 1))
isGameOver = true; // Game should end (Snake touching snake)
2023-04-15 05:15:11 -05:00
*locationState = 'O';
player.body.push(locationState);
player.headLocation = location;
if (playerFood.location != location)
player.Pop();
} catch (const std::out_of_range& error) {
isGameOver = true; // Snake ran into edge
}
2023-08-18 18:09:09 -05:00
return;
}
// Generates new food until not colliding with player
void GameEngine::RegenerateFood(void)
{
sf::Vector2f newLocation = playerFood.location;
bool isUpdated = false;
while (gameBoard.at(newLocation.y).at(newLocation.x) == 'O')
{
isUpdated = true;
playerFood.GenerateNewFood(GetGameBoundaries());
newLocation = playerFood.location;
}
2023-10-13 19:07:08 -05:00
if (isUpdated) {
gameBoard.at(newLocation.y).at(newLocation.x) = 'X';
}
return;
}
void GameEngine::PrepareGameBoard(void)
{
gameBoard.clear();
sf::Vector2f boardDimensions = GetGameBoundaries();
2023-04-15 05:15:11 -05:00
gameBoard.resize(boardDimensions.y, std::vector<char> (boardDimensions.x, ' '));
2023-08-18 19:51:15 -05:00
// Snake setup
player.headLocation.x = GenerateRandomNumber(boardDimensions.x);
player.headLocation.y = GenerateRandomNumber(boardDimensions.y);
2023-08-18 19:51:15 -05:00
{
char* locationState = &gameBoard.at(player.headLocation.y).at(player.headLocation.x);
player.body.push(locationState);
*locationState = 'O';
}
// Food setup
playerFood.GenerateNewFood(boardDimensions);
gameBoard.at(playerFood.location.y).at(playerFood.location.x) = 'X';
return;
}
void GameEngine::UpdatePlayerSpeed(void)
{
PlayerDirection controller;
2023-10-13 19:07:08 -05:00
if (isBotControlled) {
if (bot.path.empty()) {
2023-10-13 19:22:11 -05:00
bot.GetNewPath(gameBoard, player.headLocation, GetGameBoundaries(), player.body.size());
2023-10-13 19:07:08 -05:00
}
controller = bot.GetInput(&player.headLocation);
}
else { controller = GetPlayerInput(); }
switch (controller) {
case kUp:
2023-08-19 23:32:53 -05:00
if (player.speed.y == kUnitSpeed) { break; }
player.speed.x = 0;
2023-08-19 23:32:53 -05:00
player.speed.y = -kUnitSpeed;
2023-04-15 05:15:11 -05:00
break;
case kLeft:
2023-08-19 23:32:53 -05:00
if (player.speed.x == kUnitSpeed) { break; }
player.speed.x = -kUnitSpeed;
player.speed.y = 0;
2023-04-15 05:15:11 -05:00
break;
case kRight:
2023-08-19 23:32:53 -05:00
if (player.speed.x == -kUnitSpeed) { break; }
player.speed.x = kUnitSpeed;
player.speed.y = 0;
2023-04-15 05:15:11 -05:00
break;
case kDown:
2023-08-19 23:32:53 -05:00
if (player.speed.y == -kUnitSpeed) { break; }
player.speed.x = 0;
2023-08-19 23:32:53 -05:00
player.speed.y = kUnitSpeed;
2023-04-15 05:15:11 -05:00
break;
default:
break;
}
2023-08-18 18:09:09 -05:00
return;
}
}