Implementing a collision in 2D platform game ( Icy Tower ) - c++

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;
}
}

Related

Segmentation fault in recursive backtracking maze generator C++

I am trying to create a maze generator using recursive backtracking and have come across a problem that I just can't get my head around. For some reason my move function is returning the value "18446744073709551615". This is (of course) leading to a segmentation fault. Why is my move function returning such a large value when my move function can only increase or decrease the value by 2?
bool maze::generate(size_t x, size_t y) {
//mark the position as visited
labyrinth.s[y][x] = true;
//print to see progress
//this->print();
//if the position is not out of bounds
if (x < 0 || x > labyrinth.MAXWIDTH - 1 || y < 0 || y > labyrinth.MAXHIGHT - 1) {
//if the position is the endpoint return true
if (labyrinth.v[y][x - 1] == 'W' || labyrinth.v[y][x + 1] == 'W' || labyrinth.v[y - 1][x] == 'W' || labyrinth.v[y + 1][x] == 'W') {
return true;
}
}
//pick a random direction
do {
d = size_t(rand() % 4);
} while(!this->pos_test(x, y, d));
std::cout << x << ' ' << y << std::endl;
if (d == UP) {
y = move(x, y, UP);
}
else if (d == DOWN) {
y = move(x, y, DOWN);
}
else if (d == RIGHT) {
x = move(x, y, RIGHT);
}
else if (d == LEFT) {
x = move(x, y, LEFT);
}
else{
}
std::cout << x << ' ' << y << std::endl;
//recursively generate the maze
if (this->generate(x, y)) {
return true;
}
}
void maze::initialize(size_t x, size_t y) {
//set the maxhight and the maxwidth to y and x
labyrinth.MAXHIGHT = y;
labyrinth.MAXWIDTH = x;
//set all elements in the vector to #
for (size_t i = 0; i < labyrinth.MAXHIGHT; i++) {
std::vector<char> temp;
for (size_t j = 0; j < labyrinth.MAXWIDTH; j++) {
temp.push_back(labyrinth.wall);
}
labyrinth.v.push_back(temp);
}
for (size_t i = 0; i < labyrinth.MAXHIGHT; i++) {
for (size_t j = 0; j < labyrinth.MAXWIDTH; j++) {
if (j % 2 == 1 && i % 2 == 1 && j != labyrinth.MAXWIDTH - 1 && j != 0 && i != labyrinth.MAXHIGHT - 1 && i != 0) {
labyrinth.v[j][i] = labyrinth.path;
}
}
}
//set all posistions to unvisited
for (size_t i = 0; i < labyrinth.MAXHIGHT; i++) {
std::vector<bool> temp2;
for (size_t j = 0; j < labyrinth.MAXWIDTH; j++) {
temp2.push_back(false);
}
labyrinth.s.push_back(temp2);
}
//setup the start point
labyrinth.v[0][1] = 'S';
//setup the endpoint
labyrinth.v[labyrinth.MAXHIGHT - 2][labyrinth.MAXWIDTH - 1] = 'W';
}
//if a position has been visited or if not possible to go to return true
bool maze::pos_test(size_t x, size_t y, size_t d) const {
//if the position is out of bounds return false
if (x < 0 || y < 0 || x > labyrinth.MAXWIDTH - 1 || y > labyrinth.MAXHIGHT - 1) {
return true;
}
else if (x == 1 && d == LEFT) {
return true;
}
else if (y == 1 && d == UP) {
return true;
}
else if (x == labyrinth.MAXWIDTH - 1 && d == RIGHT) {
return true;
}
else if (y == labyrinth.MAXHIGHT - 1 && d == DOWN) {
return true;
}
else if (d == UP) {
return labyrinth.s[y - 2][x];
}
else if (d == DOWN) {
return labyrinth.s[y + 2][x];
}
else if (d == RIGHT) {
return labyrinth.s[y][x + 2];
}
else if (d == LEFT) {
return labyrinth.s[y][x - 2];
}
else {
return true;
}
}
size_t maze::move(size_t x, size_t y, size_t d) {
//if the position is out of bounds return without modifying
if (x < 0 || x > labyrinth.MAXWIDTH - 1) {
return x;
}
else if (y < 0 || y > labyrinth.MAXHIGHT - 1) {
return y;
}
else if (d == UP) {
labyrinth.v[y - 1][x] = labyrinth.path;
return y = y - 2;
}
else if (d == DOWN) {
labyrinth.v[y + 1][x] = labyrinth.path;
return y = y + 2;
}
else if (d == RIGHT) {
labyrinth.v[y][x + 1] = labyrinth.path;
return x = x + 2;
}
else if (d == LEFT) {
labyrinth.v[y][x - 1] = labyrinth.path;
return x = x - 2;
}
else {
}
}
You are underflowing your unsigned 64-bit return type size_t.
You are checking whether x and y are below zero, but that's not enough, because 0 and 1 will still be too low because you are subtracting 2!
The number you get is 0xFFFFFFFFFFFFFFFF in hexadecimal. This is the highest possible value for an unsigned 64-bit integer.
It comes from calculating 1 - 2. Yes, this is supposed to be -1, but because your move function doesn't return a signed number but an unsigned one (check the docs on size_t), it can't be negative! Instead, it wraps around to the highest possible number.
You can imagine this in the same way you would get ...99999999999 when you try to calculate 1 - 2 on paper ignoring the "you can't subtract a higher number from a smaller one on paper" rule.
As a side note: I guess the negative result is undesired anyway, because actually your huge number, once added to a pointer, will in turn overflow back into positive, so basically it will work the same is a real -1 in your case and the segmentation fault comes from accessing something right before the beginning of your buffer, not far beyond it, but it comes down to the same thing.
Apart from that, there is no need to do return y = y - 2 and such. Just return y - 2.

