Collision Detection almost working.

Subscribe to Collision Detection almost working. 12 posts

avatar for alecz127 alecz127 817 posts
Flag Post

E: using debugging I’ve found out the collisionMarker is always 0. The rabbit doesn’t sink if timeVector is incrementing, but does when it starts decrementing.

What I believe I’m doing wrong is instead of splicing, I should be doing something else. But I have no clue what, this is infuriating. I’ve been working on it a few days and trying different things.

The rabbit does what its supposed to, except when moving across tiles left or right too quickly it starts to sink into the ground and ultimately falls through completely.

The first two blocks of code are for reference.

//this is a function fired by my main loop;
private function updateCollisions(){
	var i:int = 0;
	while(i < ground_a.length){
		solveCollision(i);
		trace(i);
		i++;
	}//end of for loop
	findTOC();
}

//solveCollision();
public function solveCollision(i) {
	squareX2 = ground_a[i].x;
	squareY2 = ground_a[i].y;
	squareWidth2 = ground_a[i].width;
	squareHeight2 = ground_a[i].height;
	var velocityY = squareY - prevSq1Y;
	var velocityX = squareX - prevSq1X;
	var distanceX1;
	var distanceY1;
	var distanceX2;
	var distanceY2;
		if(velocityX < 0){
			distanceX1 = squareX2 + squareWidth2 - prevSq1X;
			distanceX2 = squareX2 - prevSq1X - squareWidth;
			var movingLeft = true;
			trace("Moving Left!");
		} else {
			distanceX1 = squareX2 - prevSq1X - squareWidth;
			distanceX2 = squareX2 + squareWidth2 - prevSq1X;
			var movingRight = true;
		}
		if(velocityY < 0){
			distanceY1 = squareY2 + squareHeight2 - prevSq1Y;
			distanceY2 = squareY2 - prevSq1Y - squareHeight;
			var movingUp = true;
			trace("Moving UP!");
		} else {
			distanceY1 = squareY2 - prevSq1Y - squareHeight;
			distanceY2 = squareY2 + squareHeight2 - prevSq1Y;
			var movingDown = true;
		}
	var timeX = distanceX1/velocityX;
	var timeY = distanceY1/velocityY;
	var actualTime = Math.max(timeX,timeY);
	var disjointTimeX = distanceX2/velocityX;
	var disjointTimeY = distanceY2/velocityY;
	var actualDisjointTime = Math.min(disjointTimeX, disjointTimeY);
	if (timeX < 0 && timeY < 0){
		//trace("COLLISION FOUND UNWORTHY");
		return;
	}
	if(timeX > 1 || timeY > 1){
		//trace("COLLISION FOUND UNWORTHY");
		return;
	}
	if(timeX == timeY){
		trace("timeX has the same value as timeY");
	}
	if(actualTime < actualDisjointTime){
		//trace("COLLISION FOUND WORTHY~~~~>>>>>");
		var tOC = getTimer();
		timeVector.push(tOC);
		timeXV.push(timeX);
		timeYV.push(timeY);
		actualTimeV.push(actualTime);
		velocityYV.push(velocityY);
		velocityXV.push(velocityX);
	}
}

//self explanatory;
public function findTOC(){
	if(timeVector.length > 0){
		minTOC = Math.min.apply(null,timeVector);
		var collisionMarker = timeVector.indexOf(minTOC);
		if(collisionMarker != 0)
			trace("COLLISION MARKER = " + collisionMarker);
		var tx = timeXV[collisionMarker];
		var ty = timeYV[collisionMarker];
		var at = actualTimeV[collisionMarker];
		var vy = velocityYV[collisionMarker];
		var vx = velocityXV[collisionMarker];
		player.y = player.y - ((1-at) * vy);
		if(tx < 1 && tx > 0){
			player.x = player.x - ((1-at) * vx);
		}
		if(timeXV.length > 0)
			timeXV.splice(collisionMarker, 1);
		if(timeYV.length > 0)
			timeYV.splice(collisionMarker, 1);
		if(actualTimeV.length > 0)	
			actualTimeV.splice(collisionMarker, 1);
		if(velocityYV.length > 0)
			velocityYV.splice(collisionMarker, 1);
		if(velocityXV.length > 0)
			velocityXV.splice(collisionMarker, 1);
		timeVector.splice(collisionMarker, 1);
	}
}
 
