Sign in to follow this  
Ntvu

Problem with collision detection in JavaScript Pong

Recommended Posts

Ntvu    100
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
mattd    1078
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
KeeperOfRyleh    100
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
KeeperOfRyleh    100
Okay I got it to work, there was one additional thing I ran into. x wasn't defined on the paddle objects, and it needed to be for the collision function,so I get paddle one a value of 5 and that worked okay.

Cheers

Share this post


Link to post
Share on other sites

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