diff --git a/Phaser/physics/AABB.js b/Phaser/physics/AABB.js index c516ea1c..60848be4 100644 --- a/Phaser/physics/AABB.js +++ b/Phaser/physics/AABB.js @@ -17,9 +17,15 @@ var Phaser; this.yw = Math.abs(yw); this.aabbTileProjections = {}; - this.aabbTileProjections[Phaser.Physics.TileMapCell.CTYPE_FULL] = Phaser.Physics.Projection.AABBFull.Collide; + this.aabbTileProjections[Phaser.Physics.TileMapCell.CTYPE_22DEGs] = Phaser.Physics.Projection.AABB22Deg.CollideS; + this.aabbTileProjections[Phaser.Physics.TileMapCell.CTYPE_22DEGb] = Phaser.Physics.Projection.AABB22Deg.CollideB; + this.aabbTileProjections[Phaser.Physics.TileMapCell.CTYPE_45DEG] = Phaser.Physics.Projection.AABB45Deg.Collide; + this.aabbTileProjections[Phaser.Physics.TileMapCell.CTYPE_67DEGs] = Phaser.Physics.Projection.AABB67Deg.CollideS; + this.aabbTileProjections[Phaser.Physics.TileMapCell.CTYPE_67DEGb] = Phaser.Physics.Projection.AABB67Deg.CollideB; this.aabbTileProjections[Phaser.Physics.TileMapCell.CTYPE_CONCAVE] = Phaser.Physics.Projection.AABBConcave.Collide; this.aabbTileProjections[Phaser.Physics.TileMapCell.CTYPE_CONVEX] = Phaser.Physics.Projection.AABBConvex.Collide; + this.aabbTileProjections[Phaser.Physics.TileMapCell.CTYPE_FULL] = Phaser.Physics.Projection.AABBFull.Collide; + this.aabbTileProjections[Phaser.Physics.TileMapCell.CTYPE_HALF] = Phaser.Physics.Projection.AABBHalf.Collide; } AABB.prototype.integrateVerlet = function () { var d = 1; @@ -42,6 +48,7 @@ var Phaser; }; AABB.prototype.reportCollisionVsWorld = function (px, py, dx, dy, obj) { + if (typeof obj === "undefined") { obj = null; } var p = this.pos; var o = this.oldpos; diff --git a/Phaser/physics/Circle.js b/Phaser/physics/Circle.js index d5be7a2c..0160a065 100644 --- a/Phaser/physics/Circle.js +++ b/Phaser/physics/Circle.js @@ -15,10 +15,15 @@ var Phaser; this.radius = radius; this.circleTileProjections = {}; - this.circleTileProjections[Phaser.Physics.TileMapCell.CTYPE_FULL] = Phaser.Physics.Projection.CircleFull.Collide; + this.circleTileProjections[Phaser.Physics.TileMapCell.CTYPE_22DEGs] = Phaser.Physics.Projection.Circle22Deg.CollideS; + this.circleTileProjections[Phaser.Physics.TileMapCell.CTYPE_22DEGb] = Phaser.Physics.Projection.Circle22Deg.CollideB; this.circleTileProjections[Phaser.Physics.TileMapCell.CTYPE_45DEG] = Phaser.Physics.Projection.Circle45Deg.Collide; + this.circleTileProjections[Phaser.Physics.TileMapCell.CTYPE_67DEGs] = Phaser.Physics.Projection.Circle67Deg.CollideS; + this.circleTileProjections[Phaser.Physics.TileMapCell.CTYPE_67DEGb] = Phaser.Physics.Projection.Circle67Deg.CollideB; this.circleTileProjections[Phaser.Physics.TileMapCell.CTYPE_CONCAVE] = Phaser.Physics.Projection.CircleConcave.Collide; this.circleTileProjections[Phaser.Physics.TileMapCell.CTYPE_CONVEX] = Phaser.Physics.Projection.CircleConvex.Collide; + this.circleTileProjections[Phaser.Physics.TileMapCell.CTYPE_FULL] = Phaser.Physics.Projection.CircleFull.Collide; + this.circleTileProjections[Phaser.Physics.TileMapCell.CTYPE_HALF] = Phaser.Physics.Projection.CircleHalf.Collide; } Circle.prototype.integrateVerlet = function () { var d = 1; @@ -41,7 +46,10 @@ var Phaser; p.y += (d * py) - (d * oy) + g; }; + // px projection vector + // dx surface normal Circle.prototype.reportCollisionVsWorld = function (px, py, dx, dy, obj) { + if (typeof obj === "undefined") { obj = null; } var p = this.pos; var o = this.oldpos; diff --git a/Phaser/physics/Circle.ts b/Phaser/physics/Circle.ts index 018da87d..c29952ac 100644 --- a/Phaser/physics/Circle.ts +++ b/Phaser/physics/Circle.ts @@ -97,7 +97,7 @@ module Phaser.Physics { fy = ty * f; //b = 1 + BOUNCE;//this bounce constant should be elsewhere, i.e inside the object/tile/etc.. - b = 1 + 0.9;//this bounce constant should be elsewhere, i.e inside the object/tile/etc.. + b = 1 + 0.3;//this bounce constant should be elsewhere, i.e inside the object/tile/etc.. bx = (nx * b); by = (ny * b); diff --git a/Phaser/physics/aabb/ProjAABB22Deg.js b/Phaser/physics/aabb/ProjAABB22Deg.js index 2f9b5688..98cde05f 100644 --- a/Phaser/physics/aabb/ProjAABB22Deg.js +++ b/Phaser/physics/aabb/ProjAABB22Deg.js @@ -1,19 +1,110 @@ -var Shapes; -(function (Shapes) { +var Phaser; +(function (Phaser) { + (function (Physics) { + /// + /** + * Phaser - Physics - Projection + */ + (function (Projection) { + var AABB22Deg = (function () { + function AABB22Deg() { + } + AABB22Deg.CollideS = function (x, y, obj, t) { + var signx = t.signx; + var signy = t.signy; - var Point = Shapes.Point = (function () { - function Point(x, y) { - this.x = x; - this.y = y; - } - Point.prototype.getDist = function () { - return Math.sqrt((this.x * this.x) + (this.y * this.y)); - }; - Point.origin = new Point(0, 0); - return Point; - })(); + //first we need to check to make sure we're colliding with the slope at all + var py = obj.pos.y - (signy * obj.yw); + var penY = t.pos.y - py; -})(Shapes || (Shapes = {})); + if (0 < (penY * signy)) { + var ox = (obj.pos.x - (signx * obj.xw)) - (t.pos.x + (signx * t.xw)); + var oy = (obj.pos.y - (signy * obj.yw)) - (t.pos.y - (signy * t.yw)); -var p = new Shapes.Point(3, 4); -var dist = p.getDist(); + var sx = t.sx; + var sy = t.sy; + + //if the dotprod of (ox,oy) and (sx,sy) is negative, the corner is in the slope + //and we need toproject it out by the magnitude of the projection of (ox,oy) onto (sx,sy) + var dp = (ox * sx) + (oy * sy); + + if (dp < 0) { + //collision; project delta onto slope and use this to displace the object + sx *= -dp; + sy *= -dp; + + var lenN = Math.sqrt(sx * sx + sy * sy); + var lenP = Math.sqrt(x * x + y * y); + + var aY = Math.abs(penY); + if (lenP < lenN) { + if (aY < lenP) { + obj.reportCollisionVsWorld(0, penY, 0, penY / aY, t); + + return Phaser.Physics.AABB.COL_OTHER; + } else { + obj.reportCollisionVsWorld(x, y, x / lenP, y / lenP, t); + + return Phaser.Physics.AABB.COL_AXIS; + } + } else { + if (aY < lenN) { + obj.reportCollisionVsWorld(0, penY, 0, penY / aY, t); + + return Phaser.Physics.AABB.COL_OTHER; + } else { + obj.reportCollisionVsWorld(sx, sy, t.sx, t.sy, t); + + return Phaser.Physics.AABB.COL_OTHER; + } + } + } + } + + //if we've reached this point, no collision has occured + return Phaser.Physics.AABB.COL_NONE; + }; + + AABB22Deg.CollideB = function (x, y, obj, t) { + var signx = t.signx; + var signy = t.signy; + + var ox = (obj.pos.x - (signx * obj.xw)) - (t.pos.x - (signx * t.xw)); + var oy = (obj.pos.y - (signy * obj.yw)) - (t.pos.y + (signy * t.yw)); + + var sx = t.sx; + var sy = t.sy; + + //if the dotprod of (ox,oy) and (sx,sy) is negative, the corner is in the slope + //and we need toproject it out by the magnitude of the projection of (ox,oy) onto (sx,sy) + var dp = (ox * sx) + (oy * sy); + + if (dp < 0) { + //collision; project delta onto slope and use this to displace the object + sx *= -dp; + sy *= -dp; + + var lenN = Math.sqrt(sx * sx + sy * sy); + var lenP = Math.sqrt(x * x + y * y); + + if (lenP < lenN) { + obj.reportCollisionVsWorld(x, y, x / lenP, y / lenP, t); + + return Phaser.Physics.AABB.COL_AXIS; + } else { + obj.reportCollisionVsWorld(sx, sy, t.sx, t.sy, t); + + return Phaser.Physics.AABB.COL_OTHER; + } + } + + return Phaser.Physics.AABB.COL_NONE; + }; + return AABB22Deg; + })(); + Projection.AABB22Deg = AABB22Deg; + })(Physics.Projection || (Physics.Projection = {})); + var Projection = Physics.Projection; + })(Phaser.Physics || (Phaser.Physics = {})); + var Physics = Phaser.Physics; +})(Phaser || (Phaser = {})); diff --git a/Phaser/physics/aabb/ProjAABB45Deg.js b/Phaser/physics/aabb/ProjAABB45Deg.js index 2f9b5688..8b10da13 100644 --- a/Phaser/physics/aabb/ProjAABB45Deg.js +++ b/Phaser/physics/aabb/ProjAABB45Deg.js @@ -1,19 +1,56 @@ -var Shapes; -(function (Shapes) { +var Phaser; +(function (Phaser) { + (function (Physics) { + /// + /** + * Phaser - Physics - Projection + */ + (function (Projection) { + var AABB45Deg = (function () { + function AABB45Deg() { + } + AABB45Deg.Collide = function (x, y, obj, t) { + var signx = t.signx; + var signy = t.signy; - var Point = Shapes.Point = (function () { - function Point(x, y) { - this.x = x; - this.y = y; - } - Point.prototype.getDist = function () { - return Math.sqrt((this.x * this.x) + (this.y * this.y)); - }; - Point.origin = new Point(0, 0); - return Point; - })(); + var ox = (obj.pos.x - (signx * obj.xw)) - t.pos.x; + var oy = (obj.pos.y - (signy * obj.yw)) - t.pos.y; -})(Shapes || (Shapes = {})); + var sx = t.sx; + var sy = t.sy; -var p = new Shapes.Point(3, 4); -var dist = p.getDist(); + //if the dotprod of (ox,oy) and (sx,sy) is negative, the corner is in the slope + //and we need toproject it out by the magnitude of the projection of (ox,oy) onto (sx,sy) + var dp = (ox * sx) + (oy * sy); + + if (dp < 0) { + //collision; project delta onto slope and use this to displace the object + sx *= -dp; + sy *= -dp; + + var lenN = Math.sqrt(sx * sx + sy * sy); + var lenP = Math.sqrt(x * x + y * y); + + if (lenP < lenN) { + //project along axis + obj.reportCollisionVsWorld(x, y, x / lenP, y / lenP, t); + + return Phaser.Physics.AABB.COL_AXIS; + } else { + //project along slope + obj.reportCollisionVsWorld(sx, sy, t.sx, t.sy); + + return Phaser.Physics.AABB.COL_OTHER; + } + } + + return Phaser.Physics.AABB.COL_NONE; + }; + return AABB45Deg; + })(); + Projection.AABB45Deg = AABB45Deg; + })(Physics.Projection || (Physics.Projection = {})); + var Projection = Physics.Projection; + })(Phaser.Physics || (Phaser.Physics = {})); + var Physics = Phaser.Physics; +})(Phaser || (Phaser = {})); diff --git a/Phaser/physics/aabb/ProjAABB67Deg.js b/Phaser/physics/aabb/ProjAABB67Deg.js index 2f9b5688..a76e3938 100644 --- a/Phaser/physics/aabb/ProjAABB67Deg.js +++ b/Phaser/physics/aabb/ProjAABB67Deg.js @@ -1,19 +1,108 @@ -var Shapes; -(function (Shapes) { +var Phaser; +(function (Phaser) { + (function (Physics) { + /// + /** + * Phaser - Physics - Projection + */ + (function (Projection) { + var AABB67Deg = (function () { + function AABB67Deg() { + } + AABB67Deg.CollideS = function (x, y, obj, t) { + var signx = t.signx; + var signy = t.signy; - var Point = Shapes.Point = (function () { - function Point(x, y) { - this.x = x; - this.y = y; - } - Point.prototype.getDist = function () { - return Math.sqrt((this.x * this.x) + (this.y * this.y)); - }; - Point.origin = new Point(0, 0); - return Point; - })(); + var px = obj.pos.x - (signx * obj.xw); + var penX = t.pos.x - px; -})(Shapes || (Shapes = {})); + if (0 < (penX * signx)) { + var ox = (obj.pos.x - (signx * obj.xw)) - (t.pos.x - (signx * t.xw)); + var oy = (obj.pos.y - (signy * obj.yw)) - (t.pos.y + (signy * t.yw)); -var p = new Shapes.Point(3, 4); -var dist = p.getDist(); + var sx = t.sx; + var sy = t.sy; + + //if the dotprod of (ox,oy) and (sx,sy) is negative, the corner is in the slope + //and we need to project it out by the magnitude of the projection of (ox,oy) onto (sx,sy) + var dp = (ox * sx) + (oy * sy); + if (dp < 0) { + //collision; project delta onto slope and use this to displace the object + sx *= -dp; + sy *= -dp; + + var lenN = Math.sqrt(sx * sx + sy * sy); + var lenP = Math.sqrt(x * x + y * y); + + var aX = Math.abs(penX); + if (lenP < lenN) { + if (aX < lenP) { + obj.reportCollisionVsWorld(penX, 0, penX / aX, 0, t); + + return Phaser.Physics.AABB.COL_OTHER; + } else { + obj.reportCollisionVsWorld(x, y, x / lenP, y / lenP, t); + + return Phaser.Physics.AABB.COL_AXIS; + } + } else { + if (aX < lenN) { + obj.reportCollisionVsWorld(penX, 0, penX / aX, 0, t); + + return Phaser.Physics.AABB.COL_OTHER; + } else { + obj.reportCollisionVsWorld(sx, sy, t.sx, t.sy, t); + + return Phaser.Physics.AABB.COL_OTHER; + } + } + } + } + + //if we've reached this point, no collision has occured + return Phaser.Physics.AABB.COL_NONE; + }; + + AABB67Deg.CollideB = function (x, y, obj, t) { + var signx = t.signx; + var signy = t.signy; + + var ox = (obj.pos.x - (signx * obj.xw)) - (t.pos.x + (signx * t.xw)); + var oy = (obj.pos.y - (signy * obj.yw)) - (t.pos.y - (signy * t.yw)); + + var sx = t.sx; + var sy = t.sy; + + //if the dotprod of (ox,oy) and (sx,sy) is negative, the corner is in the slope + //and we need toproject it out by the magnitude of the projection of (ox,oy) onto (sx,sy) + var dp = (ox * sx) + (oy * sy); + + if (dp < 0) { + //collision; project delta onto slope and use this to displace the object + sx *= -dp; + sy *= -dp; + + var lenN = Math.sqrt(sx * sx + sy * sy); + var lenP = Math.sqrt(x * x + y * y); + + if (lenP < lenN) { + obj.reportCollisionVsWorld(x, y, x / lenP, y / lenP, t); + + return Phaser.Physics.AABB.COL_AXIS; + } else { + obj.reportCollisionVsWorld(sx, sy, t.sx, t.sy, t); + + return Phaser.Physics.AABB.COL_OTHER; + } + } + + return Phaser.Physics.AABB.COL_NONE; + }; + return AABB67Deg; + })(); + Projection.AABB67Deg = AABB67Deg; + })(Physics.Projection || (Physics.Projection = {})); + var Projection = Physics.Projection; + })(Phaser.Physics || (Phaser.Physics = {})); + var Physics = Phaser.Physics; +})(Phaser || (Phaser = {})); diff --git a/Phaser/physics/aabb/ProjAABBHalf.js b/Phaser/physics/aabb/ProjAABBHalf.js index 2f9b5688..fb6cf753 100644 --- a/Phaser/physics/aabb/ProjAABBHalf.js +++ b/Phaser/physics/aabb/ProjAABBHalf.js @@ -1,19 +1,57 @@ -var Shapes; -(function (Shapes) { +var Phaser; +(function (Phaser) { + (function (Physics) { + /// + /** + * Phaser - Physics - Projection + */ + (function (Projection) { + var AABBHalf = (function () { + function AABBHalf() { + } + AABBHalf.Collide = function (x, y, obj, t) { + //calculate the projection vector for the half-edge, and then + //(if collision is occuring) pick the minimum + var sx = t.signx; + var sy = t.signy; - var Point = Shapes.Point = (function () { - function Point(x, y) { - this.x = x; - this.y = y; - } - Point.prototype.getDist = function () { - return Math.sqrt((this.x * this.x) + (this.y * this.y)); - }; - Point.origin = new Point(0, 0); - return Point; - })(); + var ox = (obj.pos.x - (sx * obj.xw)) - t.pos.x; + var oy = (obj.pos.y - (sy * obj.yw)) - t.pos.y; -})(Shapes || (Shapes = {})); + //we perform operations analogous to the 45deg tile, except we're using + //an axis-aligned slope instead of an angled one.. + //if the dotprod of (ox,oy) and (sx,sy) is negative, the corner is in the slope + //and we need toproject it out by the magnitude of the projection of (ox,oy) onto (sx,sy) + var dp = (ox * sx) + (oy * sy); + if (dp < 0) { + //collision; project delta onto slope and use this to displace the object + sx *= -dp; + sy *= -dp; -var p = new Shapes.Point(3, 4); -var dist = p.getDist(); + var lenN = Math.sqrt(sx * sx + sy * sy); + var lenP = Math.sqrt(x * x + y * y); + + if (lenP < lenN) { + //project along axis; note that we're assuming that this tile is horizontal OR vertical + //relative to the AABB's current tile, and not diagonal OR the current tile. + obj.reportCollisionVsWorld(x, y, x / lenP, y / lenP, t); + + return Phaser.Physics.AABB.COL_AXIS; + } else { + //note that we could use -= instead of -dp + obj.reportCollisionVsWorld(sx, sy, t.signx, t.signy, t); + + return Phaser.Physics.AABB.COL_OTHER; + } + } + + return Phaser.Physics.AABB.COL_NONE; + }; + return AABBHalf; + })(); + Projection.AABBHalf = AABBHalf; + })(Physics.Projection || (Physics.Projection = {})); + var Projection = Physics.Projection; + })(Phaser.Physics || (Phaser.Physics = {})); + var Physics = Phaser.Physics; +})(Phaser || (Phaser = {})); diff --git a/Phaser/physics/circle/ProjCircle22Deg.js b/Phaser/physics/circle/ProjCircle22Deg.js index 2f9b5688..0196cfbe 100644 --- a/Phaser/physics/circle/ProjCircle22Deg.js +++ b/Phaser/physics/circle/ProjCircle22Deg.js @@ -1,19 +1,481 @@ -var Shapes; -(function (Shapes) { +var Phaser; +(function (Phaser) { + (function (Physics) { + /// + /** + * Phaser - Physics - Projection + */ + (function (Projection) { + var Circle22Deg = (function () { + function Circle22Deg() { + } + Circle22Deg.CollideS = function (x, y, oH, oV, obj, t) { + //if the object is in a cell pointed at by signy, no collision will ever occur + //otherwise, + // + //if we're colliding diagonally: + // -collide vs. the appropriate vertex + //if obj is in this tile: collide vs slope or vertex + //if obj is horiz neighb in direction of slope: collide vs. slope or vertex + //if obj is horiz neighb against the slope: + // if(distance in y from circle to 90deg corner of tile < 1/2 tileheight, collide vs. face) + // else(collide vs. corner of slope) (vert collision with a non-grid-aligned vert) + //if obj is vert neighb against direction of slope: collide vs. face + var signx = t.signx; + var signy = t.signy; - var Point = Shapes.Point = (function () { - function Point(x, y) { - this.x = x; - this.y = y; - } - Point.prototype.getDist = function () { - return Math.sqrt((this.x * this.x) + (this.y * this.y)); - }; - Point.origin = new Point(0, 0); - return Point; - })(); + if (0 < (signy * oV)) { + //object will never collide vs tile, it can't reach that far + return Phaser.Physics.Circle.COL_NONE; + } else if (oH == 0) { + if (oV == 0) { + //colliding with current tile + //we could only be colliding vs the slope OR a vertex + //look at the vector form the closest vert to the circle to decide + var sx = t.sx; + var sy = t.sy; -})(Shapes || (Shapes = {})); + var r = obj.radius; + var ox = obj.pos.x - (t.pos.x - (signx * t.xw)); + var oy = obj.pos.y - t.pos.y; -var p = new Shapes.Point(3, 4); -var dist = p.getDist(); + //if the component of (ox,oy) parallel to the normal's righthand normal + //has the same sign as the slope of the slope (the sign of the slope's slope is signx*signy) + //then we project by the vertex, otherwise by the normal or axially. + //note that this is simply a VERY tricky/weird method of determining + //if the circle is in side the slope/face's voronio region, or that of the vertex. + var perp = (ox * -sy) + (oy * sx); + + if (0 < (perp * signx * signy)) { + //collide vs. vertex + var len = Math.sqrt(ox * ox + oy * oy); + var pen = r - len; + + if (0 < pen) { + //note: if len=0, then perp=0 and we'll never reach here, so don't worry about div-by-0 + ox /= len; + oy /= len; + + obj.reportCollisionVsWorld(ox * pen, oy * pen, ox, oy, t); + + return Phaser.Physics.Circle.COL_OTHER; + } + } else { + //collide vs. slope or vs axis + ox -= r * sx; + oy -= r * sy; + + //if the dotprod of (ox,oy) and (sx,sy) is negative, the point on the circle is in the slope + //and we need toproject it out by the magnitude of the projection of (ox,oy) onto (sx,sy) + var dp = (ox * sx) + (oy * sy); + + if (dp < 0) { + //collision; project delta onto slope and use this to displace the object + sx *= -dp; + sy *= -dp; + + var lenN = Math.sqrt(sx * sx + sy * sy); + var lenP; + + if (x < y) { + //penetration in x is smaller + lenP = x; + y = 0; + + if ((obj.pos.x - t.pos.x) < 0) { + x *= -1; + } + } else { + //penetration in y is smaller + lenP = y; + x = 0; + + if ((obj.pos.y - t.pos.y) < 0) { + y *= -1; + } + } + + if (lenP < lenN) { + obj.reportCollisionVsWorld(x, y, x / lenP, y / lenP, t); + + return Phaser.Physics.Circle.COL_AXIS; + } else { + obj.reportCollisionVsWorld(sx, sy, t.sx, t.sy, t); + + return Phaser.Physics.Circle.COL_OTHER; + } + } + } + } else { + //colliding vertically; we can assume that (signy*oV) < 0 + //due to the first conditional far above + obj.reportCollisionVsWorld(0, y * oV, 0, oV, t); + + return Phaser.Physics.Circle.COL_AXIS; + } + } else if (oV == 0) { + if ((signx * oH) < 0) { + //colliding with face/edge OR with corner of wedge, depending on our position vertically + //collide vs. vertex + //get diag vertex position + var vx = t.pos.x - (signx * t.xw); + var vy = t.pos.y; + + var dx = obj.pos.x - vx; + var dy = obj.pos.y - vy; + + if ((dy * signy) < 0) { + //colliding vs face + obj.reportCollisionVsWorld(x * oH, 0, oH, 0, t); + + return Phaser.Physics.Circle.COL_AXIS; + } else { + //colliding vs. vertex + var len = Math.sqrt(dx * dx + dy * dy); + var pen = obj.radius - len; + + if (0 < pen) { + if (len == 0) { + //project out by 45deg + dx = oH / Math.SQRT2; + dy = oV / Math.SQRT2; + } else { + dx /= len; + dy /= len; + } + + obj.reportCollisionVsWorld(dx * pen, dy * pen, dx, dy, t); + + return Phaser.Physics.Circle.COL_OTHER; + } + } + } else { + //we could only be colliding vs the slope OR a vertex + //look at the vector form the closest vert to the circle to decide + var sx = t.sx; + var sy = t.sy; + + var ox = obj.pos.x - (t.pos.x + (oH * t.xw)); + var oy = obj.pos.y - (t.pos.y - (signy * t.yw)); + + //if the component of (ox,oy) parallel to the normal's righthand normal + //has the same sign as the slope of the slope (the sign of the slope's slope is signx*signy) + //then we project by the normal, otherwise by the vertex. + //(NOTE: this is the opposite logic of the vertical case; + // for vertical, if the perp prod and the slope's slope agree, it's outside. + // for horizontal, if the perp prod and the slope's slope agree, circle is inside. + // ..but this is only a property of flahs' coord system (i.e the rules might swap + // in righthanded systems)) + //note that this is simply a VERY tricky/weird method of determining + //if the circle is in side the slope/face's voronio region, or that of the vertex. + var perp = (ox * -sy) + (oy * sx); + + if ((perp * signx * signy) < 0) { + //collide vs. vertex + var len = Math.sqrt(ox * ox + oy * oy); + var pen = obj.radius - len; + + if (0 < pen) { + //note: if len=0, then perp=0 and we'll never reach here, so don't worry about div-by-0 + ox /= len; + oy /= len; + + obj.reportCollisionVsWorld(ox * pen, oy * pen, ox, oy, t); + + return Phaser.Physics.Circle.COL_OTHER; + } + } else { + //collide vs. slope + //if the component of (ox,oy) parallel to the normal is less than the circle radius, we're + //penetrating the slope. note that this method of penetration calculation doesn't hold + //in general (i.e it won't work if the circle is in the slope), but works in this case + //because we know the circle is in a neighboring cell + var dp = (ox * sx) + (oy * sy); + var pen = obj.radius - Math.abs(dp); + + if (0 < pen) { + //collision; circle out along normal by penetration amount + obj.reportCollisionVsWorld(sx * pen, sy * pen, sx, sy, t); + + return Phaser.Physics.Circle.COL_OTHER; + } + } + } + } else { + //colliding diagonally; due to the first conditional above, + //obj is vertically offset against slope, and offset in either direction horizontally + //collide vs. vertex + //get diag vertex position + var vx = t.pos.x + (oH * t.xw); + var vy = t.pos.y + (oV * t.yw); + + var dx = obj.pos.x - vx; + var dy = obj.pos.y - vy; + + var len = Math.sqrt(dx * dx + dy * dy); + var pen = obj.radius - len; + + if (0 < pen) { + if (len == 0) { + //project out by 45deg + dx = oH / Math.SQRT2; + dy = oV / Math.SQRT2; + } else { + dx /= len; + dy /= len; + } + + obj.reportCollisionVsWorld(dx * pen, dy * pen, dx, dy, t); + + return Phaser.Physics.Circle.COL_OTHER; + } + } + + return Phaser.Physics.Circle.COL_NONE; + }; + + Circle22Deg.CollideB = function (x, y, oH, oV, obj, t) { + //if we're colliding diagonally: + // -if we're in the cell pointed at by the normal, collide vs slope, else + // collide vs. the appropriate corner/vertex + // + //if obj is in this tile: collide as with aabb + // + //if obj is horiz or vertical neighbor AGAINST the slope: collide with edge + // + //if obj is horiz neighb in direction of slope: collide vs. slope or vertex or edge + // + //if obj is vert neighb in direction of slope: collide vs. slope or vertex + var signx = t.signx; + var signy = t.signy; + var sx; + var sy; + + if (oH == 0) { + if (oV == 0) { + //colliding with current cell + sx = t.sx; + sy = t.sy; + + var r = obj.radius; + var ox = (obj.pos.x - (sx * r)) - (t.pos.x - (signx * t.xw)); + var oy = (obj.pos.y - (sy * r)) - (t.pos.y + (signy * t.yw)); + + //if the dotprod of (ox,oy) and (sx,sy) is negative, the point on the circle is in the slope + //and we need toproject it out by the magnitude of the projection of (ox,oy) onto (sx,sy) + var dp = (ox * sx) + (oy * sy); + + if (dp < 0) { + //collision; project delta onto slope and use this to displace the object + sx *= -dp; + sy *= -dp; + + var lenN = Math.sqrt(sx * sx + sy * sy); + var lenP; + + if (x < y) { + //penetration in x is smaller + lenP = x; + y = 0; + + if ((obj.pos.x - t.pos.x) < 0) { + x *= -1; + } + } else { + //penetration in y is smaller + lenP = y; + x = 0; + + if ((obj.pos.y - t.pos.y) < 0) { + y *= -1; + } + } + + if (lenP < lenN) { + obj.reportCollisionVsWorld(x, y, x / lenP, y / lenP, t); + + return Phaser.Physics.Circle.COL_AXIS; + } else { + obj.reportCollisionVsWorld(sx, sy, t.sx, t.sy, t); + + return Phaser.Physics.Circle.COL_OTHER; + } + } + } else { + if ((signy * oV) < 0) { + //colliding with face/edge + obj.reportCollisionVsWorld(0, y * oV, 0, oV, t); + + return Phaser.Physics.Circle.COL_AXIS; + } else { + //we could only be colliding vs the slope OR a vertex + //look at the vector form the closest vert to the circle to decide + sx = t.sx; + sy = t.sy; + + var ox = obj.pos.x - (t.pos.x - (signx * t.xw)); + var oy = obj.pos.y - (t.pos.y + (signy * t.yw)); + + //if the component of (ox,oy) parallel to the normal's righthand normal + //has the same sign as the slope of the slope (the sign of the slope's slope is signx*signy) + //then we project by the vertex, otherwise by the normal. + //note that this is simply a VERY tricky/weird method of determining + //if the circle is in side the slope/face's voronio region, or that of the vertex. + var perp = (ox * -sy) + (oy * sx); + + if (0 < (perp * signx * signy)) { + //collide vs. vertex + var len = Math.sqrt(ox * ox + oy * oy); + var pen = obj.radius - len; + + if (0 < pen) { + //note: if len=0, then perp=0 and we'll never reach here, so don't worry about div-by-0 + ox /= len; + oy /= len; + + obj.reportCollisionVsWorld(ox * pen, oy * pen, ox, oy, t); + + return Phaser.Physics.Circle.COL_OTHER; + } + } else { + //collide vs. slope + //if the component of (ox,oy) parallel to the normal is less than the circle radius, we're + //penetrating the slope. note that this method of penetration calculation doesn't hold + //in general (i.e it won't work if the circle is in the slope), but works in this case + //because we know the circle is in a neighboring cell + var dp = (ox * sx) + (oy * sy); + var pen = obj.radius - Math.abs(dp); + + if (0 < pen) { + //collision; circle out along normal by penetration amount + obj.reportCollisionVsWorld(sx * pen, sy * pen, sx, sy, t); + + return Phaser.Physics.Circle.COL_OTHER; + } + } + } + } + } else if (oV == 0) { + if ((signx * oH) < 0) { + //colliding with face/edge + obj.reportCollisionVsWorld(x * oH, 0, oH, 0, t); + + return Phaser.Physics.Circle.COL_AXIS; + } else { + //colliding with edge, slope, or vertex + var ox = obj.pos.x - (t.pos.x + (signx * t.xw)); + var oy = obj.pos.y - t.pos.y; + + if ((oy * signy) < 0) { + //we're colliding with the halfface + obj.reportCollisionVsWorld(x * oH, 0, oH, 0, t); + + return Phaser.Physics.Circle.COL_AXIS; + } else { + //colliding with the vertex or slope + sx = t.sx; + sy = t.sy; + + //if the component of (ox,oy) parallel to the normal's righthand normal + //has the same sign as the slope of the slope (the sign of the slope's slope is signx*signy) + //then we project by the slope, otherwise by the vertex. + //note that this is simply a VERY tricky/weird method of determining + //if the circle is in side the slope/face's voronio region, or that of the vertex. + var perp = (ox * -sy) + (oy * sx); + + if ((perp * signx * signy) < 0) { + //collide vs. vertex + var len = Math.sqrt(ox * ox + oy * oy); + var pen = obj.radius - len; + + if (0 < pen) { + //note: if len=0, then perp=0 and we'll never reach here, so don't worry about div-by-0 + ox /= len; + oy /= len; + + obj.reportCollisionVsWorld(ox * pen, oy * pen, ox, oy, t); + + return Phaser.Physics.Circle.COL_OTHER; + } + } else { + //collide vs. slope + //if the component of (ox,oy) parallel to the normal is less than the circle radius, we're + //penetrating the slope. note that this method of penetration calculation doesn't hold + //in general (i.e it won't work if the circle is in the slope), but works in this case + //because we know the circle is in a neighboring cell + var dp = (ox * sx) + (oy * sy); + var pen = obj.radius - Math.abs(dp); + + if (0 < pen) { + //collision; circle out along normal by penetration amount + obj.reportCollisionVsWorld(sx * pen, sy * pen, t.sx, t.sy, t); + + return Phaser.Physics.Circle.COL_OTHER; + } + } + } + } + } else { + if (0 < ((signx * oH) + (signy * oV))) { + //the dotprod of slope normal and cell offset is strictly positive, + //therefore obj is in the diagonal neighb pointed at by the normal. + //collide vs slope + //we should really precalc this at compile time, but for now, fuck it + var slen = Math.sqrt(2 * 2 + 1 * 1); + sx = (signx * 1) / slen; + sy = (signy * 2) / slen; + + var r = obj.radius; + var ox = (obj.pos.x - (sx * r)) - (t.pos.x - (signx * t.xw)); + var oy = (obj.pos.y - (sy * r)) - (t.pos.y + (signy * t.yw)); + + //if the dotprod of (ox,oy) and (sx,sy) is negative, the point on the circle is in the slope + //and we need toproject it out by the magnitude of the projection of (ox,oy) onto (sx,sy) + var dp = (ox * sx) + (oy * sy); + + if (dp < 0) { + //collision; project delta onto slope and use this to displace the object + //(sx,sy)*-dp is the projection vector + obj.reportCollisionVsWorld(-sx * dp, -sy * dp, t.sx, t.sy, t); + + return Phaser.Physics.Circle.COL_OTHER; + } + return Phaser.Physics.Circle.COL_NONE; + } else { + //collide vs the appropriate vertex + var vx = t.pos.x + (oH * t.xw); + var vy = t.pos.y + (oV * t.yw); + + var dx = obj.pos.x - vx; + var dy = obj.pos.y - vy; + + var len = Math.sqrt(dx * dx + dy * dy); + var pen = obj.radius - len; + + if (0 < pen) { + if (len == 0) { + //project out by 45deg + dx = oH / Math.SQRT2; + dy = oV / Math.SQRT2; + } else { + dx /= len; + dy /= len; + } + + obj.reportCollisionVsWorld(dx * pen, dy * pen, dx, dy, t); + + return Phaser.Physics.Circle.COL_OTHER; + } + } + } + + return Phaser.Physics.Circle.COL_NONE; + }; + return Circle22Deg; + })(); + Projection.Circle22Deg = Circle22Deg; + })(Physics.Projection || (Physics.Projection = {})); + var Projection = Physics.Projection; + })(Phaser.Physics || (Phaser.Physics = {})); + var Physics = Phaser.Physics; +})(Phaser || (Phaser = {})); diff --git a/Phaser/physics/circle/ProjCircle67Deg.js b/Phaser/physics/circle/ProjCircle67Deg.js index 2f9b5688..e71a6696 100644 --- a/Phaser/physics/circle/ProjCircle67Deg.js +++ b/Phaser/physics/circle/ProjCircle67Deg.js @@ -1,19 +1,472 @@ -var Shapes; -(function (Shapes) { +var Phaser; +(function (Phaser) { + (function (Physics) { + /// + /** + * Phaser - Physics - Projection + */ + (function (Projection) { + var Circle67Deg = (function () { + function Circle67Deg() { + } + Circle67Deg.CollideS = function (x, y, oH, oV, obj, t) { + //if the object is in a cell pointed at by signx, no collision will ever occur + //otherwise, + // + //if we're colliding diagonally: + // -collide vs. the appropriate vertex + //if obj is in this tile: collide vs slope or vertex or axis + //if obj is vert neighb in direction of slope: collide vs. slope or vertex + //if obj is vert neighb against the slope: + // if(distance in y from circle to 90deg corner of tile < 1/2 tileheight, collide vs. face) + // else(collide vs. corner of slope) (vert collision with a non-grid-aligned vert) + //if obj is horiz neighb against direction of slope: collide vs. face + var signx = t.signx; + var signy = t.signy; + var sx; + var sy; - var Point = Shapes.Point = (function () { - function Point(x, y) { - this.x = x; - this.y = y; - } - Point.prototype.getDist = function () { - return Math.sqrt((this.x * this.x) + (this.y * this.y)); - }; - Point.origin = new Point(0, 0); - return Point; - })(); + if (0 < (signx * oH)) { + //object will never collide vs tile, it can't reach that far + return Phaser.Physics.Circle.COL_NONE; + } else if (oH == 0) { + if (oV == 0) { + //colliding with current tile + //we could only be colliding vs the slope OR a vertex + //look at the vector form the closest vert to the circle to decide + sx = t.sx; + sy = t.sy; -})(Shapes || (Shapes = {})); + var r = obj.radius; + var ox = obj.pos.x - t.pos.x; + var oy = obj.pos.y - (t.pos.y - (signy * t.yw)); -var p = new Shapes.Point(3, 4); -var dist = p.getDist(); + //if the component of (ox,oy) parallel to the normal's righthand normal + //has the same sign as the slope of the slope (the sign of the slope's slope is signx*signy) + //then we project by the normal or axis, otherwise by the corner/vertex + //note that this is simply a VERY tricky/weird method of determining + //if the circle is in side the slope/face's voronoi region, or that of the vertex. + var perp = (ox * -sy) + (oy * sx); + + if ((perp * signx * signy) < 0) { + //collide vs. vertex + var len = Math.sqrt(ox * ox + oy * oy); + var pen = r - len; + + if (0 < pen) { + //note: if len=0, then perp=0 and we'll never reach here, so don't worry about div-by-0 + ox /= len; + oy /= len; + + obj.reportCollisionVsWorld(ox * pen, oy * pen, ox, oy, t); + return Phaser.Physics.Circle.COL_OTHER; + } + } else { + //collide vs. slope or vs axis + ox -= r * sx; + oy -= r * sy; + + //if the dotprod of (ox,oy) and (sx,sy) is negative, the point on the circle is in the slope + //and we need toproject it out by the magnitude of the projection of (ox,oy) onto (sx,sy) + var dp = (ox * sx) + (oy * sy); + var lenP; + + if (dp < 0) { + //collision; project delta onto slope and use this to displace the object + sx *= -dp; + sy *= -dp; + + var lenN = Math.sqrt(sx * sx + sy * sy); + + if (x < y) { + //penetration in x is smaller + lenP = x; + y = 0; + + if ((obj.pos.x - t.pos.x) < 0) { + x *= -1; + } + } else { + //penetration in y is smaller + lenP = y; + x = 0; + + if ((obj.pos.y - t.pos.y) < 0) { + y *= -1; + } + } + + if (lenP < lenN) { + obj.reportCollisionVsWorld(x, y, x / lenP, y / lenP, t); + return Phaser.Physics.Circle.COL_AXIS; + } else { + obj.reportCollisionVsWorld(sx, sy, t.sx, t.sy, t); + return Phaser.Physics.Circle.COL_OTHER; + } + } + } + } else { + if ((signy * oV) < 0) { + //colliding with face/edge OR with corner of wedge, depending on our position vertically + //collide vs. vertex + //get diag vertex position + var vx = t.pos.x; + var vy = t.pos.y - (signy * t.yw); + + var dx = obj.pos.x - vx; + var dy = obj.pos.y - vy; + + if ((dx * signx) < 0) { + //colliding vs face + obj.reportCollisionVsWorld(0, y * oV, 0, oV, t); + + return Phaser.Physics.Circle.COL_AXIS; + } else { + //colliding vs. vertex + var len = Math.sqrt(dx * dx + dy * dy); + var pen = obj.radius - len; + + if (0 < pen) { + if (len == 0) { + //project out by 45deg + dx = oH / Math.SQRT2; + dy = oV / Math.SQRT2; + } else { + dx /= len; + dy /= len; + } + + obj.reportCollisionVsWorld(dx * pen, dy * pen, dx, dy, t); + + return Phaser.Physics.Circle.COL_OTHER; + } + } + } else { + //we could only be colliding vs the slope OR a vertex + //look at the vector form the closest vert to the circle to decide + sx = t.sx; + sy = t.sy; + + var ox = obj.pos.x - (t.pos.x - (signx * t.xw)); + var oy = obj.pos.y - (t.pos.y + (oV * t.yw)); + + //if the component of (ox,oy) parallel to the normal's righthand normal + //has the same sign as the slope of the slope (the sign of the slope's slope is signx*signy) + //then we project by the vertex, otherwise by the normal. + //note that this is simply a VERY tricky/weird method of determining + //if the circle is in side the slope/face's voronio region, or that of the vertex. + var perp = (ox * -sy) + (oy * sx); + + if (0 < (perp * signx * signy)) { + //collide vs. vertex + var len = Math.sqrt(ox * ox + oy * oy); + var pen = obj.radius - len; + + if (0 < pen) { + //note: if len=0, then perp=0 and we'll never reach here, so don't worry about div-by-0 + ox /= len; + oy /= len; + + obj.reportCollisionVsWorld(ox * pen, oy * pen, ox, oy, t); + + return Phaser.Physics.Circle.COL_OTHER; + } + } else { + //collide vs. slope + //if the component of (ox,oy) parallel to the normal is less than the circle radius, we're + //penetrating the slope. note that this method of penetration calculation doesn't hold + //in general (i.e it won't work if the circle is in the slope), but works in this case + //because we know the circle is in a neighboring cell + var dp = (ox * sx) + (oy * sy); + var pen = obj.radius - Math.abs(dp); + + if (0 < pen) { + //collision; circle out along normal by penetration amount + obj.reportCollisionVsWorld(sx * pen, sy * pen, t.sx, t.sy, t); + + return Phaser.Physics.Circle.COL_OTHER; + } + } + } + } + } else if (oV == 0) { + //colliding horizontally; we can assume that (signy*oV) < 0 + //due to the first conditional far above + obj.reportCollisionVsWorld(x * oH, 0, oH, 0, t); + + return Phaser.Physics.Circle.COL_AXIS; + } else { + //colliding diagonally; due to the first conditional above, + //obj is vertically offset against slope, and offset in either direction horizontally + //collide vs. vertex + //get diag vertex position + var vx = t.pos.x + (oH * t.xw); + var vy = t.pos.y + (oV * t.yw); + + var dx = obj.pos.x - vx; + var dy = obj.pos.y - vy; + + var len = Math.sqrt(dx * dx + dy * dy); + var pen = obj.radius - len; + + if (0 < pen) { + if (len == 0) { + //project out by 45deg + dx = oH / Math.SQRT2; + dy = oV / Math.SQRT2; + } else { + dx /= len; + dy /= len; + } + + obj.reportCollisionVsWorld(dx * pen, dy * pen, dx, dy, t); + + return Phaser.Physics.Circle.COL_OTHER; + } + } + + return Phaser.Physics.Circle.COL_NONE; + }; + + Circle67Deg.CollideB = function (x, y, oH, oV, obj, t) { + //if we're colliding diagonally: + // -if we're in the cell pointed at by the normal, collide vs slope, else + // collide vs. the appropriate corner/vertex + // + //if obj is in this tile: collide as with aabb + // + //if obj is horiz or vertical neighbor AGAINST the slope: collide with edge + // + //if obj is vert neighb in direction of slope: collide vs. slope or vertex or halfedge + // + //if obj is horiz neighb in direction of slope: collide vs. slope or vertex + var signx = t.signx; + var signy = t.signy; + var sx; + var sy; + + if (oH == 0) { + if (oV == 0) { + //colliding with current cell + sx = t.sx; + sy = t.sy; + + var r = obj.radius; + var ox = (obj.pos.x - (sx * r)) - (t.pos.x + (signx * t.xw)); + var oy = (obj.pos.y - (sy * r)) - (t.pos.y - (signy * t.yw)); + + //if the dotprod of (ox,oy) and (sx,sy) is negative, the point on the circle is in the slope + //and we need toproject it out by the magnitude of the projection of (ox,oy) onto (sx,sy) + var dp = (ox * sx) + (oy * sy); + var lenP; + + if (dp < 0) { + //collision; project delta onto slope and use this to displace the object + sx *= -dp; + sy *= -dp; + + var lenN = Math.sqrt(sx * sx + sy * sy); + + if (x < y) { + //penetration in x is smaller + lenP = x; + y = 0; + + if ((obj.pos.x - t.pos.x) < 0) { + x *= -1; + } + } else { + //penetration in y is smaller + lenP = y; + x = 0; + + if ((obj.pos.y - t.pos.y) < 0) { + y *= -1; + } + } + + if (lenP < lenN) { + obj.reportCollisionVsWorld(x, y, x / lenP, y / lenP, t); + + return Phaser.Physics.Circle.COL_AXIS; + } else { + obj.reportCollisionVsWorld(sx, sy, t.sx, t.sy, t); + + return Phaser.Physics.Circle.COL_OTHER; + } + } + } else { + if ((signy * oV) < 0) { + //colliding with face/edge + obj.reportCollisionVsWorld(0, y * oV, 0, oV, t); + + return Phaser.Physics.Circle.COL_AXIS; + } else { + //colliding with edge, slope, or vertex + var ox = obj.pos.x - t.pos.x; + var oy = obj.pos.y - (t.pos.y + (signy * t.yw)); + + if ((ox * signx) < 0) { + //we're colliding with the halfface + obj.reportCollisionVsWorld(0, y * oV, 0, oV, t); + + return Phaser.Physics.Circle.COL_AXIS; + } else { + //colliding with the vertex or slope + sx = t.sx; + sy = t.sy; + + //if the component of (ox,oy) parallel to the normal's righthand normal + //has the same sign as the slope of the slope (the sign of the slope's slope is signx*signy) + //then we project by the vertex, otherwise by the slope. + //note that this is simply a VERY tricky/weird method of determining + //if the circle is in side the slope/face's voronio region, or that of the vertex. + var perp = (ox * -sy) + (oy * sx); + + if (0 < (perp * signx * signy)) { + //collide vs. vertex + var len = Math.sqrt(ox * ox + oy * oy); + var pen = obj.radius - len; + + if (0 < pen) { + //note: if len=0, then perp=0 and we'll never reach here, so don't worry about div-by-0 + ox /= len; + oy /= len; + + obj.reportCollisionVsWorld(ox * pen, oy * pen, ox, oy, t); + + return Phaser.Physics.Circle.COL_OTHER; + } + } else { + //collide vs. slope + //if the component of (ox,oy) parallel to the normal is less than the circle radius, we're + //penetrating the slope. note that this method of penetration calculation doesn't hold + //in general (i.e it won't work if the circle is in the slope), but works in this case + //because we know the circle is in a neighboring cell + var dp = (ox * sx) + (oy * sy); + var pen = obj.radius - Math.abs(dp); + + if (0 < pen) { + //collision; circle out along normal by penetration amount + obj.reportCollisionVsWorld(sx * pen, sy * pen, sx, sy, t); + + return Phaser.Physics.Circle.COL_OTHER; + } + } + } + } + } + } else if (oV == 0) { + if ((signx * oH) < 0) { + //colliding with face/edge + obj.reportCollisionVsWorld(x * oH, 0, oH, 0, t); + + return Phaser.Physics.Circle.COL_AXIS; + } else { + //we could only be colliding vs the slope OR a vertex + //look at the vector form the closest vert to the circle to decide + var slen = Math.sqrt(2 * 2 + 1 * 1); + var sx = (signx * 2) / slen; + var sy = (signy * 1) / slen; + + var ox = obj.pos.x - (t.pos.x + (signx * t.xw)); + var oy = obj.pos.y - (t.pos.y - (signy * t.yw)); + + //if the component of (ox,oy) parallel to the normal's righthand normal + //has the same sign as the slope of the slope (the sign of the slope's slope is signx*signy) + //then we project by the slope, otherwise by the vertex. + //note that this is simply a VERY tricky/weird method of determining + //if the circle is in side the slope/face's voronio region, or that of the vertex. + var perp = (ox * -sy) + (oy * sx); + + if ((perp * signx * signy) < 0) { + //collide vs. vertex + var len = Math.sqrt(ox * ox + oy * oy); + var pen = obj.radius - len; + if (0 < pen) { + //note: if len=0, then perp=0 and we'll never reach here, so don't worry about div-by-0 + ox /= len; + oy /= len; + + obj.reportCollisionVsWorld(ox * pen, oy * pen, ox, oy, t); + + return Phaser.Physics.Circle.COL_OTHER; + } + } else { + //collide vs. slope + //if the component of (ox,oy) parallel to the normal is less than the circle radius, we're + //penetrating the slope. note that this method of penetration calculation doesn't hold + //in general (i.e it won't work if the circle is in the slope), but works in this case + //because we know the circle is in a neighboring cell + var dp = (ox * sx) + (oy * sy); + var pen = obj.radius - Math.abs(dp); + if (0 < pen) { + //collision; circle out along normal by penetration amount + obj.reportCollisionVsWorld(sx * pen, sy * pen, t.sx, t.sy, t); + + return Phaser.Physics.Circle.COL_OTHER; + } + } + } + } else { + if (0 < ((signx * oH) + (signy * oV))) { + //the dotprod of slope normal and cell offset is strictly positive, + //therefore obj is in the diagonal neighb pointed at by the normal. + //collide vs slope + sx = t.sx; + sy = t.sy; + + var r = obj.radius; + var ox = (obj.pos.x - (sx * r)) - (t.pos.x + (signx * t.xw)); + var oy = (obj.pos.y - (sy * r)) - (t.pos.y - (signy * t.yw)); + + //if the dotprod of (ox,oy) and (sx,sy) is negative, the point on the circle is in the slope + //and we need toproject it out by the magnitude of the projection of (ox,oy) onto (sx,sy) + var dp = (ox * sx) + (oy * sy); + + if (dp < 0) { + //collision; project delta onto slope and use this to displace the object + //(sx,sy)*-dp is the projection vector + obj.reportCollisionVsWorld(-sx * dp, -sy * dp, t.sx, t.sy, t); + + return Phaser.Physics.Circle.COL_OTHER; + } + return Phaser.Physics.Circle.COL_NONE; + } else { + //collide vs the appropriate vertex + var vx = t.pos.x + (oH * t.xw); + var vy = t.pos.y + (oV * t.yw); + + var dx = obj.pos.x - vx; + var dy = obj.pos.y - vy; + + var len = Math.sqrt(dx * dx + dy * dy); + var pen = obj.radius - len; + + if (0 < pen) { + if (len == 0) { + //project out by 45deg + dx = oH / Math.SQRT2; + dy = oV / Math.SQRT2; + } else { + dx /= len; + dy /= len; + } + + obj.reportCollisionVsWorld(dx * pen, dy * pen, dx, dy, t); + + return Phaser.Physics.Circle.COL_OTHER; + } + } + } + + return Phaser.Physics.Circle.COL_NONE; + }; + return Circle67Deg; + })(); + Projection.Circle67Deg = Circle67Deg; + })(Physics.Projection || (Physics.Projection = {})); + var Projection = Physics.Projection; + })(Phaser.Physics || (Phaser.Physics = {})); + var Physics = Phaser.Physics; +})(Phaser || (Phaser = {})); diff --git a/Phaser/physics/circle/ProjCircleHalf.js b/Phaser/physics/circle/ProjCircleHalf.js index 2f9b5688..bcc49a2e 100644 --- a/Phaser/physics/circle/ProjCircleHalf.js +++ b/Phaser/physics/circle/ProjCircleHalf.js @@ -1,19 +1,183 @@ -var Shapes; -(function (Shapes) { +var Phaser; +(function (Phaser) { + (function (Physics) { + /// + /** + * Phaser - Physics - Projection + */ + (function (Projection) { + var CircleHalf = (function () { + function CircleHalf() { + } + CircleHalf.Collide = function (x, y, oH, oV, obj, t) { + //if obj is in a neighbor pointed at by the halfedge normal, + //we'll never collide (i.e if the normal is (0,1) and the obj is in the DL.D, or R neighbors) + // + //if obj is in a neigbor perpendicular to the halfedge normal, it might + //collide with the halfedge-vertex, or with the halfedge side. + // + //if obj is in a neigb pointing opposite the halfedge normal, obj collides with edge + // + //if obj is in a diagonal (pointing away from the normal), obj collides vs vertex + // + //if obj is in the halfedge cell, it collides as with aabb + var signx = t.signx; + var signy = t.signy; - var Point = Shapes.Point = (function () { - function Point(x, y) { - this.x = x; - this.y = y; - } - Point.prototype.getDist = function () { - return Math.sqrt((this.x * this.x) + (this.y * this.y)); - }; - Point.origin = new Point(0, 0); - return Point; - })(); + var celldp = (oH * signx + oV * signy); + if (0 < celldp) { + //obj is in "far" (pointed-at-by-normal) neighbor of halffull tile, and will never hit + return Phaser.Physics.Circle.COL_NONE; + } else if (oH == 0) { + if (oV == 0) { + //colliding with current tile + var r = obj.radius; + var ox = (obj.pos.x - (signx * r)) - t.pos.x; + var oy = (obj.pos.y - (signy * r)) - t.pos.y; -})(Shapes || (Shapes = {})); + //we perform operations analogous to the 45deg tile, except we're using + //an axis-aligned slope instead of an angled one.. + var sx = signx; + var sy = signy; -var p = new Shapes.Point(3, 4); -var dist = p.getDist(); + //if the dotprod of (ox,oy) and (sx,sy) is negative, the corner is in the slope + //and we need toproject it out by the magnitude of the projection of (ox,oy) onto (sx,sy) + var dp = (ox * sx) + (oy * sy); + + if (dp < 0) { + //collision; project delta onto slope and use this to displace the object + sx *= -dp; + sy *= -dp; + + var lenN = Math.sqrt(sx * sx + sy * sy); + var lenP = Math.sqrt(x * x + y * y); + + if (lenP < lenN) { + obj.reportCollisionVsWorld(x, y, x / lenP, y / lenP, t); + + return Phaser.Physics.Circle.COL_AXIS; + } else { + obj.reportCollisionVsWorld(sx, sy, t.signx, t.signy); + + return Phaser.Physics.Circle.COL_OTHER; + } + return true; + } + } else { + if (celldp == 0) { + var r = obj.radius; + var dx = obj.pos.x - t.pos.x; + + if ((dx * signx) < 0) { + //collision with halfedge side + obj.reportCollisionVsWorld(0, y * oV, 0, oV, t); + + return Phaser.Physics.Circle.COL_AXIS; + } else { + //collision with halfedge vertex + var dy = obj.pos.y - (t.pos.y + oV * t.yw); + + var len = Math.sqrt(dx * dx + dy * dy); + var pen = obj.radius - len; + + if (0 < pen) { + if (len == 0) { + //project out by 45deg + dx = signx / Math.SQRT2; + dy = oV / Math.SQRT2; + } else { + dx /= len; + dy /= len; + } + + obj.reportCollisionVsWorld(dx * pen, dy * pen, dx, dy, t); + + return Phaser.Physics.Circle.COL_OTHER; + } + } + } else { + //due to the first conditional (celldp >0), we know we're in the cell "opposite" the normal, and so + //we can only collide with the cell edge + //collision with vertical neighbor + obj.reportCollisionVsWorld(0, y * oV, 0, oV, t); + + return Phaser.Physics.Circle.COL_AXIS; + } + } + } else if (oV == 0) { + if (celldp == 0) { + var r = obj.radius; + var dy = obj.pos.y - t.pos.y; + + if ((dy * signy) < 0) { + //collision with halfedge side + obj.reportCollisionVsWorld(x * oH, 0, oH, 0, t); + + return Phaser.Physics.Circle.COL_AXIS; + } else { + //collision with halfedge vertex + var dx = obj.pos.x - (t.pos.x + oH * t.xw); + + var len = Math.sqrt(dx * dx + dy * dy); + var pen = obj.radius - len; + if (0 < pen) { + if (len == 0) { + //project out by 45deg + dx = signx / Math.SQRT2; + dy = oV / Math.SQRT2; + } else { + dx /= len; + dy /= len; + } + + obj.reportCollisionVsWorld(dx * pen, dy * pen, dx, dy, t); + + return Phaser.Physics.Circle.COL_OTHER; + } + } + } else { + //due to the first conditional (celldp >0), we know w're in the cell "opposite" the normal, and so + //we can only collide with the cell edge + obj.reportCollisionVsWorld(x * oH, 0, oH, 0, t); + + return Phaser.Physics.Circle.COL_AXIS; + } + } else { + //colliding diagonally; we know, due to the initial (celldp >0) test which has failed + //if we've reached this point, that we're in a diagonal neighbor on the non-normal side, so + //we could only be colliding with the cell vertex, if at all. + //get diag vertex position + var vx = t.pos.x + (oH * t.xw); + var vy = t.pos.y + (oV * t.yw); + + var dx = obj.pos.x - vx; + var dy = obj.pos.y - vy; + + var len = Math.sqrt(dx * dx + dy * dy); + var pen = obj.radius - len; + if (0 < pen) { + if (len == 0) { + //project out by 45deg + dx = oH / Math.SQRT2; + dy = oV / Math.SQRT2; + } else { + dx /= len; + dy /= len; + } + + obj.reportCollisionVsWorld(dx * pen, dy * pen, dx, dy, t); + + return Phaser.Physics.Circle.COL_OTHER; + } + } + + return Phaser.Physics.Circle.COL_NONE; + }; + return CircleHalf; + })(); + Projection.CircleHalf = CircleHalf; + })(Physics.Projection || (Physics.Projection = {})); + var Projection = Physics.Projection; + })(Phaser.Physics || (Phaser.Physics = {})); + var Physics = Phaser.Physics; +})(Phaser || (Phaser = {})); diff --git a/Tests/Tests.csproj b/Tests/Tests.csproj index 5d8941e0..b540565d 100644 --- a/Tests/Tests.csproj +++ b/Tests/Tests.csproj @@ -264,7 +264,6 @@ sprite bounds.ts - ballscroller.ts diff --git a/Tests/phaser-debug.js b/Tests/phaser-debug.js index 324fba4b..f7d2d413 100644 --- a/Tests/phaser-debug.js +++ b/Tests/phaser-debug.js @@ -19442,7 +19442,7 @@ var Phaser; fy = ty * f; //b = 1 + BOUNCE;//this bounce constant should be elsewhere, i.e inside the object/tile/etc.. - b = 1 + 0.9; + b = 1 + 0.3; bx = (nx * b); by = (ny * b); diff --git a/Tests/physics/circle 1.js b/Tests/physics/circle 1.js index ef545478..42932820 100644 --- a/Tests/physics/circle 1.js +++ b/Tests/physics/circle 1.js @@ -4,25 +4,48 @@ function preload() { game.load.image('ball', 'assets/sprites/shinyball.png'); - game.load.image('card', 'assets/sprites/mana_card.png'); + game.load.image('tommy', 'assets/tommy.png'); + game.load.image('alice', 'assets/alice.png'); + game.load.image('mummy', 'assets/mummy.png'); } var cells; - var b; + var b1; + var b2; + var b3; + var b4; + var b5; + var b6; + var b7; + var b8; + var b9; + var b10; var c; var t; var ball; - var card; + var carrot1; + var carrot2; + var carrot3; + var carrot4; + var carrot5; + var carrot6; + var carrot7; + var carrot8; + var carrot9; + var carrot10; function create() { - this.ball = game.add.sprite(0, 0, 'ball'); + //this.ball = game.add.sprite(0, 0, 'ball'); + var f = [null, 'tommy', 'alice', 'mummy', 'tommy', 'alice', 'mummy', 'tommy', 'alice', 'mummy', 'tommy', 'alice', 'mummy', 'tommy', 'alice', 'mummy', 'tommy', 'alice', 'mummy']; - this.card = game.add.sprite(0, 0, 'card'); - this.card.rotation = 30; + for (var i = 1; i <= 10; i++) { + this['carrot' + i] = game.add.sprite(0, 0, f[i]); - this.c = game.add.circle(200, 200, 16); - this.b = game.add.aabb(400, 200, 74, 128); + //this['carrot' + i].scale.setTo(0.5, 0.5); + this['b' + i] = game.add.aabb(game.stage.randomX, 200, 50, 50); + } + //this.c = game.add.circle(200, 200, 16); // pos is center, not upper-left this.cells = []; @@ -31,8 +54,10 @@ for (var i = 0; i < 10; i++) { if (i % 2 == 0) { tid = Phaser.Physics.TileMapCell.TID_CONCAVEpn; + //tid = Phaser.Physics.TileMapCell.TID_22DEGnnS; } else { tid = Phaser.Physics.TileMapCell.TID_CONCAVEnn; + //tid = Phaser.Physics.TileMapCell.TID_22DEGpnS; } this.cells.push(game.add.cell(100 + (i * 100), 400, 50, 50, tid)); @@ -57,32 +82,29 @@ fy += 0.2; } - // update circle - this.c.pos.x = this.c.oldpos.x + Math.min(20, Math.max(-20, this.c.pos.x - this.c.oldpos.x + fx)); - this.c.pos.y = this.c.oldpos.y + Math.min(20, Math.max(-20, this.c.pos.y - this.c.oldpos.y + fy)); - this.c.IntegrateVerlet(); - - // update box - this.b.pos.x = this.b.oldpos.x + Math.min(40, Math.max(-40, this.b.pos.x - this.b.oldpos.x + fx)); - this.b.pos.y = this.b.oldpos.y + Math.min(40, Math.max(-40, this.b.pos.y - this.b.oldpos.y + fy)); - this.b.IntegrateVerlet(); - - for (var i = 0; i < this.cells.length; i++) { - this.c.CollideCircleVsTile(this.cells[i]); - this.b.CollideAABBVsTile(this.cells[i]); + for (var i = 1; i <= 10; i++) { + this['b' + i].pos.x = this['b' + i].oldpos.x + Math.min(40, Math.max(-40, this['b' + i].pos.x - this['b' + i].oldpos.x + fx)); + this['b' + i].pos.y = this['b' + i].oldpos.y + Math.min(40, Math.max(-40, this['b' + i].pos.y - this['b' + i].oldpos.y + fy)); + this['b' + i].integrateVerlet(); } - this.c.CollideCircleVsWorldBounds(); - this.b.CollideAABBVsWorldBounds(); + for (var i = 0; i < this.cells.length; i++) { + for (var ib = 1; ib <= 10; ib++) { + this['b' + ib].collideAABBVsTile(this.cells[i]); + } + } - this.ball.transform.centerOn(this.c.pos.x, this.c.pos.y); - this.card.transform.centerOn(this.b.pos.x, this.b.pos.y); + for (var i = 1; i <= 10; i++) { + this['b' + i].collideAABBVsWorldBounds(); + } + + for (var i = 1; i <= 10; i++) { + this['carrot' + i].transform.centerOn(this['b' + i].pos.x, this['b' + i].pos.y); + } + //this.ball.transform.centerOn(this.c.pos.x, this.c.pos.y); } function render() { - this.c.render(game.stage.context); - this.b.render(game.stage.context); - for (var i = 0; i < this.cells.length; i++) { this.cells[i].render(game.stage.context); } diff --git a/Tests/physics/circle 1.ts b/Tests/physics/circle 1.ts index af073ad2..f772eb1b 100644 --- a/Tests/physics/circle 1.ts +++ b/Tests/physics/circle 1.ts @@ -7,26 +7,51 @@ function preload() { game.load.image('ball', 'assets/sprites/shinyball.png'); - game.load.image('card', 'assets/sprites/mana_card.png'); + game.load.image('tommy', 'assets/tommy.png'); + game.load.image('alice', 'assets/alice.png'); + game.load.image('mummy', 'assets/mummy.png'); } var cells; - var b: Phaser.Physics.AABB; + var b1: Phaser.Physics.AABB; + var b2: Phaser.Physics.AABB; + var b3: Phaser.Physics.AABB; + var b4: Phaser.Physics.AABB; + var b5: Phaser.Physics.AABB; + var b6: Phaser.Physics.AABB; + var b7: Phaser.Physics.AABB; + var b8: Phaser.Physics.AABB; + var b9: Phaser.Physics.AABB; + var b10: Phaser.Physics.AABB; var c: Phaser.Physics.Circle; var t: Phaser.Physics.TileMapCell; var ball: Phaser.Sprite; - var card: Phaser.Sprite; + var carrot1: Phaser.Sprite; + var carrot2: Phaser.Sprite; + var carrot3: Phaser.Sprite; + var carrot4: Phaser.Sprite; + var carrot5: Phaser.Sprite; + var carrot6: Phaser.Sprite; + var carrot7: Phaser.Sprite; + var carrot8: Phaser.Sprite; + var carrot9: Phaser.Sprite; + var carrot10: Phaser.Sprite; function create() { - this.ball = game.add.sprite(0, 0, 'ball'); + //this.ball = game.add.sprite(0, 0, 'ball'); - this.card = game.add.sprite(0, 0, 'card'); - this.card.rotation = 30; + var f = [null, 'tommy', 'alice', 'mummy', 'tommy', 'alice', 'mummy', 'tommy', 'alice', 'mummy', 'tommy', 'alice', 'mummy', 'tommy', 'alice', 'mummy', 'tommy', 'alice', 'mummy']; - this.c = game.add.circle(200, 200, 16); - this.b = game.add.aabb(400, 200, 74, 128); + for (var i = 1; i <= 10; i++) + { + this['carrot' + i] = game.add.sprite(0, 0, f[i]); + //this['carrot' + i].scale.setTo(0.5, 0.5); + this['b' + i] = game.add.aabb(game.stage.randomX, 200, 50, 50); + } + + //this.c = game.add.circle(200, 200, 16); // pos is center, not upper-left this.cells = []; @@ -38,10 +63,12 @@ if (i % 2 == 0) { tid = Phaser.Physics.TileMapCell.TID_CONCAVEpn; + //tid = Phaser.Physics.TileMapCell.TID_22DEGnnS; } else { tid = Phaser.Physics.TileMapCell.TID_CONCAVEnn; + //tid = Phaser.Physics.TileMapCell.TID_22DEGpnS; } this.cells.push(game.add.cell(100 + (i * 100), 400, 50, 50, tid)); @@ -75,33 +102,46 @@ } // update circle - this.c.pos.x = this.c.oldpos.x + Math.min(20, Math.max(-20, this.c.pos.x - this.c.oldpos.x + fx)); - this.c.pos.y = this.c.oldpos.y + Math.min(20, Math.max(-20, this.c.pos.y - this.c.oldpos.y + fy)); - this.c.IntegrateVerlet(); + //this.c.pos.x = this.c.oldpos.x + Math.min(20, Math.max(-20, this.c.pos.x - this.c.oldpos.x + fx)); + //this.c.pos.y = this.c.oldpos.y + Math.min(20, Math.max(-20, this.c.pos.y - this.c.oldpos.y + fy)); + //this.c.integrateVerlet(); // update box - this.b.pos.x = this.b.oldpos.x + Math.min(40, Math.max(-40, this.b.pos.x - this.b.oldpos.x + fx)); - this.b.pos.y = this.b.oldpos.y + Math.min(40, Math.max(-40, this.b.pos.y - this.b.oldpos.y + fy)); - this.b.IntegrateVerlet(); + for (var i = 1; i <= 10; i++) + { + this['b' + i].pos.x = this['b' + i].oldpos.x + Math.min(40, Math.max(-40, this['b' + i].pos.x - this['b' + i].oldpos.x + fx)); + this['b' + i].pos.y = this['b' + i].oldpos.y + Math.min(40, Math.max(-40, this['b' + i].pos.y - this['b' + i].oldpos.y + fy)); + this['b' + i].integrateVerlet(); + } for (var i = 0; i < this.cells.length; i++) { - this.c.CollideCircleVsTile(this.cells[i]); - this.b.CollideAABBVsTile(this.cells[i]); + //this.c.collideCircleVsTile(this.cells[i]); + for (var ib = 1; ib <= 10; ib++) + { + this['b' + ib].collideAABBVsTile(this.cells[i]); + } } - this.c.CollideCircleVsWorldBounds(); - this.b.CollideAABBVsWorldBounds(); + for (var i = 1; i <= 10; i++) + { + this['b' + i].collideAABBVsWorldBounds(); + } - this.ball.transform.centerOn(this.c.pos.x, this.c.pos.y); - this.card.transform.centerOn(this.b.pos.x, this.b.pos.y); + //this.c.collideCircleVsWorldBounds(); + for (var i = 1; i <= 10; i++) + { + this['carrot' + i].transform.centerOn(this['b' + i].pos.x, this['b' + i].pos.y); + } + + //this.ball.transform.centerOn(this.c.pos.x, this.c.pos.y); } function render() { - this.c.render(game.stage.context); - this.b.render(game.stage.context); + //this.c.render(game.stage.context); + //this.b.render(game.stage.context); for (var i = 0; i < this.cells.length; i++) { diff --git a/build/phaser-debug.js b/build/phaser-debug.js index 324fba4b..f7d2d413 100644 --- a/build/phaser-debug.js +++ b/build/phaser-debug.js @@ -19442,7 +19442,7 @@ var Phaser; fy = ty * f; //b = 1 + BOUNCE;//this bounce constant should be elsewhere, i.e inside the object/tile/etc.. - b = 1 + 0.9; + b = 1 + 0.3; bx = (nx * b); by = (ny * b);