Collision being detected without collision

Started by
2 comments, last by wicked357 13 years, 11 months ago
Okay, I have 4 different functions to detect whether or not collision has happend on the top, bottom, left, and right sides of the rectangles. I am using a tile map and I have a index that I want no movement on (Collision), I have it working for the top and left tiles (1 - Dirt), but it is always colliding with the right and down and not letting me move around, what is the problem here I have been messing with this for hours now and to no avail? Here is my complete code, it isn't that long dont worry

#include <SFML/Graphics.hpp>
#include <vector>

using namespace std;

typedef struct
{
	float x, y;
	sf::Sprite sprite;
	bool allowUp, allowDown, allowLeft, allowRight;
}Player;

Player player;

typedef struct  
{
	float left, right, top, bottom;
}pRect;

bool checkCollisionTop(sf::Sprite, sf::Sprite);
bool checkCollisionBottom(sf::Sprite, sf::Sprite);
bool checkCollisionLeft(sf::Sprite, sf::Sprite);
bool checkCollisionRight(sf::Sprite, sf::Sprite);

int main(int argv, char** argc)
{
	sf::RenderWindow dev(sf::VideoMode(800, 600, 32), "SFML Tile Engine Example Version 1.0");

	sf::Event Event;

	vector<sf::Sprite> tileSprites;

	const int tileMapWidth = 5;
	const int tileMapHeight = 5;

	int tileMap[tileMapWidth][tileMapHeight] =
	{
		1, 1, 1, 1, 1,
		1, 0, 0, 0, 1,
		1, 0, 0, 0, 1,
		1, 0, 0, 0, 1,
		1, 1, 1, 1, 1
	};

	int tileWidth = 64;
	int tileHeight = 64;

	sf::Image imageBuffer;
	sf::Image imageBuffer2;
	sf::Image imagePlayer;
	sf::Image imageObject;
	sf::Sprite sprite;

	if(!imageBuffer.LoadFromFile("grass.jpg"))
		return 1;
	sprite.SetImage(imageBuffer);
	tileSprites.push_back(sprite);

	if(!imageBuffer2.LoadFromFile("dirt.jpg"))
		return 1;
	sprite.SetImage(imageBuffer2);
	tileSprites.push_back(sprite);

	if(!imagePlayer.LoadFromFile("player.png"))
		return 1;
	player.sprite.SetImage(imagePlayer);
	player.x = 128;
	player.y = 128;
	player.allowUp = true;
	player.allowDown = true;
	player.allowLeft = true;
	player.allowRight = true;

	float movement = 1;

	while(dev.IsOpened())
	{
		while(dev.GetEvent(Event))
		{
			if(Event.Type == sf::Event::Closed)
				dev.Close();
		}

		if(dev.GetInput().IsKeyDown(sf::Key::Escape))
			dev.Close();

		if(player.allowUp)
		{
			if(dev.GetInput().IsKeyDown(sf::Key::W))
			{
				player.y -= movement;
			}
		}
		if(player.allowDown)
		{
			if(dev.GetInput().IsKeyDown(sf::Key::S))
			{
				player.y += movement;
			}
		}
		if(player.allowLeft)
		{
			if(dev.GetInput().IsKeyDown(sf::Key::A))
			{
				player.x -= movement;
			}
		}
		if(player.allowRight)
		{
			if(dev.GetInput().IsKeyDown(sf::Key::D))
			{
				player.x += movement;
			}
		}

		player.sprite.SetPosition(sf::Vector2f(player.x, player.y));

		dev.Clear();

		//Draw the tile map
		for(int x = 0; x < tileMapWidth; x++)
		{
			for(int y = 0; y < tileMapHeight; y++)
			{
				int textureIndex = tileMap[y][x];
				sf::Sprite texture = tileSprites.at(textureIndex);
				texture.SetPosition(sf::Vector2f(x * tileWidth, y * tileWidth));
				texture.SetScale(sf::Vector2f(.25f, .25f));
				dev.Draw(texture);
				if(textureIndex == 1)
				{
					if(checkCollisionTop(player.sprite, tileSprites[textureIndex]))
					{
						player.allowUp = false;
					}
					else
					{
						player.allowUp = true;
					}
					if(checkCollisionBottom(player.sprite, tileSprites[textureIndex]))
					{
						player.allowDown = false;
					}
					else
					{
						player.allowDown = true;
					}
					if(checkCollisionLeft(player.sprite, tileSprites[textureIndex]))
					{
						player.allowLeft = false;
					}
					else
					{
						player.allowLeft = true;
					}
					if(checkCollisionRight(player.sprite, tileSprites[textureIndex]))
					{
						player.allowRight = false;
					}
					else
					{
						player.allowRight = true;
					}
				}
			}
		}

		dev.Draw(player.sprite);

		dev.Display();
	}

	return EXIT_SUCCESS;
}