avatar for qwerber qwerber 4717 posts
Flag Post

for cases where timeX is equal to timeY, the rabbit can only go either back in 1 axis or the other; and you don’t know which is the right one (sliding against the ground vs pushing against a wall and jumping). This means that it is necessary to add a directional loop in your algorithm. This means, instead of for-in loops, you must use a numerical loop that accesses tiles by index; then loop either up or down depending on the current velocities.

 
avatar for alecz127 alecz127 817 posts
Flag Post
Originally posted by qwerber:

intelligent words!

“numerical loop that accesses tiles by index” Guess I’ll have to do some research. I barely understand what your getting at friend.

 
avatar for qwerber qwerber 4717 posts
Flag Post
Originally posted by alecz127:
Originally posted by qwerber:

intelligent words!

“numerical loop that accesses tiles by index” Guess I’ll have to do some research. I barely understand what your getting at friend.

lol its a for i++ or while i— or something like that then you go collide(i,j).

 
avatar for alecz127 alecz127 817 posts
Flag Post
Originally posted by qwerber:
Originally posted by alecz127:
Originally posted by qwerber:

intelligent words!

“numerical loop that accesses tiles by index” Guess I’ll have to do some research. I barely understand what your getting at friend.

lol its a for i++ or while i— or something like that then you go collide(i,j).

oh duh x D
Thanks a lot qwerber!

 
avatar for alecz127 alecz127 817 posts
Flag Post

Updated the code above to show what I’ve got so far. qwerber, why would I need to loop up or down dependent on the velocities?
Am I trying to only loop through a small amount of the overall array of collidable tiles via doing this?
I just don’t understand what I should be doing differently here.
Like I said before, something screwy is happening…
I also don’t understand what replacing the for in loop with the while loop did. It seems to be identical. Probably because it doesn’t increment and decrement depending on the velocity at this point, but I don’t understand that part.

What my code should be doing is

1) loop through all tiles and check for collision

2) if collision happens, add the time of the collision along with all variables needed to follow through with collision to an array of its own nature.

3) seperate loop that checks if theres any TOC’s to go through, if there is find the smallest TOC

4) instantiate collisionMarker variable so that the placement of the smallest TOC is also the placement of all related variables so as not to screw up the collision by applying variables that belong with a different TOC.

5) collision happens.

6) splice out each arrays value, at the index of the collisionMarker so as to remove the appropriate index, meaning the one that was just used.

7) ???

8) profit.

 
avatar for jasonjie88 jasonjie88 302 posts
Flag Post

In theory, you don’t need to loop through all tiles… at least, I didn’t have to. This method is easiest if the main character movieclip thingy has its reference point in the center, i.e. (0,0) is the center of the bunny, in fact it is recommended that you do this. This method is also easiest if the bunny movieclip is a square. It is preferred that the bunny is as big as a level ground tile too. It doesn’t mean this method will not work if the bunny movieclip is not a square, or if its reference point is not in the center, or not as big as a ground tile- it just is recommended that it is done this way. Less calculations this way, so the code is optimised.

My method of collision detection:

*1) *Pass the bunny’s length and height into some variables. If the reference point is in the center, pass in the bunny’s length divided by 2 and the bunny’s height divided by 2. If the bunny movieclip is a square, just pass in half of one side of the square. (Really though, if you want to change the bunny’s size by some growth powerup that stretches the bunny, or makes him fat, or something, I would recommend using two variables.

*2) *Find where the bunny will be in the next frame and pass it into some variables. Find the ‘future’ bunny’s x-coordinate by adding the bunny’s current x-coordinate to the bunny’s current x-velocity. Find the ‘future’ bunny’s y-coordinate by adding the bunny’s current y-coordinate to the bunny’s y-velocity.

Then, convert this into ‘tile’ coordinates. For example, if the bunny is at (400, 280) and each tile is 20×20, the bunny is at (20, 14) in tile coordinates.

