Move by still makes my player skip the floor


(Abel Toy) #1

So I have this situation:

moveBy problem

That’d be two frames. When checking collisions, in frame 1 I can see I’m on the floor. In frame 2 I can also see I’m in the floor. So here is the problem, in both frames the player is on the floor. But between the frames, he isn’t.

Now, moveBy() was designed to solve this problem. To check for collidable objects in the middle.

The issue is, moveBy() is a bit broken. It doesn’t take into account certain situations. This is one of them.

The way it works, it first checks pixel-per-pixel the x-axis, and then the y-axis. Thing is, just doing that won’t solve my problem.

They way it’d have to be solved is, each time I move the x-axis by one, check if there is or there isn’t a floor.

So for moveBy to be accurate, it’d have to check each pixel in the whole square area of the movement… which is expensive.

Just wanted to point out that issue. MoveBy isn’t perfect, don’t always rely on it.

I’m trying to figure out a solution now. I’m thinking right now maybe I can check on which tile I am of the grid, see which tiles I’ve gone through, and if there’s floor below or not.


(Jacob Albano) #2

I had a similar situation in one of my games. You drag colored blocks around a grid. Blocks can move through others of the same color, but collide against those of a different color. The issue was that as long as you were inside one block (returning false in moveCollideX/Y), no further collision check was being done, so you could get blocks stuck inside of each other.

I ended up modifying the move function to move the entity the whole distance for each collision type listed, and reset its position each time.

MoveBy is nice, but it breaks really easily if you’re doing complex things.


(Ultima2876) #3

Yup, MoveBy definitely seems to be more of a ‘starting point’ where if you have specific situational needs like these you’ll need a more appropriate solution!


(Zachary Lewis) #4

For cases like this, you’ll want to take both x and y speed into consideration during your collision check. If a collision occurs, you need to find the depth of the collision (plunge depth) and move backward from your desired location. I made a gif because learning is more fun to watch!

Keep in mind that this is a near-phase collision technique that won’t always work for extremely fast moving objects. If your objects are moving so fast that they could completely skip over a tile, you’ll want to use a ray-trace to make sure you didn’t cross any collisions.


(Jacob Albano) #5

Goodness gracious, that gif is unbearably delicious.


(Ultima2876) #6

I just watched it like, 12 times before I could bring myself to close it.


(Zachary Lewis) #7

Here’s an example of a sweeping collision for fast-moving objects. You just need to check a box from where the object was to where it will be and boom.


(Jacob Albano) #8

This one doesn’t repeat D:

HOW WILL I ENTERTAIN MYSELF

In all seriousness though, this is super cool. I haven’t done a lot with collision that FP’s built-in functionality couldn’t handle, but you make it look so easy.


(Zachary Lewis) #9

Really? It repeats for me. :sweat_smile:


(Jacob Albano) #10

Huh, it’s working fine now. Also previously it would go to download if I tried to view it by itself, but that’s fixed too. Technology, man.


(Abel Toy) #11

I did this, after moving the entity

(caution: really bad code. Not optimised yet. First trying to get it work):

var solid:Entity = collide("solid", x, y);
if (solid)
{
	var centerA:Point = new Point(x, y - halfHeight);
	var centerB:Point = new Point(solid.x + solid.halfWidth, solid.y + solid.halfHeight);
	
	var distX:Number = centerA.x - centerB.x;
	var distY:Number = centerA.y - centerB.y;
	var minDistX:Number = halfWidth + solid.halfWidth;
	var minDistY:Number = halfHeight + solid.halfHeight;
	
	var depthX:Number = distX > 0 ? minDistX - distX : -minDistX - distX;
	var depthY:Number = distY > 0 ? minDistY - distY : -minDistY - distY;
	
	if (Math.abs(depthX) > Math.abs(depthY))
	{
		//y axis
		trace("y", depthX, depthY);
		y += depthY;
		collideY();
	}
	else
	{
		//x axis
		trace("x", depthX, depthY);
		x += depthX;
	}
}

It works good and everything, but it continues skipping the gaps.

I debugged it a bit and noticed that, sometimes, when the player is around here:

Player

It will get to the top of the first platform.

I’m trying to figure out what’s wrong with the way I’m doing it.

(sorry for not providing cool, entertaining gifs :P)


(Abel Toy) #12

Anyone has any ideas on how they’d fix this? Any methods?

I hate collision handling.

@zachwlewis - any additional stuff you can tell me? :stuck_out_tongue:


(azrafe7) #13

That’s an interesting problem… will definitely play aorund a bit to see if I can find a solution.

In the mean time I could suggest reducing the hitbox (if that’s feasible), or, better, just use another smaller hitbox at the feet of the player and run your checks against that for ground collisions (in my mind that should work, but haven’t tested it yet).


(Abel Toy) #14

@azrafe7: tried reducing the hitbox, but I need to be able to jump as late as possible… reducing the hitbox gives the player less time to jump, and we need the jump distance for pixel-almostperfect jumps.

Thanks for taking interest in this. I’m investigating as well, trying different techniques… but nothing seems to work. There’s predictive collisions for things in the middle, but not for no-things lol.


(Ultima2876) #15

**

Warning: hax0rz ti3m!!1111

**

How about adjusting the player’s hitbox when they are jumping (in the air state) and then reset it back to normal when they are on the ground? Essentially getting the best of both worlds.

[my apologies if that makes no sense given the context; it’s late and collision logic is a pig’s ear as you said]


(azrafe7) #16

Still fiddling with it…

thought about experimenting with the Bresenham line algo. So what I’m doing right now is using a custom / modified version of World.collideLine(). This way I can check for collisions every num pixels along the line (setting the precision could helpful performance-wise).

It doesn’t behave correctly yet, but you have the general idea. I’ll work on it tomorrow hopefully. Anyway here’s the main really messy function code I have by now: http://pastebin.com/59gPquQT.

If it works and is generic enough, we could try to optimize it and maybe even add it to the engine, no? :smirk:

EDIT: To expand on this:

I’m thinking about a sort of moveByInLine() (bad name but…) that will check for collisions at every pixel along the specified line, similar to what moveBy() does - more or less -, and calls something like moveCollideXY() so that it can be overridden. Meh… not sure I’ve explained myself as I would have liked to - late here! -.

EDIT AGAIN: FPFloorTest.swf (101.8 KB)


(Stefan Langeder) #17

I guess you should set your X speed to 0 if moveCollideX gets called. :wink:


(Abel Toy) #18

@Ultima2876: wouldn’t work. The problem is when the player doesn’t jump but still goes over the gap. The problem is it never detects the player is not on the floor. So, just setting the hitbox when it’s not on the floor wouldn’t fix that, as it never would be; and if I could reliably check that, I wouldn’t have a problem anyways.

@azrafe7: the idea is good. I also tried something like that, but thought maybe other methods would be better. I think I’ll give it a chance as well, see who finishes it first :stuck_out_tongue: (you’re on an advantage here as I won’t be able to work on it for a few hours haha)

@Stee: why? what would this improve? I don’t want the player to accelerate each time they collide horizontally. I want the speed to be constant except when the level begins, there’s a multiplier or he’s hit.


(azrafe7) #19

Not yet finished my implementation, but couldn’t resist and not post this Bresenham fun: :smirk:

FPBresenhamFun.swf (87.7 KB)

TestWorld.as (3.8 KB)


(Abel Toy) #20

Let’s have a Bresenparty everybody!