phaserjs / phaser

Phaser is a fun, free and fast 2D game framework for making HTML5 games for desktop and mobile web browsers, supporting Canvas and WebGL rendering.
https://phaser.io
MIT License
37.01k stars 7.08k forks source link

Collision in tilemaps doesn't work in dev branch. #127

Closed dibu28 closed 10 years ago

dibu28 commented 10 years ago

Error: Collision in tilemaps doesn't work in dev branch.

In examples ("sci fly.js" and "fill tiles.js") if you try to scroll the tilemap then the tilemap is scrolling but it seems like it's collisions are not scrolling.

photonstorm commented 10 years ago

You're right, will look at that later. Used to work fine, so probably something really small :)

photonstorm commented 10 years ago

Have dug into this a bit more and will get a patch rolled out early next week.

dibu28 commented 10 years ago

Thank you. Waiting for patch.

photonstorm commented 10 years ago

Just to say that I've been looking in to this and it's quite a bit more complex than I thought. It's actually nothing to do with tilemaps themselves, but actually how fixedToCamera sprites work (and also sprites that follow the camera), that causes their bodies to go out of sync. Still digging...

dibu28 commented 10 years ago

I've digged a little bit. And find out that sprite.body.x, sprite.body.y and body.hullX.x, body.hullY.y (in separateTileX and separateTileY) contain screen coordinates. But should they contain coordinates of game world and not screen for tilemaps to work properly?

photonstorm commented 10 years ago

I actually made a lot of progress on this last night and the current implementation seems to be working great. Certainly fixed the tilemap demos I had previously and all the collision tests still work too. Please grab the latest dev branch release and test for yourselves.

dibu28 commented 10 years ago

Ok. Just tested on the last commit in dev. And Collisions with tilemap seems to be working now.

But there is a small bug appeared: if I press two buttons simultaneously and my sprite is moving diagonally (like sprite.body.velocity.x = 150; sprite.body.velocity.y = 150;) it can go through the tile if it collides exactly on the corner of a tile.(corner of sprite collided with corner of tile) While collisions set to true on every side (tileset.setCollisionRange(0, tileset.total - 1, true, true, true, true);).

dibu28 commented 10 years ago

Tested a little more. Moving sprite diagonaly I can even get through walls if I set "velocity" on x and y to big numbers like 500 or 1000.

photonstorm commented 10 years ago

That doesn't surprise me, you've basically just tunnelled through the wall. There's no ray casting implementation in Phaser yet, so tunnelling will be common if you allow too high velocities for your tile sizes.

dibu28 commented 10 years ago

I've thought about tunnelling, but if I move sprite only in one direction X or Y axis it stops at walls and not going through walls.

photonstorm commented 10 years ago

I'll experiment some more today, what size tiles are you using?

dibu28 commented 10 years ago

In "fill tiles.js" example it's 32x32 and today I've tried "sci fly.js" it's 16x16 px.

dibu28 commented 10 years ago

I've debugged a little bit today and found that the problem was in functions separateTileX and separateTileY in those cases this._maxOverlap is smaller then this._overlap (for example this._maxOverlap was 13 and this._overlap was 18) and adjustment of sprite position and velocitie was not executed for the first tile. But on the next step this._maxOverlap was 13 and this._overlap was 2 so the sprite stopped at the next tile.

photonstorm commented 10 years ago

I was just playing with this eariler and came to the same conclusion - that for tile separation max overlap isn't actually needed at all. I've just removed it, am pushing a new dev branch build now - please could you test against your samples and let me know if it works better for you.

photonstorm commented 10 years ago

I'm happy this is sorted now so I'm going to close it, but if you do find issues please open a new report (or re-open this if you like) and throw some sample code at me.

dibu28 commented 10 years ago

I'll test this couple of weeks later on my dev rig. For now it seems working fine.

dibu28 commented 10 years ago

I've tested a little more and there is one of the bugs still present. If (for example) I move sprite to the right and it hits the wall and I continue to press button to move right for a couple of seconds, sprite can jump through one or couple of bricks. I've debugged and find out that in this case DeltaX can change like this (-3, -5 ,-2, -150) and the DeltaX = this.x - this.preX; Where preX = 320 (which is correct) but this.x = 170 (which is wrong, the sprite inside the tiles).

The problem is in the folowing: It seems that the coordinates of the sprite are updated in some loop inside phaser which is not tied to RAF or timer. But collision detection is executed inside update method in the "sci fly.js" (game.physics.collide(sprite, layer);) which seems to be tied to RAF or timer. And if there is some frame drops or low fps occure then sprite continue to move (velocity continue to be added) but collision detection is not executed(becouse it is tied to RAF) and sprite gets far away through tiles.

The problem is hard to reproduce on desktop. I've used virtual machine with 2 cores to see it. And I think it can appear on some mobiles.

The question is: should the collision detection be executed right after coordinates of sprites are changed or am I missing some callback or method which can help to set this.

photonstorm commented 10 years ago

In the main (raf controlled) loop the Sprite positions and motion is updated during the world.update call. This is what runs updateMotion on a sprite body.

After this runs the state.update runs. This is when any calls to collide, changes in velocity etc are applied to the sprite.

Then there is a world.postUpdate call. This tells the sprite body to adjust the sprites position (just in time for rendering) based on its delta value.

All of this happens via a single raf loop.

I think you are on to something here though, i.e. you're getting very close to the source of a problem, but I'm not sure it's to do with code being executed out of sync unless it's possible for the core game loop to be called by raf while it's is already running which I'm pretty certain can't happen.

dibu28 commented 10 years ago

Just tested against 1.1.6 releaase and every thing seems working fine now.