TileMap Solid Actor Physics Clipping Issue

42 views
Skip to first unread message

Andrew Exton

unread,
Feb 24, 2018, 2:44:25 AM2/24/18
to excaliburjs
Hi,

recently started developing a multiplayer platformer game using excaliberjs. I implemented a TileMap that uses an exported Tiled json file to load in the platformer map. Essentially the TileMap consists of either solid or non-solid unit blocks to make up the playable level. When I have a Actor (our runner, just a cube in this case effected by the physics engine gravity) "run" across the floor created from the solid components of the TileMap, the runner will get stuck at the seams between two unit blocks. The issue causes the physics engine to bug, and the Actor ends up clipping through the TileMap. I was wondering if anyone else has run into this issue? I've been super impressed with the speed I've been able to develop with this framework so far, but currently stuck from this issue. Any thoughts or advice is appreciated, thanks!
TileMapClipBug2.gif

Erik Onarheim

unread,
Feb 26, 2018, 9:17:04 AM2/26/18
to excaliburjs
Hi Andrew,

Do you have a code sample I can run to reproduce the issue? Either a small repo or a codepen?

Thanks,
Erik

Andrew Exton

unread,
Feb 26, 2018, 11:22:57 PM2/26/18
to excaliburjs
Just got off work and was able to recreate the issue in a smaller repository!

Erik Onarheim

unread,
Feb 27, 2018, 8:25:13 PM2/27/18
to excaliburjs
Hi Andrew,

I've taken a look at your repro, this is definitely an bug in excalibur. We have an issue to address tilemap collisions in the backlog, I'll move it up to target a robust fix the next release of the engine (https://github.com/excaliburjs/Excalibur/issues/626).

The first problem is that tilemaps currently don't zero out the component of velocity from other actors upon collision, like in the normal collision system. Because global acceleration is always on, velocity accumulates until it can update through the edge of the tilemap. The second problem is that fast moving objects can accidentally warp through walls because each frame moves the object velocity pixels/second across the screen. This is fixed for most of excalibur, except for tilemaps https://github.com/excaliburjs/Excalibur/issues/665

I've been able to create a workaround for you (unfortunately it's not the prettiest) to temporarily solve this until we can fix it at the engine level.

Let me know if you run into anything else :)

This is the updated version of test.ts

import * as ex from 'excalibur';
import TiledResource from '../src';
import { Actor } from 'excalibur';

var game = new ex.Engine({
   width: 500,
   height: 400,
   canvasElementId: 'game',
  pointerScope: ex.Input.PointerScope.Canvas
});

var start = (mapFile) => {

   ex.Physics.collisionResolutionStrategy = ex.CollisionResolutionStrategy.RigidBody;

   // set global acceleration simulating gravity pointing down
  ex.Physics.defaultMass = 100;
  ex.Physics.acc.setTo(0, 700);

   ex.Physics.showMotionVectors = true;
  ex.Physics.checkForFastBodies = true;

   // enable physics
  ex.Physics.enabled = true;

   var map = new TiledResource(mapFile);
  var loader = new ex.Loader([map]);
 
   game.currentScene.tileMaps = []
  game.start(loader).then(function() {
     
     map.data.tilesets.forEach(function(ts) {
        console.log(ts.image, ts.imageTexture.isLoaded());
     });

      const tileMap: ex.TileMap = map.getTileMap();

      const layer: any = map.data.layers[0];
     for (let i: number = 0; i < layer.height; i++) {
       for (let j: number = 0; j < layer.width; j++) {
         if (layer.data[i * layer.width + j] !== 0) {
           tileMap.data[i * layer.width + j].solid = true;
         }
       }
     }

      var tm = map.getTileMap();

      game.add(tm);

      game.addTileMap(tileMap);

      let runner = new Actor(60, 60, 10, 10);
     runner.collisionType = ex.CollisionType.Active;
     runner.color = ex.Color.Red;
     runner.body.useBoxCollision();

      // There is an issue for this: https://github.com/excaliburjs/Excalibur/issues/626
     // Unfortunately tilemaps don't yet operate in the nice new physics system
     // The root cause of the problem is that while the actor is sitting on the tile, it
     // gradually accumulates velocity until it is so high that a single engine tick updates
     // it over the floor. I'll pull this in to the next release milestone, the work-around for
      // now is to manually set the velocity when the bottom of the box collides.

      let delta = 16/1000; // default to 60fps to start
     let intersection = ex.Vector.Zero;
     runner.on('precollision', (evt: ex.PostCollisionEvent) => {
        if (evt.side === ex.Side.Bottom && evt.other === null) {
           evt.actor.vel.y = 0;
           evt.actor.pos.y += evt.intersection.y;
           evt.actor.pos.y -= ex.Physics.acc.y * delta * delta;
        }
     });

      runner.on('preupdate', (evt: ex.PreUpdateEvent) => {
        delta = evt.delta/1000; // convert to seconds
     });

      // Because the current tilemap implementation does not deal with fast acceleration well with
     // small objects we need to check for skipped frames and correct.
     runner.on('postupdate', () => {
        if (delta > 32/1000) {
           // catch frame drops that can increase update distance and reset to last know good position/velocity for 1 frame
           runner.vel = runner.oldVel;
           runner.pos = runner.oldPos;
           console.log('reset')
        }

      });

      game.input.keyboard.on('press', (evt) => {
        if (evt.key === ex.Input.Keys.Left){
           runner.vel.x = -20;
        }

         if (evt.key === ex.Input.Keys.Right) {
           runner.vel.x = 20;
        }

         if (evt.key === ex.Input.Keys.Up) {
           runner.vel.y = -400;
        }
     })


     

      game.add(runner);

   });
}

document.getElementById('select-map').addEventListener('change', (e) => {
  var map = (e.target as HTMLSelectElement).value;

   if (map) {
     start(map);
  }

   return true;
})

start("test-v2.json");


Cheers,
Erik

Andrew Exton

unread,
Feb 27, 2018, 9:59:32 PM2/27/18
to excaliburjs
Really appreciate the rapid response and your work! Just made my day :)

Erik Onarheim

unread,
Apr 6, 2018, 9:56:59 AM4/6/18
to Andrew Exton, excaliburjs
Hi Andrew,

We have a fix for this that shipped in v0.16.0 last night!

Thanks for bringing this to our attention!

--
You received this message because you are subscribed to the Google Groups "excaliburjs" group.
To unsubscribe from this group and stop receiving emails from it, send an email to excaliburjs...@googlegroups.com.
To post to this group, send email to excal...@googlegroups.com.
Visit this group at https://groups.google.com/group/excaliburjs.
To view this discussion on the web visit https://groups.google.com/d/msgid/excaliburjs/dfc31bb0-452d-4c0f-8853-0d8f8c72de80%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Reply all
Reply to author
Forward
0 new messages