[C++]Using the pythagorean theorem for collision detection

I am recreating Pacman in my class, and I encountered a problem making the ghosts collide with Pacman using corner collisions, so I was told to make a function that calculated the distance between the ghosts and Pacman, and use a "radius" to see if they are within colliding distance. My calculation code goes as follows:

1
2
3
4
5
6
7
8
9
10
11
void Ghost::doMath(Pacman p)
{
	difference.x = p.center.x - center.x;
	difference.y = p.center.y - center.y;
	if(difference.x<0)
		difference.x * -1;
	if(difference.y<0)
		difference.y * -1;
	float cSquared = (difference.x*difference.x) + (difference.y*difference.y);
	float distance = sqrt(cSquared);
}


When I run it, the ghosts just move through Pacman, and when I debug it and hover over p.center.x, it doesn't show the value, nor does it show the value for difference.x, difference.y, cSquared, or distance.
What does you collision code look like? The problem doesn't seem to be in doMath()
Good to know I did that part right, I suppose. Here is the collision code, pretty simple, so the problem is probably here.
1
2
3
4
5
6
7
8
9
10
11
12
if(distance<=7)
	{
		if(p.powered)
		{
			setPosition(337,275);
			s.points += 200;
			return false;
		}
		setPosition(337,275);
		return true;
	}
	return false;

If this returns true, I lose a life and get reset. If it returns false, nothing happens. If Pacman is powered up, it resets the ghost's position to the start and gives me points.
Last edited on
if(p.powered)

Is powered a method or just a variable?
It's just a bool variable. This worked when I was checking just the corners (except a certain area at the top, which is why I am changing the collision detection)
closed account (D80DSL3A)
Also, where is that code from? Your doMath() returns void, not bool.
You store the distance in a local variable inside doMath so when the function ends the calculations will be lost. You will have to return or store the distance in a variable that you can use after the function has return. If Ghost has a distance member variable that you want to get this value it is as simple as just removing the float from line 10.

If you are not going to use the value of difference in any other parts of your code you could make difference a local variable and remove the if statements on lines 5-8 because the sign will disappear when you calculate the square anyway (multiply two negative numbers and you get a positive number).
Last edited on
1
2
3
4
5
6
7
8
9
10
11
void Ghost::doMath(Pacman p)
{
	difference.x = p.center.x - center.x;
	difference.y = p.center.y - center.y;
	if(difference.x<0)
		difference.x * -1;
	if(difference.y<0)
		difference.y * -1;
	float cSquared = (difference.x*difference.x) + (difference.y*difference.y);
	float distance = sqrt(cSquared);
}
I would think not, but Is this a literal copy of the code? If so, the function doesn't really do anything with cSquared or distance.

Also, this bit:
1
2
3
4
	if(difference.x<0)
		difference.x * -1;
	if(difference.y<0)
		difference.y * -1;
is not necessary. For any real value of x, x^2 >= 0.
So I could make it a float function and return line 10?
Either that or make distance a variable in the Ghost class.
Okay, I've made the following changes:

Distance is initially declared to be 10, so as to stop Pacman from colliding when the game starts due to junk data.

doMath is now isColliding, and this is the code:
1
2
3
4
5
6
7
8
9
bool Ghost::isColliding(Pacman p)
{
	difference.x = p.center.x - center.x;
	difference.y = p.center.y - center.y;
	float cSquared = (difference.x*difference.x) + (difference.y*difference.y);
	float distance = sqrt(cSquared);
	if(distance<7)
		return true;
}


this is the collision check:
1
2
3
4
5
6
7
8
9
10
11
12
if(isColliding(p))
	{
		if(p.powered)
		{
			setPosition(337,275);
			s.points += 200;
			return false;
		}
		setPosition(337,275);
		return true;
	}
	return false;


Now, obviously 10 is not less than 7... When I start the game, I immediately collide 3 times and get a game over. Any idea why that is?
You have to return false from the isColliding if distance >= 7.
Simply return distance<7;
So, now I am returning true if the distance is less than 7, and false if it is not, and the code is causing some problems.
The space I've circled in red is the only place I seem to be able to collide with the ghosts. And sometimes it's when I'm half way down the hall. Also, it's ONLY when I'm below them.
Apparently I can't post links. Anyways, it is only in one hallway, and it is only when I am below them.
Last edited on
After a bit more testing, I appear to get hit when I am on the same y or x axis as the ghosts, but the times when it happens are completely random.

Could someone tell me a better way to check for collisions, or spot any errors in my code?
This method of collision checking is called "bounding sphere" and it's perfectly acceptable. It's usually used as a first pass over a list of objects before a more precise method to cull object pairs that couldn't possibly be intersecting, but it can be used on its own if only approximate detection is enough for the application.

The function appears correct, as well. If you're getting weird behavior it's likely because you're not using the function properly. Either you're not properly filling the variables that the function uses (there's probably some uninitialized variables), or you're not correctly using the return value from the function.
I'll post a few chunks of my ghost code. I've only been programming for a few months, but I don't really see anything wrong here.
From the header:
1
2
3
4
5
6
7
public:
	bool isColliding(Pacman p);
private:
	Point2D center;
	Point2D difference;
	float cSquared;
	float distance;


From the cpp:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
Ghost::Ghost()
{
	distance = 20;
}

bool Ghost::isColliding(Pacman p)
{
	difference.x = p.center.x - center.x;
	difference.y = p.center.y - center.y;
	float cSquared = (difference.x*difference.x) + (difference.y*difference.y);
	float distance = sqrt(cSquared);
	if(distance<1)
		return true;
	else if(distance>=1)
		return false;
}

bool Ghost::collision(Pacman p, Score &s)
{
	if(isColliding(p))
	{
		if(p.powered)
		{
			setPosition(337,275);
			s.points += 200;
			return false;
		}
		setPosition(337,275);
		return true;
	}
	return false;
}

void Ghost::updateCorners()
{
	TopLeft.x = pos.x;
	TopLeft.y = pos.y;
	TopRight.x = pos.x + width;
	TopRight.y = pos.y;
	BottomLeft.x = pos.x;
	BottomLeft.y = pos.y + height;
	BottomRight.x = pos.x + width;
	BottomRight.y = pos.y + height;
	center.x = TopLeft.x + width/2;
	center.y = TopLeft.x + width/2;
}
Oh my god, I just realized I set center.y to TopLeft.x... Everything is fixed now. Marking as solved. Thanks for your help everyone.
Topic archived. No new replies allowed.