www.webdeveloper.com
Results 1 to 3 of 3

Thread: Trouble Understanding a bug in my collision detection system...

  1. #1
    Join Date
    Jun 2014
    Location
    in a while loop
    Posts
    6

    Trouble Understanding a bug in my collision detection system...

    I'm working on a basic collision system for my HTML5 game. Unfortunately I'm running into a problem in the algorithm. This is what the collision system does:

    - Detects if collision boxes are intersecting. If not, false. If true, a
    "collision solver" function is fired. This is where my problem starts:

    The Collision Solver Tasks:

    1. - Get the normalized sides
    2. - Calculate the absolute change in X and Y
    3. - But when it's time to place the player on either the right, left, top, or bottom sides of the collidee box, my character appears on one of the corners.


    If I let the player hit either the left or right edge, the system works perfectly. The problem occurs when the player hits either the top or bottom edges.

    What I think is happening

    If I remove the if statements that check left and right edges, the top and bottom collision detetion works perfectly. Which leads me to believe that the issue is related to the order of execution in the algorithm. (If, else, if, else). In fact, if you look at the function code I'm providing, you'll notice left and right come first. What puzzles me is that even if I put the top and bottom if statements first, the same problem occurs.

    Hopefully this all makes sense to somebody. Thanks in advance. Any questions, I'll check back on the thread.

    Code:
    collisionsolver: function (collidee)
    		{
    // Calculate Absolute change in X and Y
    this.normalizedX = (collidee.colliderMidX - this.colliderMidX) / (collidee.width /2);
    this.normalizedY = (collidee.colliderMidY - this.colliderMidY) / (collidee.height /2);
    
    this.absNX = Math.abs(this.normalizedX) / (collidee.width/2);
    this.absNY = Math.abs(this.normalizedY) / (collidee.height/2);
    var test = (this.absNX - this.absNY);
    
    if(Math.abs(test) < .1)
    {
            // Hit Right Side?
            if(this.normalizedX < 0)
    	{
    	        this.x = collidee.colliderRight;
    		console.log('right!');
    	}
    	// Left Side
    	else
    	{
    		this.x = collidee.colliderLeft - this.width;
    		console.log('left!');
    	}
    	if(this.normalizedY < 0)
    	{
    		this.y = collidee.colliderBottom;
    		console.log('bottom!');
    	}
    	else
    	{
    		console.log('top');
    		this.y = collidee.colliderTop - this.height;
    	}
    }
    },

  2. #2
    Join Date
    May 2014
    Posts
    1,049
    Your math for this just seems weird... also not sure why you're saving "normalize"... I'm not even sure how that would work out to actually provide box collisions.

    From what I'm seeing for variables:

    Code:
    var
    	xRange = (collidee.width + this.width) / 2,
    	yRange = (collidee.height + this.height) / 2,
    	xDistance = (collidee.colliderMixX - this.colliderMidX),
    	yDistance = (collidee.colliderMixY - this.colliderMidY);
    
    if (abs(xDistance) < xRange) {
    	if (xDistance < 0) {
    		this.x = collidee.colliderLeft - this.width;
    		console.log('left!');
    	} else {
    		this.x = collidee.colliderRight;
    		console.log('right!');
    	}
    }
    
    if (abs(yDistance) < yRange) {
    	if (yDistance < 0) {
    		this.y = collidee.colliderTop - this.height;
    		console.log('top!');
    	} else {
    		this.y = collidee.colliderBottom;
    		console.log('bottom!');
    	}
    }
    Should do what you are trying for. Of course, this misses that you should only REALLY have a collision if BOTH conditions are true.

    Code:
    var
    	xRange = (collidee.width + this.width) / 2,
    	yRange = (collidee.height + this.height) / 2,
    	xDistance = (collidee.colliderMixX - this.colliderMidX),
    	yDistance = (collidee.colliderMixY - this.colliderMidY),
    	xCollide = abs(xDistance) < xRange,
    	yCollide = abs(yDistance) < yRange;
    	
    if (xCollide && yCollide) {
    	if (xCollide) {
    		if (xDistance < 0) {
    			this.x = collidee.colliderLeft - this.width;
    			console.log('left!');
    		} else {
    			this.x = collidee.colliderRight;
    			console.log('right!');
    		}
    	}
    	if (yCollide) {
    		if (yDistance < 0) {
    			this.y = collidee.colliderTop - this.height;
    			console.log('top!');
    		} else {
    			this.y = collidee.colliderBottom;
    			console.log('bottom!');
    		}
    	}
    }
    Though really this whole mid-point nonsense is just making things harder than need be. Box collisons are simple, don't make them hard. Assuming you have .x, .y, .width and .height on all elements involved...

    Code:
    var
    	// you can skip these four vars if you already have these calculated
    	thisEx = this.x + collidee.width,
    	thisEy = this.y + collidee.height,
    	colEx = collidee.x + collidee.width,
    	colEy = collidee.y + collidee.height,
    	xCollide = (
    		(this.x >= collidee.x) && (this.x <= colEx)
    	) ? -1 : (
    		(thisEx <= colEx) &&(thisEx >= collidee.x) ? 1 : 0
    	);
    	yCollide = (
    		(this.y >= collidee.y) && (this.y <= colEy)
    	) ? -1 : (
    		(thisEy <= colEy) &&(thisEy >= collidee.y) ? 1 : 0
    	);
    	
    if (xCollide && yCollide) {
    
    	if (xCollide < 0) {
    		this.x = collidee.colliderLeft - this.width;
    		console.log('left!');
    	} else if (xCollide > 0) {
    		this.x = collidee.colliderRight;
    		console.log('right!');
    	}
    	
    	if (yCollide < 0) {
    			this.y = collidee.colliderTop - this.height;
    			console.log('top!');
    	} else if (yCollide > 0) {
    		this.y = collidee.colliderBottom;
    		console.log('bottom!');
    	}
    	
    }
    But that's likely the low level 8088 coder in me trying to avoid divide, multiply, and any other math. Of course if this were ASM, or a compiled language like Pascal or C, I'd be using !=0 instead of >0 on the second 'if' since at the low level it's easier to check for z instead of ns.

    -- edit -- wait, are you trying to calculate internal or external collision here? If internal, that's called a 'bounding' check, not 'collision' (even if it IS a collision)
    Last edited by deathshadow; 07-22-2014 at 08:32 PM.
    Java is to JavaScript as Ham is to Hamburger.

  3. #3
    Join Date
    Jul 2014
    Posts
    6
    Quote Originally Posted by deathshadow View Post
    Your math for this just seems weird... also not sure why you're saving "normalize"... I'm not even sure how that would work out to actually provide box collisions.

    From what I'm seeing for variables:

    Code:
    var
    	xRange = (collidee.width + this.width) / 2,
    	yRange = (collidee.height + this.height) / 2,
    	xDistance = (collidee.colliderMixX - this.colliderMidX),
    	yDistance = (collidee.colliderMixY - this.colliderMidY);
    
    if (abs(xDistance) < xRange) {
    	if (xDistance < 0) {
    		this.x = collidee.colliderLeft - this.width;
    		console.log('left!');
    	} else {
    		this.x = collidee.colliderRight;
    		console.log('right!');
    	}
    }
    
    if (abs(yDistance) < yRange) {
    	if (yDistance < 0) {
    		this.y = collidee.colliderTop - this.height;
    		console.log('top!');
    	} else {
    		this.y = collidee.colliderBottom;
    		console.log('bottom!');
    	}
    }
    Should do what you are trying for. Of course, this misses that you should only REALLY have a collision if BOTH conditions are true.

    Code:
    var
    	xRange = (collidee.width + this.width) / 2,
    	yRange = (collidee.height + this.height) / 2,
    	xDistance = (collidee.colliderMixX - this.colliderMidX),
    	yDistance = (collidee.colliderMixY - this.colliderMidY),
    	xCollide = abs(xDistance) < xRange,
    	yCollide = abs(yDistance) < yRange;
    	
    if (xCollide && yCollide) {
    	if (xCollide) {
    		if (xDistance < 0) {
    			this.x = collidee.colliderLeft - this.width;
    			console.log('left!');
    		} else {
    			this.x = collidee.colliderRight;
    			console.log('right!');
    		}
    	}
    	if (yCollide) {
    		if (yDistance < 0) {
    			this.y = collidee.colliderTop - this.height;
    			console.log('top!');
    		} else {
    			this.y = collidee.colliderBottom;
    			console.log('bottom!');
    		}
    	}
    }
    Though really this whole mid-point nonsense is just making things harder than need be. Box collisons are simple, don't make them hard. Assuming you have .x, .y, .width and .height on all elements involved...

    Code:
    var
    	// you can skip these four vars if you already have these calculated
    	thisEx = this.x + collidee.width,
    	thisEy = this.y + collidee.height,
    	colEx = collidee.x + collidee.width,
    	colEy = collidee.y + collidee.height,
    	xCollide = (
    		(this.x >= collidee.x) && (this.x <= colEx)
    	) ? -1 : (
    		(thisEx <= colEx) &&(thisEx >= collidee.x) ? 1 : 0
    	);
    	yCollide = (
    		(this.y >= collidee.y) && (this.y <= colEy)
    	) ? -1 : (
    		(thisEy <= colEy) &&(thisEy >= collidee.y) ? 1 : 0
    	);
    	
    if (xCollide && yCollide) {
    
    	if (xCollide < 0) {
    		this.x = collidee.colliderLeft - this.width;
    		console.log('left!');
    	} else if (xCollide > 0) {
    		this.x = collidee.colliderRight;
    		console.log('right!');
    	}
    	
    	if (yCollide < 0) {
    			this.y = collidee.colliderTop - this.height;
    			console.log('top!');
    	} else if (yCollide > 0) {
    		this.y = collidee.colliderBottom;
    		console.log('bottom!');
    	}
    	
    }
    But that's likely the low level 8088 coder in me trying to avoid divide, multiply, and any other math. Of course if this were ASM, or a compiled language like Pascal or C, I'd be using !=0 instead of >0 on the second 'if' since at the low level it's easier to check for z instead of ns.

    -- edit -- wait, are you trying to calculate internal or external collision here? If internal, that's called a 'bounding' check, not 'collision' (even if it IS a collision)
    Thanks, I will try it.

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
HTML5 Development Center



Recent Articles