Sign in to follow this  

Problem with collision detection in JavaScript Pong

This topic is 2942 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Yesterday I decided to test my javascript skills by creating a simple pong game. So far everything works fine except for the collision detection, which is having some major problems. It seems to be detecting nonexistent collisions often, sometimes even when the ball is in the middle of the field and not even touching the paddles. Can anyone help me find what the problem is?
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xml:lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
	<title>JavaScript Pong</title>
	<style type="text/css">
	*
	{
		margin: 0; 
		padding: 0; 
		outline: none;
	}
	
	body
	{
		color: #ffffff;
		background: #000000;
		font: 15px "Trebuchet MS", Verdana; 
		text-align: center;
	}
	
	div
	{
		margin: auto;
	}
	
	#field
	{
		width: 1000px; 
		height: 700px; 
		margin-top: 50px; 
		position: relative;
		border: 3px outset #a0a0a0; 
	}
	
	#ball
	{
		width: 25px; 
		height: 25px;
		top: 48%;
		left: 48%;
		position: absolute;
		background: #00ff00;
		-moz-border-radius: 90px; 
	}
	
	#paddle-1, #paddle-2
	{
		width: 15px; 
		height: 120px;
		top: 45%; 
		position: absolute; 
		background: #22bd22;
	}
	
	#paddle-1
	{
		left: 1%;
	}
	
	#paddle-2
	{
		right: 1%;
	}
	
	</style>
</head>
<body onkeydown="controller.register_key(event.keyCode)" onkeyup="controller.unregister_key(event.keyCode)">
	<div id="field">
		<div id="paddle-1"></div>
		<div id="paddle-2"></div>
		<div id="ball"></div>
	</div>
	<h3 style="font-size: 120%; color: green; margin-top: 20px; margin-right: 20px" id="c">No collision</h3>
	
	<script type="text/javascript">
	
	function $(id)
	{
		return document.getElementById(id.replace("#", ""));
	}
	
	function random()
	{
		return Math.floor(Math.random() * 8) - Math.floor(Math.random() * 8);
	}
	
	function collides(object_a, object_b)
	{
		var topA, topB; 
		var leftA, leftB; 
		var rightA, rightB; 
		var bottomA, bottomB; 
		
		topA = object_a.y;
		leftA = object_a.x; 
		rightA = object_a.x + object_a.w; 
		bottomA = object_a.y + object_a.h; 
		
		topB = object_b.y; 
		leftB = object_b.x; 
		rightB = object_b.x + object_b.w; 
		bottomB = object_b.y + object_b.h; 
		
		if (topA >= bottomB || bottomA <= topB || leftA <= rightB || rightA >= leftB)
		{
			$("#c").innerHTML = "Collision"; 
			return true; 
		}
		
		$("#c").innerHTML = "No collision"; 
		return false; 
	}
	
	var model = 
	{
		paddles  : { w : 15, h : 120, v : 10 }, 
		paddle_1 : { y : 450, yv : 0 }, 
		paddle_2 : { y : 450, yv : 0 }, 
		field: { w : 1000, h : 700 }, 
		ball : { x : 480, y : 480, w : 25, h : 25, xv: -5, yv: 5 }, 
		
		keytable : [], 
		
		reset : function()
		{
			this.ball.x = this.ball.y = 480; 
			this.ball.xv = -5; 
			this.ball.yv = 5; 
		}, 
		
		update : function()
		{
			// Reset paddle velocities every time
			this.paddle_1.yv = 0; 
			this.paddle_2.yv = 0; 
			
			// Set paddle velocities based on user input
			if (this.keytable[38] == true)
			{
				this.paddle_1.yv = -this.paddles.v;
			}
			if (this.keytable[40] == true)
			{
				this.paddle_1.yv = this.paddles.v;
			}
			
			// Set the computer paddle velocity
			if (this.ball.xv > 0)
			{
				this.paddle_2.yv = (this.ball.y > this.paddle_2.y) ? -this.paddles.v : this.paddles.v; 
			}
			
			// Update locations based on velocities
			this.paddle_1.y += this.paddle_1.yv; 
			this.paddle_2.y += this.paddle_2.yv; 
			this.ball.x += this.ball.xv; 
			this.ball.y += this.ball.yv; 
			
			// Check paddle locations
			if (this.paddle_1.y < 0)
			{
				this.paddle_1.y = 0;
			}
			else if (this.paddle_1.y + this.paddles.h > this.field.h)
			{
				this.paddle_1.y = this.field.h - this.paddles.h; 
			}
			if (this.paddle_2.y < 0)
			{
				this.paddle_2.y = 0;
			}
			else if (this.paddle_2.y + this.paddles.h > this.field.h)
			{
				this.paddle_2.y = this.field.h - this.paddles.h; 
			}
			
			// Check ball locations
			if (this.ball.x < 0)
			{
				this.ball.x = 0;
				this.ball.xv = -this.ball.xv + random();
				
				//alert("The computer has won this round.");
				this.reset();
			}
			else if (this.ball.x + this.ball.w> this.field.w)
			{
				this.ball.x = this.field.w - this.ball.w; 
				this.ball.xv = -this.ball.xv + random();
				
				//alert("You have won this round.");
				this.reset();
			}
			if (this.ball.y < 0)
			{
				this.ball.y = 0; 
				this.ball.yv = -this.ball.yv + random();
			}
			else if (this.ball.y + this.ball.h> this.field.h)
			{
				this.ball.y = this.field.h - this.ball.h; 
				this.ball.yv = -this.ball.yv + random();
			}
			
			// Check to see if ball hit a paddle
			if (collides(this.ball, this.paddle_1) || collides(this.ball, this.paddle_2))
			{
				this.ball.xv = -this.ball.xv;
				this.ball.yv = (random() < 5) ? this.ball.yv + random() : -this.ball.yv + random();
			}
		}
	}; 
	
	var view = 
	{
		update : function()
		{
			$("#ball").style.top = model.ball.y.toString() + "px"; 
			$("#ball").style.left = model.ball.x.toString() + "px"; 
			$("#paddle-1").style.top = model.paddle_1.y.toString() + "px"; 
		}
	}; 
	
	var controller = 
	{
		register_key : function(key)
		{
			model.keytable[key] = true;
		}, 
		
		unregister_key : function(key)
		{
			model.keytable[key] = false;
		}, 
		
		loop : function()
		{
			model.update();
			view.update();
		}, 
		
		start : function()
		{
			setInterval("controller.loop()", 20);
		}
	}; 
	
	controller.start(); 
	
	</script>