If ignores my == sign

I'm trying to make a game (simple 2d platformer).
The program runs as it should, but an if statement doesn't work correctly.
I have this function:
int Collision::platformCollision(SDL_Rect *hitbox, SDL_Rect plat) {
if (checkCollision(*hitbox, plat)) {
//X
//LEFT SIDE
if (hitbox->x + hitbox->w > plat.x && hitbox->x + hitbox->w < plat.x + 5) {
hitbox->x = plat.x - hitbox->w;
return 1;
}
//RIGHT SIDE
if (hitbox->x < plat.x + plat.w && hitbox->x > plat.x + plat.w - 5) {
hitbox->x = plat.x + plat.w;
return 2;
}
//Y
//UPPER SIDE
if (hitbox->y + hitbox->h > plat.y && hitbox->y + hitbox->h < plat.y + 10) {
hitbox->y = plat.y - hitbox->h;
return 3;
}
//BOTTOM SIDE
if (hitbox->y < plat.y + plat.h && hitbox->y > plat.y + plat.h - 10) {
hitbox->y = plat.y + plat.h;
return 4;
}
}
//NOT COLLIDING
return -1;
}
So I have this function return an int whenever it collides with a certain part of the platform.
Then I have this function:
void Player::playerCheckPlatCollision(SDL_Rect rect) {
if (platformCollision(p_hitboxPTR, rect) == 3) {
setGravityF(0.0);
}
if (platformCollision(p_hitboxPTR, rect) == 4) {
p_space = false;
}
return;
}
The problem should be easy to fix.
When I debug the program it gets to return 4; in the platformCollision function, but when I do
if (platformCollision(p_hitboxPTR, rect) == 4) {
p_space = false;
}
It doesn't put p_space as false, it just ignores the == 4 and when I debugged, I saw it got to that if statement.
Can someone please help.
Thanks.
If platformCollision returns 4 on the first call, it alters state, and will not return 4 on the second call.
void Player::playerCheckPlatCollision(SDL_Rect rect) {
int bang = platformCollision(p_hitboxPTR, rect);
if (bang == 3) {
setGravityF(0.0);
} else if (bang == 4) {
p_space = false;
}
}

SFML Axis independent collision

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.

Check if the Snake bangs into itself in game [closed]

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.

Overview rpg tiled space

I'm trying to make it where the character is in a tile and when they move up or down it moves to the next tile but I'm not sure how to do that. Right now, I have it set up where the character moves by pixels but I want it to move by 1 square.
The code right now is this, and it works, but it's glitchy in pixel mode. I believe if it was by blocks it might work better but I might change it anyway.
float spritewidth = sprite->stretchX;
float spriteheight = sprite->stretchY;
float bushwidth = bush->stretchX;
float bushheight = bush->stretchY;
//Basic border collision
if (sprite->x <= 0)
sprite->x = 0;
if (sprite->y <= 0)
sprite->y = 0;
if (sprite->x >= 455)
sprite->x = 455;
if (sprite->y >= 237)
sprite->y = 237;
if ( (sprite->x + spritewidth > bush->x) && (sprite->x < bush->x + bushwidth) && (sprite->y + spriteheight > bush->y) && (sprite->y < bush->y + bushheight) )
{
bushcol = 1;
}
else
{
bushcol = 0;
}
if (osl_keys->held.down)
{
if (bushcol == 1)
{
sprite->y = bush->y - spriteheight - 3;
bushcol = 0;
}
else
{
bushcol = 0;
sprite->y += 3;
}
}
if (osl_keys->held.up)
{
if (bushcol == 1)
{
sprite->y = bush->y + bushheight + 3;
bushcol = 0;
}
else
{
bushcol = 0;
sprite->y -= 3;
}
}
if (osl_keys->held.right)
{
if (bushcol == 1)
{
sprite->x = bush->x - spritewidth - 3;
bushcol = 0;
}
else
{
bushcol = 0;
sprite->x += 3;}
}
if (osl_keys->held.left)
{
if (bushcol == 1)
{
sprite->x = bush->x + bushwidth + 3;
bushcol = 0;
}
else
{
bushcol = 0;
sprite->x -= 3;
}
}
If you want the character to move one tile/square/block at a time, just move the sprite the number of pixels the tile is wide (or tall).
const int tile_width = 32; // or something
// and then
sprite->x += tile_width;