javascript - AABB collision resolution slipping sides -


so, reinventing wheel (and learning lot) trying hand @ making simple physics engine game engine. have been searching internet, trying (and failing) fix current problem. there lot of resources out there on subject, none of have found seem apply case.

the problem in short: collision resolution not work intended on of corners when 2 rectangles colliding. how fails varies based on dimensions of rectangles. looking "shortest overlap" kind of resolution collision or simple solution (i open suggestions!). (scroll down better explaination , illustrations).

warning: following code not efficient...

first of all, here physics loop. loops through of game entities , checks if collide other game entities. not efficient (n^2 , of that), works now.

updatephysics: function(step) {   // loop through entities , update positions based on velocities   (var entityid in vroom.entitylist) {     var entity = vroom.entitylist[entityid];     if (entity.physicsenabled) {       switch (entity.entitytype) {         case vroomentity.kinematic:           entity.pos.x += entity.vel.x * step;           entity.pos.y += entity.vel.y * step;           break;          case vroomentity.dynamic:           // dynamic stuff           break;       }     }   }   // loop through entities , detect collisions. resolve collisions detected.   (var entityid in vroom.entitylist) {     var entity = vroom.entitylist[entityid];     if (entity.physicsenabled && entity.entitytype !== vroomentity.static) {       (var targetid in vroom.entitylist) {         if (targetid !== entityid) {           var target = vroom.entitylist[targetid];           if (target.physicsenabled) {             // check if current entity , target colliding             if (vroom.collideentity(entity, target)) {               switch (entity.collisiontype) {                 case vroomentity.displace:                   vroom.resolvetesttest(entity, target);                   break;               }             }           }         }       }     }   } }, 

here code actual collision detection. seems work alright.

collideentity: function(entity, target) {   if (entity.getbottom() < target.gettop() || entity.gettop() > target.getbottom() ||  entity.getright() < target.getleft() ||  entity.getleft() > target.getright()) {     return false;   }    return true; }, 

here problems start pop up. want entity "pushed" out of target entity , have velocity set 0. works fine long both entity , target perfect squares. if let's entity (the player figure in gif) rectangle, collision "slipp" when colliding longest sides (the x axis) target (the square). if swap player dimensions short , wide, same problem appears y axis instead.

resolvetesttest: function(entity, target) {   var normalizedx = (target.getmidx() - entity.getmidx());   var normalizedy = (target.getmidy() - entity.getmidy());   var absolutenormalizedx = math.abs(normalizedx);   var absolutenormalizedy = math.abs(normalizedy);    console.log(absolutenormalizedx, absolutenormalizedy);    // collision comming left or right   if (absolutenormalizedx > absolutenormalizedy) {     if (normalizedx < 0) {       entity.pos.x = target.getright();     } else {       entity.pos.x = target.getleft() - entity.dim.width;     }      // set velocity 0     entity.vel.x = 0;      // collision comming top or bottom   } else {     if (normalizedy < 0) {       entity.pos.y = target.getbottom();     } else {       entity.pos.y = target.gettop() - entity.dim.height;     }      // set velocity 0     entity.vel.y = 0;   }  }, 

collision on y axis works these shapes gif

collision on x axis slips these shapes gif

what can fix slipping problem? have been bashing head against last 5 days, immensely grateful if 1 push me in right direction!

thank :)

-- edit: --

the slipping happens if moving in 1 direction along left or right side.

gif

-- edit 2 working code: -- see answer below example of working code!

the important logical error have made line:

if (absolutenormalizedx > absolutenormalizedy) {

this works if both entities square.

consider near-extremal case x-slipping example: if touch @ corner:

enter image description here

although diagram little exaggerated, can see absolutenormalizedx < absolutenormalizedy in case - implementation move on resolve vertical collision instead of expected horizontal one.


another error set corresponding velocity component 0 regardless of side collision on: must 0 component if in opposite direction collision normal, or won't able move away surface.


a way overcome record collided face(s) when collision detection:

collideentity: function(entity, target) {    // adjust parameter liking    var eps = 1e-3;     // no collision    var coll_x = entity.getright() > target.getleft() && entity.getleft() < target.getright();    var coll_y = entity.getbottom() > target.gettop() && entity.gettop() < target.getbottom();    if (!(coll_x && coll_y)) return 0;     // calculate bias flag in each direction    var bias_x = entity.targetx() < target.getmidx();    var bias_y = entity.targety() < target.getmidy();     // calculate penetration depths in each direction    var pen_x = bias_x ? (entity.getright() - target.getleft())                       : (target.getright() - entity.getleft());    var pen_y = bias_y ? (entity.getbottom() - target.getup())                       : (target.getbottom() - entity.getup());    var diff = pen_x - pen_y;     // x penetration greater    if (diff > eps)       return (1 << (bias_y ? 0 : 1));     // y pentration greater    else if (diff < -eps)        return (1 << (bias_x ? 2 : 3));     // both penetrations approximately equal -> treat corner collision    else       return (1 << (bias_y ? 0 : 1)) | (1 << (bias_x ? 2 : 3)); },  updatephysics: function(step) {    // ...             // pass collision flag resolver function             var result = vroom.collideentity(entity, target);             if (result > 0) {               switch (entity.collisiontype) {                 case vroomentity.displace:                   vroom.resolvetesttest(entity, target, result);                   break;               }             }    // ... } 

using bit flag instead of boolean array efficiency. resolver function can re-written as:

resolvetesttest: function(entity, target, flags) {   if (!!(flags & (1 << 0))) {  // collision upper surface       entity.pos.y = target.gettop() - entity.dim.height;       if (entity.vel.y > 0)  // travelling downwards          entity.vel.y = 0;   }    else   if (!!(flags & (1 << 1))) {  // collision lower surface       entity.pos.y = target.getbottom();       if (entity.vel.y < 0)  // travelling upwards          entity.vel.y = 0;   }    if (!!(flags & (1 << 2))) {  // collision left surface       entity.pos.x = target.getleft() - entity.dim.width;       if (entity.vel.x > 0)  // travelling rightwards          entity.vel.x = 0;   }    else   if (!!(flags & (1 << 3))) {  // collision right surface       entity.pos.x = target.getright();       if (entity.vel.x < 0)  // travelling leftwards          entity.vel.x = 0;   } }, 

note unlike original code, above allows corners collide - i.e. velocities , positions resolved along both axes.


Comments

Popular posts from this blog

angular - Ionic slides - dynamically add slides before and after -

minify - Minimizing css files -

Add a dynamic header in angular 2 http provider -