bool checkCollisionTop(sf::Sprite sprite1, sf::Sprite sprite2)
{
	pRect rect1;
	rect1.top		= sprite1.GetPosition().y;
	rect1.bottom	= sprite1.GetPosition().y + 64;
	rect1.left		= sprite1.GetPosition().x;
	rect1.right		= sprite1.GetPosition().x + 64;

	pRect rect2;
	rect2.top		= sprite2.GetPosition().y;
	rect2.bottom	= sprite2.GetPosition().y + 64;
	rect2.left		= sprite2.GetPosition().x;
	rect2.right		= sprite2.GetPosition().x + 64;

	if(rect1.top <= rect2.bottom)
	{
		return true;
	}

	return false;
}

bool checkCollisionBottom(sf::Sprite sprite1, sf::Sprite sprite2)
{
	pRect rect1;
	rect1.top		= sprite1.GetPosition().y;
	rect1.bottom	= sprite1.GetPosition().y + 64;
	rect1.left		= sprite1.GetPosition().x;
	rect1.right		= sprite1.GetPosition().x + 64;

	pRect rect2;
	rect2.top		= sprite2.GetPosition().y;
	rect2.bottom	= sprite2.GetPosition().y + 64;
	rect2.left		= sprite2.GetPosition().x;
	rect2.right		= sprite2.GetPosition().x + 64;

	if(rect1.bottom >= rect2.top)
	{
		return true;
	}

	return false;
}

bool checkCollisionLeft(sf::Sprite sprite1, sf::Sprite sprite2)
{
	pRect rect1;
	rect1.top		= sprite1.GetPosition().y;
	rect1.bottom	= sprite1.GetPosition().y + 64;
	rect1.left		= sprite1.GetPosition().x;
	rect1.right		= sprite1.GetPosition().x + 64;

	pRect rect2;
	rect2.top		= sprite2.GetPosition().y;
	rect2.bottom	= sprite2.GetPosition().y + 64;
	rect2.left		= sprite2.GetPosition().x;
	rect2.right		= sprite2.GetPosition().x + 64;

	if(rect1.left <= rect2.right)
	{
		return true;
	}

	return false;
}

bool checkCollisionRight(sf::Sprite sprite1, sf::Sprite sprite2)
{
	pRect rect1;
	rect1.top		= sprite1.GetPosition().y;
	rect1.bottom	= sprite1.GetPosition().y + 64;
	rect1.left		= sprite1.GetPosition().x;
	rect1.right		= sprite1.GetPosition().x + 64;

	pRect rect2;
	rect2.top		= sprite2.GetPosition().y;
	rect2.bottom	= sprite2.GetPosition().y + 64;
	rect2.left		= sprite2.GetPosition().x;
	rect2.right		= sprite2.GetPosition().x + 64;

	if(rect1.right >= rect2.left)
	{
		return true;
	}

	return false;
}

Advertisement
Okay I had a der moment, but I understand why it isn't letting me go right or down, but how can I solve this problem? I cannot be exact on the collision testing by using == instead of <= or >= if I did that my movement speed would cause major bugs in testing for collison. I some how need to know that actual contact was made and not by testing position points... hmmm, anyone have any suggestions?

[Edited by - wicked357 on May 4, 2010 10:26:42 PM]
You could simplify your code by only having one function that checks for collision between your two rects:

// This is what I use in my codeBool isIntersecting(const CRect &rectOne, const CRect &rectTwo){	// Check weather these Rectangles are crossing	if ((rectOne.topLeft.x > rectTwo.topLeft.x) || (rectOne.bottomRight.x > rectTwo.bottomRight.x)) return false;	if ((rectOne.topLeft.y > rectTwo.topLeft.y) || (rectOne.bottomRight.y > rectTwo.bottomRight.y)) return false;	return true;}


What you can do is when you move your character, you can stop movement all together, or in that one direction.

// Pseudo codeif (!isIntersecting(myPlayerSprite.getRect(), myWallSprite.getRect())){  // do movement}
------------Anything prior to 9am should be illegal.
I agree with only one functions it just seems to be to linear for this kind of detection. The movement isn't just one kind of movement it is all sides need to be tested and movement needs to be limited based on that, so I need to know the the left side collide with the right side, but only give me a case for sprite1.

For example, if left side of s1 collides with right side of s2, then I wouldn't be able to move left anymore until that collision isn't happening, the problem with how it is going is because s2 right is touching s1's left then it will disallow right movement as well so I can never get off once contact is made. That is why I have different functions and not just one, but this isn't just tilemap collision it is any object I am colliding with from all sides, your way only tells me I collided but I can figure the collision it is what happens after that I have a problem with. Any ideas on this for post-collision?

This topic is closed to new replies.

Advertisement