263 lines
6.4 KiB
C++
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()
|
|
{
|
|
}
|