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

Dec 14, 2012 at 7:26pm
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.
Dec 14, 2012 at 7:47pm
What does you collision code look like? The problem doesn't seem to be in doMath()
Dec 14, 2012 at 7:55pm
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 Dec 14, 2012 at 7:56pm
Dec 14, 2012 at 8:01pm
if(p.powered)

Is powered a method or just a variable?
Dec 14, 2012 at 8:05pm
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)
Dec 14, 2012 at 8:05pm
closed account (D80DSL3A)
Also, where is that code from? Your doMath() returns void, not bool.
Dec 14, 2012 at 8:06pm
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 Dec 14, 2012 at 8:08pm
Dec 14, 2012 at 8:08pm
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.
Dec 14, 2012 at 8:11pm
So I could make it a float function and return line 10?
Dec 14, 2012 at 8:15pm
Either that or make distance a variable in the Ghost class.
Dec 14, 2012 at 8:20pm
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?
Dec 14, 2012 at 8:28pm
You have to return false from the isColliding if distance >= 7.
Dec 14, 2012 at 8:33pm
Simply return distance<7;
Dec 14, 2012 at 8:41pm
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 Dec 14, 2012 at 8:44pm
Dec 14, 2012 at 10:39pm
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?
Dec 15, 2012 at 12:08am
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.
Dec 15, 2012 at 12:15am
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;
}
Dec 15, 2012 at 1:38am
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.