*3) * Attempt to detect collisions. Here I will give a scenario. Let’s say the ‘future’ bunny is under an overhang such, if the bunny jumps, it should brush the side of the overhang. However, also note that if we use the four corner points of the bunny to check for a collision, positive collisions on the top-left and bottom-left corners means the bunny cannot move left. However, if the bunny moves a little bit left just before it brushes the wall of the overhang, the top-left corner will be positive, but the top-right corner will be negative. This shows the inaccuracy of this method. Really, what should be done is that points just before the corners of the movieclips should be used for collision detection. So there are eight points to be checked.

Assuming you have the reference point at the center, the collision detection points are:
From the top-left corner, one pixel right and one pixel up.
From the top-right corner, one pixel left and one pixel up.
From the top-left corner, one pixel left and one pixel down.
From the bottom-left corner, one pixel left and one pixel up.
From the top-right corner, one pixel right and one pixel down.
From the bottom-right corner, one pixel right and one pixel up.
From the bottom-left corner, one pixel right and one pixel down.
From the bottom-right corner, one pixel left and one pixel down.

To figure out whether there is a collision, calculate lvlArray[int(examplePointX/tileLength)][int(examplePointY/tileHeight)] for all eight points. Of course it is better to make the tiles square because you don’t need tileLength or tileHeight, just tileSideLength. Otherwise, there is another way: Place the level’s number of columns into the equation. Then you are calculating lvlArray[(int(examplePointX/tileLength))*lvlColumns + int(examplePointY/tileHeight)].

If any one of the first two points are detected, there’s a collision from above.
If any one of the second two points are detected, there’s a collision from the left.
If any one of the third two points are detected, there’s a collision from the right.
If any one of the last two points are detected, there’s a collision from below.
If there’s a ground collision from below, snap the bunny’s y-coordinate into place.
If there’s nothing below, fall.
If there’s a collision from above, don’t jump.
And so on.
Just repeatedly run the code, and as long as you use the collisions to help snap the player to the grid where there is ground, it should run seamlessly.

Turn these into tile coordinates and check these too.

I tested this method on my computer. It lagged on Power Saver mode, but worked seamlessly and quickly on High Performance mode, and my computer is a Windows Experience 3.2. Most modern computers would have a Windows Experience Index of 5.0-6.0, so I reckon it should work quite well on most up-to-date computers. I hope you understood; I wish I could explain it better. I would have posted a pic to help you get the idea if I could :( Sorry

 
avatar for jasonjie88 jasonjie88 302 posts
Flag Post

}

 
avatar for jasonjie88 jasonjie88 302 posts
Flag Post

Will be sending out code soon so you can get an example :) Used this method about a year ago. Just need to chop off some annoying bits of code. Do you use Flash? Because I’m afraid I wasn’t using classes a year ago, I was coding directly to the stage.

 
avatar for alecz127 alecz127 817 posts
Flag Post

oh man. Thank you for your reply. I appreciate. But the project I’m working on is work related, and I’ve been loitering on collision detection for way too long to move on to a different way of doing it.
I’ve already done about 3 or 4 different approaches to it, each failing.
I do use flash. Coding on the stage is baaaad. Things are way too messy.

 
avatar for alecz127 alecz127 817 posts
Flag Post

WAIT. I think I figured out why this is happening. The rabbit falls through the tiles when the rabbit is slightly sunken in, which makes him collide with the very little corner tip of the next ground tile he goes to run over. Which makes him fall through because yeah, make sense?

You see as soon as it touches the 2nd tile in the bottom half of the image, it falls straight through. Was actually difficult to get that screenshot before the falling started, so he might be a little sunken in the tile.
Anyway can do this or do I really need to rewrite my collision stuff again? The way qwerber wrote it, its suppose to collide with corners, so this is good. Just frustrating.
Going to try to figure out if qwerbers mention of the direction will fix this.

 
avatar for qwerber qwerber 4717 posts
Flag Post

Well, I think it’s because in the second picture the rabbit collides with the bottom left rect at exactly 90 degrees; Determining the axis of collision is either xTime < yTime or <=.

Let me explain it this way, there are 2 ways for 2 AABBs to collide. 1 is side on side collision, 2 is point on point collision. What I think is happening the the point on point collision. The problem is, what we solve that as if it is a side on side collision, only solving the collision on one of the axis, Which is the wrong axis.