Long-Starlight-Snake-Game/Snake.hpp

263 lines
6.4 KiB
C++

#include "SynEngine.hpp"
#include <time.h>
enum CellState
{
EmptyCell,
PointCell,
SnakeCell
};
enum PlayerSprite
{
Empty,
Point,
Straight,
Curved,
Back,
Head,
PointGot,
GameOver
};
struct SnakePart
{
sf::Vector2i cellPosition;
unsigned direction;
};
class Snake : public IBehaviour
{
private:
std::vector<SnakePart> snake;
unsigned int lenght;
SnakePart *backSecond;
SnakePart *back;
SnakePart *headSecond;
SnakePart *head;
Timer *timer;
Grid *grid;
sf::Vector2i gridSize;
float timeCountdown;
float timeResetValue;
unsigned TickPerSec;
GameConfiguration *config;
sf::Vector2i pointPosition;
void Move();
void Grow();
void ResetPointPosition();
int GetRandom(int, int);
unsigned GetDirection(sf::Vector2i, sf::Vector2i);
unsigned GetBackDirection();
unsigned GetMoveDirection();
sf::Vector2i GetDirectionVector(unsigned);
PlayerSprite GetNewSprite(unsigned &);
CellState NextCellState();
public:
Snake();
void Update();
~Snake();
};
Snake::Snake()
{
pointPosition = { 0, 0 }; // TEST
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 = backSecond = &snake[0];
back = headSecond = &snake[1];
config = GameManager::GetConfig();
grid = &GameManager::GetGrid();
gridSize = config -> GetGridSize();
TickPerSec = config -> GetTickPerSec();
timeResetValue = 1.0 / (float)TickPerSec;
timeCountdown = timeResetValue;
grid -> UpdateCell(snake[0].cellPosition.x, snake[0].cellPosition.y, PlayerSprite::Head, 0);
grid -> UpdateCell(snake[1].cellPosition.x, snake[1].cellPosition.y, PlayerSprite::Back, 0);
ResetPointPosition();
}
int Snake::GetRandom(int min, int max)
{
int result;
static float value = 0.0;
value += GameManager::timer.GetTimePassed();
srand(value);
result = rand() % (max - min);
result += min;
return result;
}
void Snake::ResetPointPosition()
{
bool isInside = false;
int i;
do
{
isInside = false;
pointPosition = sf::Vector2i(GetRandom(0, gridSize.x), GetRandom(0, gridSize.y));
for (i = 0; i < lenght; i++)
if(snake[i].cellPosition == pointPosition)
{
isInside = true;
break;
}
} while (isInside);
grid -> UpdateCell(pointPosition.x, pointPosition.y, PlayerSprite::Point, 0);
}
void Snake::Grow()
{
sf::Vector2i secondPosition;
sf::Vector2i headPosition = head -> cellPosition;
unsigned previousDirection;
unsigned headDirection;
PlayerSprite sprite;
headDirection = GetMoveDirection();
headPosition += GetDirectionVector(headDirection);
grid -> ApplyGridLimitsToVector2i(headPosition);
snake.insert(snake.begin(), { headPosition, headDirection });
lenght = snake.size();
previousDirection = snake[1].direction;
sprite = GetNewSprite(previousDirection);
head = &snake[0]; headSecond = &snake[1];
back = &snake[lenght - 1]; backSecond = &snake[lenght - 2];
grid -> UpdateCell(headPosition.x, headPosition.y, PlayerSprite::Head, headDirection);
grid -> UpdateCell(headSecond -> cellPosition.x, headSecond -> cellPosition.y, sprite, (int)previousDirection);
}
void Snake::Move()
{
grid -> UpdateCell(back -> cellPosition.x, back -> cellPosition.y, PlayerSprite::Empty);
snake.pop_back();
Grow();
grid -> UpdateCell(back -> cellPosition.x, back -> cellPosition.y, PlayerSprite::Back, GetBackDirection());
}
void Snake::Update()
{
if(timeCountdown > 0.0)
{
timeCountdown -= timer -> GetDeltaTime();
return;
}
switch (NextCellState())
{
case CellState::EmptyCell: Move(); break;
case CellState::PointCell: Grow(); ResetPointPosition(); break;
// case CellState::SnakeCell: GameOver(); break;
}
timeCountdown = timeResetValue;
}
unsigned Snake::GetMoveDirection()
{
// Check if the new direction is opposite to the head's direction
unsigned direction = head -> direction;
unsigned inputDirection = GameManager::GetInputDirection();
if((inputDirection + 2) % 4 != direction)
return inputDirection;
return direction;
}
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);
}
}
CellState Snake::NextCellState()
{
sf::Vector2i cellPosition = head -> cellPosition + GetDirectionVector(GetMoveDirection());
grid -> ApplyGridLimitsToVector2i(cellPosition);
for (int i = 0; i < lenght; i++)
if(snake[i].cellPosition == cellPosition)
return CellState::SnakeCell;
if(cellPosition == pointPosition)
return CellState::PointCell;
return CellState::EmptyCell;
}
PlayerSprite Snake::GetNewSprite(unsigned &direction)
{
SnakePart *third = &snake[2];
SnakePart *second = headSecond;
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()
{
}