</body>
</html>

Thanks.

Share this post


Link to post
Share on other sites
Try this for your collision condition:
rightA > leftB && leftA < rightB && bottomA > topB && topA < bottomB

You want to test for overlap on both axes. Also, use non-inclusive comparisons (> < instead of >= <=) because your right/bottom co-ordinates are non-inclusive as well.

Share this post


Link to post
Share on other sites
Hi, I copied your code and I haven't gotten it working yet, but I found the following.

1. It looks like in your collision function you may have the top and bottoms reversed. I changed the code to:
bottomA = object_a.y;
leftA = object_a.x;
rightA = object_a.x + object_a.w;
topA = object_a.y + object_a.h;

bottomB = object_b.y;
leftB = object_b.x;
rightB = object_b.x + object_b.w;
topB = object_b.y + object_b.h;
logically it's easier for me to thing about it this way, like a cartesian plane mirrored. on the y axis.

2. I think a better algorithm for collision detection would be:

y = ((topA <= topB) && (topA >= bottomB)) || (
(topB <= topA) && (topB >=bottomA));

x = ((rightA >= leftA) && (rightA <=leftB)) ||
((rightB >= leftA) && (rightB <= rightA));
//alert("test");
if (x && y)
{
$("#c").innerHTML = "Collision";
return true;
}
I looked it up, then had to draw pictures to justify it to myself, but I think it will work.

3. The paddle objects don't seem to have h defined. So in the collision function when the bottom is calculated, it is adding undefined, because the h is defined on paddles. That would make sense if they were inheriting, but I am going to try moving h onto the paddle objects to see if that works.

*crosses fingers*

Share this post


Link to post
Share on other sites

This topic is 2942 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this