Skip to content

Instantly share code, notes, and snippets.

@kirbysayshi
Created July 5, 2012 15:43
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kirbysayshi/3054439 to your computer and use it in GitHub Desktop.
Save kirbysayshi/3054439 to your computer and use it in GitHub Desktop.
ig.module(
'plugins.collision-map-intersect'
)
.requires(
'impact.collision-map'
,'plugins.math'
)
.defines(function(){
// Injects:
// res.collision.snx: surface normal x
// res.collision.sny: surface normal y
// res.collision.initial = { x, y }: the point at which the projected velocity line collides with a tile
ig.CollisionMap.inject({
_traceStep: function( res, x, y, vx, vy, width, height, rvx, rvy, step ) {
this.parent.apply(this, arguments);
var pxTileX, pxTileY, iRes = {}
,a1x = x + width / 2
,a1y = y + height / 2
,a2x = a1x + vx
,a2y = a1y + vy
// if vx or vy is 0, that means it's already been handled
if( res.collision.x && vx !== 0 ){
pxTileX = res.pos.x
+ (vx > 0 ? width : 0) // correct for "pxOffsetX"
//- (vx > 0 ? this.tilesize : 0 ); // correct for tileOffsetX
// perform intersection test with velocity line and vertical tile line.
// the 0/100 is arbitrary, to extend the vertical line a "visible" amount.
// this assumes the velocity vector is projected out from the center
// when in actuallity the initial check was projected from the upper left corner
ig.math.intersectLineLine(
a1x, a1y, a2x, a2y,
pxTileX, 0, pxTileX, 100,
iRes
);
res.collision.snx = vx > 0 ? -1 : 1;
res.collision.sny = 0;
}
if( res.collision.y && vy !== 0 ){
pxTileY = res.pos.y
+ (vy > 0 ? height : 0) // correct for "pxOffsetX"
//+ (vy > 0 ? this.tilesize : 0); // correct for tileOffsetX
// perform intersection test with velocity line and horizontal tile line.
// the 100s are arbitrary, to extend the horizontal line a "visible" amount.
// this assumes the velocity vector is projected out from the center
// when in actuallity the initial check was projected from the upper left corner
ig.math.intersectLineLine(
a1x, a1y, a2x, a2y,
0, pxTileY, 100, pxTileY,
iRes
);
res.collision.snx = 0;
res.collision.sny = vy > 0 ? -1 : 1;
}
if( res.collision.slope ){
res.collision.snx = res.collision.slope.nx;
res.collision.sny = res.collision.slope.ny;
}
if( iRes.line ){
res.collision.initial = { x: iRes.line.x, y: iRes.line.y };
}
}
,_checkTileDef: function( res, t, x, y, vx, vy, width, height, tileX, tileY ) {
var def = this.tiledef[t];
if( !def ) { return false; }
var result = this.parent.apply(this, arguments)
,slope = res.collision.slope
,a1x
,a1y
,a2x
,a2y
,b1x
,b1y
,b2x
,b2y
,iRes = {};
if( result && slope ){
// lx/ly appears to ALWAYS be the absolute pixel coords of the lower right
// corner of the collided tile.
// This point + the normal can define a parametric plane (really
// a line because this is 2D) which can be used to determine where
// the plane and the velocity vector (x,y -> x+vx,y+vy) cross.
slope.lx = (tileX + def[0]) * this.tilesize
slope.ly = (tileY + def[1]) * this.tilesize
a1x = (tileX + def[0]) * this.tilesize
a1y = (tileY + def[1]) * this.tilesize
a2x = (tileX + def[2]) * this.tilesize
a2y = (tileY + def[3]) * this.tilesize
// this assumes the velocity vector is projected out from the center
// when in actuallity the initial check was projected from the upper left corner
b1x = x + (width / 2)
b1y = y + (height / 2)
b2x = b1x + vx
b2y = b1y + vy
ig.math.intersectLineLine( a1x, a1y, a2x, a2y, b1x, b1y, b2x, b2y, iRes );
if( iRes.line ){
res.collision.initial = { x: iRes.line.x, y: iRes.line.y };
}
}
return result;
}
});
});
ig.module(
'plugins.math'
)
.requires()
.defines(function(){
ig.math = ig.math || {};
ig.math.angleTo = function( v1x, v1y, v2x, v2y ){
var v1atan = Math.atan2( v1y, v1x )
v2atan = 0;
if( v2x != null && v2y != null ){
v2atan = Math.atan2( v2y, v2x )
}
return v1atan - v2atan;
}
// adapted/ported from: http://paulbourke.net/geometry/lineline2d/Helpers.cs
ig.math.intersectLineLine = function(a1x, a1y, a2x, a2y, b1x, b1y, b2x, b2y, res){
res = res || {};
res.parallel = false;
res.coincidental = false;
res.line = false;
res.segment = false;
var denom = (b2y - b1y) * (a2x - a1x) - (b2x - b1x) * (a2y - a1y)
,n_a = (b2x - b1x) * (a1y - b1y) - (b2y - b1y) * (a1x - b1x)
,n_b = (a2x - a1x) * (a1y - b1y) - (a2y - a1y) * (a1x - b1x);
// check for lines being parallel (or possibly coincidental)
if( denom == 0 ){
res.parallel = true;
if( n_a === 0 && n_b === 0 ){
res.coincidental = true;
}
return false
}
// calculate the scalar (fractional) that determines where each line
// could intersect (t in many versions)
var ua = n_a / denom
,ub = n_b / denom;
res.line = {
x: a1x + ( ua * (a2x - a1x) )
,y: a1y + ( ua * (a2y - a1y) )
};
// test if segments intersect. 0 >= ua <= 1 implies intersection of
// the given segments, while 0 > ua > 1 implies that only the defined
// lines intersect
if( ua >= 0 && ua <= 1 && ub >= 0 && ub <= 1 ){
res.segment = res.line;
}
return true;
}
ig.math.exportV3 = function(){
ig.global.v3 = ov3;
}
ig.math.v3 = ov3;
var ov3 = function(x, y, z){
return {
x: x || 0,
y: y || 0,
z: z || 0
}
};
ov3.asArray = function( v1, target ){
if( !target ){
target = [ v1.x, v1.y, v1.z || 0 ]
} else {
target[0] = v1.x;
target[1] = v1.y;
target[2] = v1.z || 0;
}
return target;
}
ov3.fromArray = function( v1arr, target ){
target = target || ov3();
target.x = v1arr[0];
target.y = v1arr[1];
target.z = v1arr[2] || 0;
return target;
}
ov3.add = function(v1, v2, target){
if(!target) target = v1;
target.x = v1.x + v2.x;
target.y = v1.y + v2.y;
target.z = v1.z + v2.z || 0;
return target;
}
ov3.sub = function(v1, v2, target){
if(!target) target = v1;
target.x = v1.x - v2.x;
target.y = v1.y - v2.y;
target.z = v1.z - v2.z || 0;
return target;
}
ov3.scale = function(v1, x, target){
if(!target) target = v1;
target.x = v1.x * x;
target.y = v1.y * x;
target.z = v1.z * x || 0;
return target;
}
ov3.normalize = function(v1, target){
if(!target) target = v1;
var x = v1.x
,y = v1.y
,z = v1.z || 0
,len = 1 / Math.sqrt(x*x + y*y + z*z);
target.x = x * len;
target.y = x * len;
target.z = x * len;
return target;
}
ov3.length = function(v1){
var x = v1.x + v2.x
,y = v1.y + v2.y
,z = v1.z + v2.z || 0
return Math.sqrt(x*x + y*y + z*z);
}
ov3.dot = function( v1, v2 ){
return v1.x*v2.x + v1.y*v2.y + (v1.z || 0)*(v2.z || 0);
}
ov3.direction = function( v1, v2, target ){
target = target || v1;
var x = v2.x - v1.x
,y = v2.y - v1.y
,z = v2.z - v1.z || 0
,len = Math.sqrt(x*x + y*y + z*z);
if (!len) {
target.x = 0;
target.y = 0;
target.z = 0;
return target;
}
len = 1 / len;
target.x = x * len;
target.y = y * len;
target.z = z * len;
return target;
}
ov3.angleTo = function( v1, v2 ){
var v1atan = Math.atan2( v1.y, v1.x )
v2atan = 0;
if( v2 ){
v2atan = Math.atan2( v2.y, v2.x )
}
return v1atan - v2atan;
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment