I've implemented tilemap collision into my game, it works but the problem comes when I'm colliding on one axis and trying to move on the other. I can't slide along the wall.
in Player.cpp
void Player::update(float delta, std::vector<Tile>& tiles) {
if (sf::Keyboard::isKeyPressed(sf::Keyboard::W) || sf::Keyboard::isKeyPressed(sf::Keyboard::Up) || sf::Joystick::getAxisPosition(0, sf::Joystick::Y) < -20) {
newPos.y -= speed * delta;
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::A) || sf::Keyboard::isKeyPressed(sf::Keyboard::Left) || sf::Joystick::getAxisPosition(0, sf::Joystick::X) < -20) {
newPos.x -= speed * delta;
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::S) || sf::Keyboard::isKeyPressed(sf::Keyboard::Down) || sf::Joystick::getAxisPosition(0, sf::Joystick::Y) > 20) {
newPos.y += speed * delta;
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::D) || sf::Keyboard::isKeyPressed(sf::Keyboard::Right) || sf::Joystick::getAxisPosition(0, sf::Joystick::X) > 20) {
newPos.x += speed * delta;
}
sf::Vector2f oldPos = sprite.getPosition();
move(delta, newPos);
for (int i = 0; i < tiles.size(); i++) {
if (Collision::PixelPerfectTest(sprite, tiles[i].sprite) && tiles[i].collision) {
sprite.setPosition(oldPos);
newPos = oldPos;
}
}
}
void Player::move(float delta, sf::Vector2f position) {
sprite.setPosition(position);
}
In Collision.cpp
bool PixelPerfectTest(const sf::Sprite& Object1, const sf::Sprite& Object2, sf::Uint8 AlphaLimit) {
sf::FloatRect Intersection;
if (Object1.getGlobalBounds().intersects(Object2.getGlobalBounds(), Intersection)) {
sf::IntRect O1SubRect = Object1.getTextureRect();
sf::IntRect O2SubRect = Object2.getTextureRect();
sf::Uint8* mask1 = Bitmasks.GetMask(Object1.getTexture());
sf::Uint8* mask2 = Bitmasks.GetMask(Object2.getTexture());
// Loop through our pixels
for (int i = Intersection.left; i < Intersection.left + Intersection.width; i++) {
for (int j = Intersection.top; j < Intersection.top + Intersection.height; j++) {
sf::Vector2f o1v = Object1.getInverseTransform().transformPoint(i, j);
sf::Vector2f o2v = Object2.getInverseTransform().transformPoint(i, j);
// Make sure pixels fall within the sprite's subrect
if (o1v.x > 0 && o1v.y > 0 && o2v.x > 0 && o2v.y > 0 &&
o1v.x < O1SubRect.width && o1v.y < O1SubRect.height &&
o2v.x < O2SubRect.width && o2v.y < O2SubRect.height) {
if (Bitmasks.GetPixel(mask1, Object1.getTexture(), (int)(o1v.x) + O1SubRect.left, (int)(o1v.y) + O1SubRect.top) > AlphaLimit &&
Bitmasks.GetPixel(mask2, Object2.getTexture(), (int)(o2v.x) + O2SubRect.left, (int)(o2v.y) + O2SubRect.top) > AlphaLimit)
return true;
}
}
}
}
return false;
}
That's because your collision test is all or nothing. I would do extra collision tests to see if the x or y new position is valid or not, something like:
if (tiles[i].collision && Collision::PixelPerfectTest(sprite, tiles[i].sprite))
{
sf::Vector2f checkPosX = newPos;
sf::Vector2f checkPosY = newPos;
checkPosX.y = oldPos.y;
checkPosY.x = oldPos.x;
sprite.setPosition(checkPosX);
if (!Collision::PixelPerfectTest(sprite, tiles[i].sprite))
{
newPos = checkPosX;
}
else
{
sprite.setPosition(checkPosY);
if (!Collision::PixelPerfectTest(sprite, tiles[i].sprite))
{
newPos = checkPosY;
}
else
{
sprite.setPosition(oldPos);
newPos = oldPos;
}
}
}
As an aside, if you do test tiles[i].collision first you will skip the more expensive PixelPerfectTest() test for non-collision tiles due to the expression short-circuiting.
Related
I was making a super-mario-like game in C++/SFML and while trying to write some code for Mario collisions, I had some problems: The character, when collides with a vertical stack of blocks while moving along the horizontal axis, get stuck on one side of the blocks, like if it is walking on an invisible block. I tried to modify the collision function like making mario to collide with blocks horizontally only if his position related to blocks is contained into the block coordinates.
I include some code for the movement(keyPressed is a function that returns the key pressed):
void Player::movement(Time& gameTime) {
player.move(v * gameTime.asSeconds());
view.setCenter(player.getPosition().x + 16, 590);
if (keyPressed(up) && !jumping) {
jumping = true;
v.y = jumpSpeed;
}
if (v.y > 200) {
jumping = true;
}
else {
crouch = false;
}
if (keyPressed(left)) {
if (v.x > -moveSpeed) {
v.x -= 100;
}
else {
v.x = -moveSpeed;
}
}
else if (keyPressed(right)) {
noKeyPressed = false;
if (v.x < moveSpeed) {
v.x += 100;
}
else {
v.x = moveSpeed;
}
}
else {
if (v.x < -100) {
v.x += 100;
}
else if (v.x > 100) {
v.x -= 100;
}
else {
v.x = 0;
}
}
gravity();
if (big) { //Big is a variable that tells me if mario is big or small
heightValue = 33; //heightValue is a variable that stores the sprite height in pixels
}
else {
heightValue = 16;
}
}
void Player::gravity() {
if (!big) {
if (player.getPosition().y + 32 < 1100) {
if (v.y < maxSpeed) {
v.y += 100;
}
}
if (alive) { //This is useful to check if big mario has fallen
if (player.getPosition().y + 32 >= 1200) {
player.setPosition(player.getPosition().x, 1200 - 32);
jumping = false;
alive = false;
}
}
}
else {
if (player.getPosition().y + 64 < 1100) {
if (v.y < maxSpeed) {
v.y += 100;
}
}
if (alive) { //This is useful to check if small mario has fallen
if (player.getPosition().y + 64 >= 1200) {
player.setPosition(player.getPosition().x, 1200 - 64);
jumping = false;
alive = false;
}
}
}
}
And the collision function, where the block class has 4 small blocks around the block sprite that simplify collisions:
void Player::collisions(Block* block) {
if (this->player.getGlobalBounds().intersects(block->up.getGlobalBounds())) {
if (!big) {
if (this->player.getPosition().y + heightValue <= block->block.getPosition().y) {
this->player.setPosition(this->player.getPosition().x, block->up.getPosition().y - 32);
v.y = 0;
jumping = false;
score = 100;
}
}
else {
if (this->player.getPosition().y + heightValue <= block->block.getPosition().y) {
this->player.setPosition(this->player.getPosition().x, block->up.getPosition().y - 64);
v.y = 0;
jumping = false;
score = 100;
}
}
}
if (this->player.getGlobalBounds().intersects(block->down.getGlobalBounds())) {
this->player.setPosition(this->player.getPosition().x, block->down.getPosition().y + 1);
v.y = 0;
}
if (this->player.getGlobalBounds().intersects(block->left.getGlobalBounds()) && v.x > 0) {
this->player.setPosition(block->left.getPosition().x - 32, this->player.getPosition().y);
}
else if (this->player.getGlobalBounds().intersects(block->right.getGlobalBounds()) && v.x < 0) {
this->player.setPosition(block->right.getPosition().x + 1, this->player.getPosition().y);
}
}
I hope I explained accurately the problem.
simply do your collision detection one axis at a time, this allows nice smooth movement along tiles
pseudocode example:
//X axis
oldPos = position
if(leftKey):
position.x -= speed
if(rightKey):
position.x += speed
if(collision):
position = oldPos
//Y axis
oldPos = position
if(upKey):
position.y -= speed
if(downKey):
position.y += speed
if(collision):
position = oldPos
I'm fighting with this for like few days, and I have no idea, how to do that, so I'd like to ask you for help. I've got no idea how collision should look like right here, so player could jump through 'down zone' of the block, and stay right on the block.
block.cpp
bool block::CollidingWithPlayer(character& player) {
for (int i = 1; i < MAX_BLOCKS; i++) {
if (player.x + player.width >= coordinateX[i] && player.x <= coordinateX[i] + width[i] && player.y + player.height >= coordinateY[i] && player.y <= coordinateY[i] + block_height) {
player.onGround = true;
return true;
}
}
}
character.cpp
void character::startJump(map& Map, character& player) {
if (onGround)
{
vel[1] = -11.0;
onGround = false;
}
}
void character::updateJump(block& Block, character& player) {
if (!onGround) {
Block.CollidingWithPlayer(player);
vel[1] += 0.5;
y += vel[1];
x += vel[0];
}
if (y > 460){
y = 460;
vel[1] = 0.0;
onGround = true;
vel[0] = 0.0;
}
if ((x + width >= START_OF_RIGHT_WALL && x <= WALL_WIDTH + START_OF_RIGHT_WALL) || (x + width >= START_OF_LEFT_WALL &&x <= START_OF_LEFT_WALL + WALL_WIDTH)){
vel[0] *= -1;
bound = true;
if (direction == 1)
direction = 2;
else if (direction == 2)
direction = 1;
}
}
Okay so I am a college student and our professor gave us this code to examine, and I was wondering if there was another way to do this but for OS X. My professor is using a HANDLE which I barely understand what that is, the professor was telling me he create the HANDLE as a pointer to the output stream so what would be the equivalent to it for mac since we don't have #include Windows.h obviously. Everything you see in this code is my professor's, including the comments.
//This is an example of a simple platformer made in the console. This
//makes no claims as the best way of doing things as I created this
//live before a class (while taking suggestions from them).
#include <iostream>
#include <string>
#include <vector>
#include <Windows.h>
using namespace std;
const int MAX_ROWS = 20;
const int MAX_COLS = 60;
//this is a reference to cout (we got this when we changed the output color)
//we can use this to setCursorPosition
HANDLE output = GetStdHandle(STD_OUTPUT_HANDLE);
//this is the place that we can set the cursor to when we are not using it
COORD zero;
//basic cardinal directions
enum Direction
{
UP = 8,
DOWN = 2,
RIGHT = 6,
LEFT = 4,
NORTH = UP,
SOUTH = DOWN,
EAST = RIGHT,
WEST = LEFT
};
//each place on the gameboard is a tile (tiles in this game are 1 character in length, though they do not have to be)
class Tile
{
public:
char display;
bool isPassible;
COORD pos;
Tile(char d, bool b, int y, int x)
{
display = d;
isPassible = b;
pos.X = x;
pos.Y = y;
}
void Display()
{
SetConsoleCursorPosition(output, pos);
cout << display;
SetConsoleCursorPosition(output, zero);
}
};
class Player
{
public:
COORD pos;
char display;
int JumpAmt;
//player constructor (x and y are starting location)
Player(int x, int y)
{
pos.X = x;
pos.Y = y;
display = 'C';
JumpAmt = 0;
}
//This gets the input and decides how to use it (this should be called in the main game loop)
bool Act(vector<vector<Tile>> GameBoard)
{
bool didMove = false;
COORD oldPos;
oldPos.X = pos.X;
oldPos.Y = pos.Y;
if (GetAsyncKeyState(VK_RIGHT) & 0x8000)
{
//make sure the movement is not off the game board and that there is not a wall in the way
if (pos.X + 1 < MAX_COLS && GameBoard[pos.Y][pos.X + 1].isPassible)
{
//actually move the character
pos.X += 1;
didMove = true;
}
}
if (GetAsyncKeyState(VK_LEFT) & 0x8000)
{
if (pos.X - 1 > 0 && GameBoard[pos.Y][pos.X - 1].isPassible)
{
pos.X -= 1;
didMove = true;
}
}
//You can only jump if you are on the ground
if (pos.Y + 1 < MAX_ROWS && !(GameBoard[pos.Y + 1][pos.X].isPassible))
{
if (GetAsyncKeyState(VK_UP) & 0x8000)
{
if (pos.Y - 1 > 0 && GameBoard[pos.Y - 1][pos.X].isPassible)
{
pos.Y -= 1;
didMove = true;
JumpAmt = 4;
}
}
}
//When you are not jumping fall (gravity)
if (JumpAmt == 0)
{
if (pos.Y + 1 < MAX_ROWS && GameBoard[pos.Y + 1][pos.X].isPassible)
{
pos.Y += 1;
didMove = true;
}
}
//This is what happens during your jump
if (JumpAmt > 0)
{
JumpAmt--;
if (pos.Y - 1 > 0 && GameBoard[pos.Y - 1][pos.X].isPassible)
{
pos.Y -= 1;
didMove = true;
}
}
//If you did move anywhere then update the board
if (didMove)
{
Display(oldPos, GameBoard);
}
return didMove;
}
void Display()
{
//draw myself at my position
SetConsoleCursorPosition(output, pos);
cout << display;
SetConsoleCursorPosition(output, zero);
}
void Display(COORD fix, vector<vector<Tile>> GameBoard)
{
//clear my old position
GameBoard[fix.Y][fix.X].Display();
Display();
}
};
int main()
{
//zero is used after anything is drawn to reset the cursor (this should never be changed after this)
zero.X = 0;
zero.Y = 0;
//this is a 2 dimentional array of tiles
vector<vector<Tile>> GameBoard;
//init all the tiles to blank (we will later add in platforms and stuff over top of these)
for (int row = 0; row < MAX_ROWS; row++)
{
vector<Tile> thisRow;
for (int col = 0; col < MAX_COLS; col++)
{
thisRow.push_back(Tile(' ', true, row, col));
}
GameBoard.push_back(thisRow);
}
//Build the game specific tiles (in a perfect world these would be read in from a file)
GameBoard[4][2] = Tile('-', false,4,2);
GameBoard[4][3] = Tile('-', false, 4,3);
GameBoard[4][4] = Tile('-', false, 4,4);
GameBoard[4][5] = Tile('-', false, 4,5);
GameBoard[4][6] = Tile('-', false, 4,6);
GameBoard[7][9] = Tile('-', false, 7,9);
GameBoard[7][10] = Tile('-', false, 7,10);
GameBoard[5][10] = Tile('-', false, 5,10);
GameBoard[8][14] = Tile('*', false, 8, 14); //this marks the win square
//display the board once
for (int row = 0; row < MAX_ROWS; row++)
{
for (int col = 0; col < MAX_COLS; col++)
{
GameBoard[row][col].Display();
}
}
//Bob is our hero
Player bob = Player(3, 3);
while (true)
{
bob.Act(GameBoard);
bob.Display();
Sleep(50);
//if bob falls down he dies
if (bob.pos.Y > 18)
{
bob.pos.X = 3;
bob.pos.Y = 3;
//bob.display = 65 + rand() % 26;
}
//if bob gets here he wins
if (bob.pos.Y == 7 && bob.pos.X == 14)
{
COORD pos;
pos.Y = 20;
pos.X = 0;
SetConsoleCursorPosition(output, pos);
cout << "You are Awesome";
break;
}
}
COORD pos;
pos.Y = 21;
pos.X = 0;
SetConsoleCursorPosition(output, pos);
system("Pause");
return 0;
}
I posted a different question earlier that gave me a bug using D3DPT_TRIANGLEFAN but I tried to recode my circle differently. Only problem is that it doesn't draw to the screen... I have tried debugging it but everything seems to be going perfect which is weird.
Here is my whole "Circle' class (This is part of a larger program a Pong game)
class Circle: public physicsObject
{
public:
Circle(float x, float y, float r, D3DCOLOR col){
xVel=3;
yVel=3;
xLB=0.0;
xRB=800;
yUB=600;
yLB=0;
this->r=r;
this->x=x;
this->y=y;
for(float i = 0.0f; i<360.0f; i += 1.0f)
{
float angle = i;
points[(int)i].x = x + (sinD(angle) * r);
points[(int)i].y = y + (cosD(angle) * r);
points[(int)i].z = 0;
points[(int)i].Color = col;
}
}
void update()
{
for(int i = 0; i < paddles.size(); ++i)
{
if(paddles[i]->left)
{
if(x - r + xVel < paddles[i]->x + 20 && y+yVel > paddles[i]->y && y+yVel< paddles[i]->y+80){
xVel *= -1;
}
}else{
if(x + r + xVel > paddles[i]->x && y+yVel > paddles[i]->y && y+yVel< paddles[i]->y+80){
xVel *= -1;
}
}
}
if(x+r+10+xVel>xRB || x-r+xVel < xLB)
{
//MessageBox(0,"AWW SHEEIT","I LOSED",MB_OK);
//ExitProcess(0);
}
if(y+r+30+yVel > yUB || y-r+yVel < yLB)
yVel*=-1;
translate(xVel,yVel);
}
void translate(float x, float y)
{
if(GetAsyncKeyState(VK_SPACE))
{
gamestart = true;
}
if(gamestart){
this->x+=x;
this->y+=y;
for(int i = 0; i < 360; ++i)
{
points[i].x+=x;
points[i].y+=y;
}
}
}
void render()
{
update();
d3ddev->SetTexture(0,0);
d3ddev->SetFVF((D3DFVF_XYZRHW | D3DFVF_DIFFUSE));
d3ddev->SetRenderState( D3DRS_LIGHTING, FALSE);
d3ddev->SetRenderState( D3DRS_CULLMODE, D3DCULL_CCW);
d3ddev->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
d3ddev->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );
d3ddev->SetRenderState( D3DRS_ZENABLE, D3DZB_FALSE );
d3ddev->SetRenderState( D3DRS_FOGENABLE, false);
d3ddev->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 360, &points, sizeof(360));
}
Vertex points [360];
private:
float r;
};
Thanks for the help ahead of time!
This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 11 years ago.
I'm writing Snake in C++, using OpenGL and GLFW. I'm trying to implement a feature where the game exits, when the snakes head crashes into its body.
Here are the move() and CrashCheck() functions of the Snake class that I wrote.
x_pos is a floating point array that stores the x_coordinate of a segment of the snake body. y_pos does the same with the y_coordinate. length is the number of body segments in the snake, and increases when the snake eats food(not yet implemented). x_speed and y_speed store the speeds of the segments along the axis. The snake can never move along both the axes simultaneously; Also, float MAX_S = 0.00075;. I've included my draw() function as well. And Fix_Snake_x and Fix_Snake_y are functions that realign the segments of the snake (because they kept separating and causing havoc with the game). I know it's a stupid way to correct the problem, so if you can suggest fixes in the move() function, that would helpful.
void draw(float win_aspect)
{
for(int a = 0; a < length; a++)
{
Fix_Snake_y();
glBegin(GL_QUADS);
glColor3f(1.0,0.0,0.0);
glVertex2f(x_pos[a],y_pos[a]);
glVertex2f((x_pos[a]+0.05),y_pos[a]);
glVertex2f((x_pos[a]+0.05),y_pos[a]-0.05);
glVertex2f(x_pos[a],y_pos[a] - 0.05);
glEnd();
Fix_Snake_x();
}
}
void move()
{
for(int a = length ; a >= 0; a--)
{
if(a > 0)
{
if(x_pos[a] >= x_pos[a-1] && x_speed[a] < 0)
{
x_pos[a] += -MAX_S;
Fix_Snake_y();
Fix_Snake_x();
if(x_pos[a] <= x_pos[a - 1])
{
x_speed [a] = 0;
if(y_pos[a] <= y_pos[a-1])
{
y_speed[a] = MAX_S;
}
else
{
y_speed[a] = -MAX_S;
}
}
}
if(x_pos[a] <= x_pos[a-1] && x_speed[a] > 0)
{
x_pos[a] += MAX_S;
Fix_Snake_y();
Fix_Snake_x();
if(x_pos[a] >= x_pos[a - 1])
{
x_speed [a] = 0;
if(y_pos[a] <= y_pos[a-1])
{
y_speed[a] = MAX_S;
}
else
{
y_speed[a] = -MAX_S;
}
}
}
if(y_pos[a] <= y_pos[a-1] && y_speed[a] > 0)
{
y_pos[a] += MAX_S;
Fix_Snake_y();
Fix_Snake_x();
if(y_pos[a] >= y_pos[a-1])
{
y_speed[a] = 0;
if(x_pos[a] >= x_pos[a-1])
{
x_speed[a] = -MAX_S;
}
if(x_pos[a] <= x_pos[a-1])
{
x_speed[a] = MAX_S;
}
}
}
if(y_pos[a] >= y_pos[a-1] && y_speed[a] < 0)
{
y_pos[a] += -MAX_S;
Fix_Snake_y();
Fix_Snake_x();
if(y_pos[a] <= y_pos[a-1])
{
y_speed[a] = 0;
if(x_pos[a] >= x_pos[a-1])
{
x_speed[a] = -MAX_S;
}
if(x_pos[a] <= x_pos[a-1])
{
x_speed[a] = MAX_S;
}
}
}
}
if(a == 0)
{
x_pos[0] += x_speed[0];
y_pos[0] += y_speed[0];
Fix_Snake_y();
Fix_Snake_x();
}
CrashCheck();
}
}
void CrashCheck()
{
for(int a = 1; a < length; a++)
{
if(y_speed[0] > 0 && y_speed[a] == 0)
{
if(x_pos[0] < x_pos[a] && x_pos[0] < x_pos[a] + 0.05)
{
if(y_pos[0] < y_pos[a] && y_pos[0] > y_pos[a] - 0.05)
{
exit(0);
}
}
}
else if(y_speed[0] < 0 && y_speed[a] == 0)
{
if(x_pos[0] > x_pos[a] && x_pos[0] < x_pos[a] + 0.05)
{
if(y_pos[0] < y_pos[a] && y_pos[0] > y_pos[a] - 0.05)
{
exit(0);
}
}
}
}
}
void Fix_Snake_x()
{
for(int a = 1; a<length; a++)
{
if(a > 0)
{
if(x_pos[a] <= x_pos[a-1] - 0.05)
{
x_pos[a] = x_pos[a-1] - 0.05;
}
if(x_pos[a] >= x_pos[a -1] + 0.05)
{
x_pos[a] = x_pos[a-1] + 0.05;
}
}
}
}
void Fix_Snake_y()
{
for(int a = 1; a < length; a++)
{
if(a > 0)
{
if(y_pos[a] <= y_pos[a-1] - 0.05)
{
y_pos[a] = y_pos[a-1] - 0.05;
}
if(y_pos[a] >= y_pos[a-1] + 0.05)
{
y_pos[a] = y_pos[a-1] + 0.05;
}
}
}
}
Edit:
New move function
for(int a = 0; a < length; a++)
{
if(a > 0)
{
if(x_speed[a] < 0 && x_pos[a] >= x_pos[a-1])
{
x_pos[a] += x_speed[a];
if(x_pos[a] == x_pos[a-1])
{
y_speed[a] = y_speed[a-1];
x_speed[a] = 0;
continue;
}
}
if(x_speed[a] > 0 && x_pos[a] <= x_pos[a-1])
{
x_pos[a] += x_speed[a];
if(x_pos[a] == x_pos[a-1])
{
y_speed[a] = y_speed[a-1];
x_speed[a] = 0;
continue;
}
}
if(y_speed[a] > 0 && y_pos[a] <= y_pos[a-1])
{
y_pos[a] += y_speed[a];
if(y_pos[a] == y_pos[a-1])
{
x_speed[a] = x_speed[a-1];
y_speed[a] = 0;
}
}
if(y_speed[a] < 0 && y_pos[a] >= y_pos[a-1])
{
y_pos[a] += y_speed[a];
if(y_pos[a] == y_pos[a-1])
{
x_speed[a] = x_speed[a-1];
y_speed[a] = 0;
}
}
}
else
{
x_pos[0] += x_speed[0];
y_pos[0] += y_speed[0];
}
}
Is causing a few problems. The snake breaks it there are too many simultaneous turns. Only the first two blocks remain in motion
If I were you, I would store a std::set with all the invalid coordinates that the snake can't go to. That would include:
the border of the "playground"
obstacles
the snake's body
Then for each move of the snake, considering the x/y speed(s) I would first try to InsertLocation into CInvalidPlaces, if that returns true then I can step there, if false then the snake's just about to hit a wall, the border or it's own body and the "game" can finish. Here's the code for that:
#include <set>
using namespace std;
typedef pair<int,int> tInvalidLocation;
struct ltSeCmp
{
bool operator()(tInvalidLocation s1, tInvalidLocation s2) const
{
if (s1.first == s2.first) return s1.second > s2.second;
return s1.first > s2.first;
}
};
typedef set<tInvalidLocation, ltSeCmp> tInvalidLocations;
class CInvalidPlaces
{
private:
tInvalidLocations mInvalid; //this set will hold all the invalid locations for the snake to go to
public:
bool InsertLocation(tInvalidLocation iLoc)
{
if (mInvalid.find(iLoc) != mInvalid.end()) return false; //check if the location is already in the set
//we survived.. it's safe to go there :)
mInvalid.insert(iLoc);
return true;
}
bool RemoveLocation(tInvalidLocation iLoc)
{
if (mInvalid.find(iLoc)== mInvalid.end()) return false;
mInvalid.insert(iLoc);
return true;
}
};
What you will have to do additionally is :
initially add the margins, all the obstacles, and all the positions of the snake just as they are from where the snake starts
modify the move routine, so that when the snake moves, it also has to remove from CInvalidPlaces it's tail using RemoveLocation
after you implement the "enlargement" of the snake you'll also have to add to CInvalidPlaces the extra segment.
If need be, you can find in the following places extra information about an stl::set :
SGI
CPP.com
HTH,JP
I highly recommend that you use a dynamic container to hold the coordinates of the snakes's body. This allows to you take the coordinate of the snakes new position and search the container for the coordinates. If the point is found, the snake has run into itself.
Similarly you can have container for points of walls and blocks and other entities that is not part of the board.
An alternative is to use a grid data structure (or matrix), and place values in it representing the snakes body and other obstacles.