mirror of
https://github.com/photonstorm/phaser
synced 2024-11-23 21:24:09 +00:00
2091 lines
68 KiB
TypeScript
2091 lines
68 KiB
TypeScript
/// <reference path="../../Phaser/Game.ts" />
|
|
|
|
class NPhysics {
|
|
|
|
grav: number = 0.2;
|
|
drag: number = 1;
|
|
bounce: number = 0.3;
|
|
friction: number = 0.05;
|
|
|
|
min_f: number = 0;
|
|
max_f: number = 1;
|
|
|
|
min_b: number = 0;
|
|
max_b: number = 1;
|
|
|
|
min_g: number = 0;
|
|
max_g = 1;
|
|
|
|
xmin: number = 0;
|
|
xmax: number = 800;
|
|
ymin: number = 0;
|
|
ymax: number = 600;
|
|
|
|
objrad: number = 24;
|
|
tilerad: number = 24*2;
|
|
objspeed: number = 0.2;
|
|
maxspeed: number = 20;
|
|
|
|
public update() {
|
|
// demoObj.Verlet();
|
|
// demoObj.CollideVsWorldBounds();
|
|
}
|
|
|
|
}
|
|
|
|
class AABB {
|
|
|
|
constructor(x: number, y: number, xw, yw) {
|
|
|
|
this.pos = new Phaser.Vec2(x, y);
|
|
this.oldpos = Phaser.Vec2Utils.clone(this.pos);
|
|
this.xw = Math.abs(xw);
|
|
this.yw = Math.abs(yw);
|
|
this.aabbTileProjections = {};//hash object to hold tile-specific collision functions
|
|
this.aabbTileProjections[TileMapCell.CTYPE_FULL] = this.ProjAABB_Full;
|
|
this.aabbTileProjections[TileMapCell.CTYPE_CONCAVE] = this.ProjAABB_Concave;
|
|
this.aabbTileProjections[TileMapCell.CTYPE_CONVEX] = this.ProjAABB_Convex;
|
|
|
|
}
|
|
|
|
type:number = 0;
|
|
pos: Phaser.Vec2;
|
|
oldpos: Phaser.Vec2;
|
|
xw: number;
|
|
yw: number;
|
|
aabbTileProjections;
|
|
public oH: number;
|
|
public oV: number;
|
|
static COL_NONE = 0;
|
|
static COL_AXIS = 1;
|
|
static COL_OTHER = 2;
|
|
|
|
public IntegrateVerlet() {
|
|
|
|
//var d = DRAG;
|
|
//var g = GRAV;
|
|
var d = 1;
|
|
var g = 0.2;
|
|
|
|
var p = this.pos;
|
|
var o = this.oldpos;
|
|
var px, py;
|
|
|
|
var ox = o.x; //we can't swap buffers since mcs/sticks point directly to vector2s..
|
|
var oy = o.y;
|
|
o.x = px = p.x; //get vector values
|
|
o.y = py = p.y; //p = position
|
|
//o = oldposition
|
|
|
|
//integrate
|
|
p.x += (d * px) - (d * ox);
|
|
p.y += (d * py) - (d * oy) + g;
|
|
|
|
}
|
|
|
|
public ReportCollisionVsWorld(px, py, dx, dy, obj: TileMapCell) {
|
|
|
|
var p = this.pos;
|
|
var o = this.oldpos;
|
|
|
|
//calc velocity
|
|
var vx = p.x - o.x;
|
|
var vy = p.y - o.y;
|
|
|
|
//find component of velocity parallel to collision normal
|
|
var dp = (vx * dx + vy * dy);
|
|
var nx = dp * dx;//project velocity onto collision normal
|
|
|
|
var ny = dp * dy;//nx,ny is normal velocity
|
|
|
|
var tx = vx - nx;//px,py is tangent velocity
|
|
var ty = vy - ny;
|
|
|
|
//we only want to apply collision response forces if the object is travelling into, and not out of, the collision
|
|
var b, bx, by, f, fx, fy;
|
|
|
|
if (dp < 0)
|
|
{
|
|
//f = FRICTION;
|
|
f = 0.05;
|
|
fx = tx * f;
|
|
fy = ty * f;
|
|
|
|
//b = 1 + BOUNCE;//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);
|
|
|
|
}
|
|
else
|
|
{
|
|
//moving out of collision, do not apply forces
|
|
bx = by = fx = fy = 0;
|
|
}
|
|
|
|
p.x += px;//project object out of collision
|
|
p.y += py;
|
|
|
|
o.x += px + bx + fx;//apply bounce+friction impulses which alter velocity
|
|
o.y += py + by + fy;
|
|
|
|
}
|
|
|
|
|
|
public CollideAABBVsTile(tile)
|
|
{
|
|
var pos = this.pos;
|
|
var c = tile;
|
|
|
|
var tx = c.pos.x;
|
|
var ty = c.pos.y;
|
|
var txw = c.xw;
|
|
var tyw = c.yw;
|
|
|
|
var dx = pos.x - tx;//tile->obj delta
|
|
var px = (txw + this.xw) - Math.abs(dx);//penetration depth in x
|
|
|
|
if (0 < px)
|
|
{
|
|
var dy = pos.y - ty;//tile->obj delta
|
|
var py = (tyw + this.yw) - Math.abs(dy);//pen depth in y
|
|
|
|
if (0 < py)
|
|
{
|
|
//object may be colliding with tile; call tile-specific collision function
|
|
|
|
//calculate projection vectors
|
|
if (px < py)
|
|
{
|
|
//project in x
|
|
if (dx < 0)
|
|
{
|
|
//project to the left
|
|
px *= -1;
|
|
py = 0;
|
|
}
|
|
else
|
|
{
|
|
//proj to right
|
|
py = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//project in y
|
|
if (dy < 0)
|
|
{
|
|
//project up
|
|
px = 0;
|
|
py *= -1;
|
|
}
|
|
else
|
|
{
|
|
//project down
|
|
px = 0;
|
|
}
|
|
}
|
|
|
|
this.ResolveBoxTile(px, py, this, c);
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
public CollideAABBVsWorldBounds() {
|
|
var p = this.pos;
|
|
var xw = this.xw;
|
|
var yw = this.yw;
|
|
var XMIN = 0;
|
|
var XMAX = 800;
|
|
var YMIN = 0;
|
|
var YMAX = 600;
|
|
|
|
//collide vs. x-bounds
|
|
//test XMIN
|
|
var dx = XMIN - (p.x - xw);
|
|
if (0 < dx)
|
|
{
|
|
//object is colliding with XMIN
|
|
this.ReportCollisionVsWorld(dx, 0, 1, 0, null);
|
|
}
|
|
else
|
|
{
|
|
//test XMAX
|
|
dx = (p.x + xw) - XMAX;
|
|
if (0 < dx)
|
|
{
|
|
//object is colliding with XMAX
|
|
this.ReportCollisionVsWorld(-dx, 0, -1, 0, null);
|
|
}
|
|
}
|
|
|
|
//collide vs. y-bounds
|
|
//test YMIN
|
|
var dy = YMIN - (p.y - yw);
|
|
if (0 < dy)
|
|
{
|
|
//object is colliding with YMIN
|
|
this.ReportCollisionVsWorld(0, dy, 0, 1, null);
|
|
}
|
|
else
|
|
{
|
|
//test YMAX
|
|
dy = (p.y + yw) - YMAX;
|
|
if (0 < dy)
|
|
{
|
|
//object is colliding with YMAX
|
|
this.ReportCollisionVsWorld(0, -dy, 0, -1, null);
|
|
}
|
|
}
|
|
}
|
|
|
|
public render(context:CanvasRenderingContext2D) {
|
|
|
|
context.beginPath();
|
|
context.strokeStyle = 'rgb(0,255,0)';
|
|
context.strokeRect(this.pos.x - this.xw, this.pos.y - this.yw, this.xw * 2, this.yw * 2);
|
|
context.stroke();
|
|
context.closePath();
|
|
|
|
context.fillStyle = 'rgb(0,255,0)';
|
|
context.fillRect(this.pos.x, this.pos.y, 2, 2);
|
|
|
|
/*
|
|
if (this.oH == 1)
|
|
{
|
|
context.beginPath();
|
|
context.strokeStyle = 'rgb(255,0,0)';
|
|
context.moveTo(this.pos.x - this.radius, this.pos.y - this.radius);
|
|
context.lineTo(this.pos.x - this.radius, this.pos.y + this.radius);
|
|
context.stroke();
|
|
context.closePath();
|
|
}
|
|
else if (this.oH == -1)
|
|
{
|
|
context.beginPath();
|
|
context.strokeStyle = 'rgb(255,0,0)';
|
|
context.moveTo(this.pos.x + this.radius, this.pos.y - this.radius);
|
|
context.lineTo(this.pos.x + this.radius, this.pos.y + this.radius);
|
|
context.stroke();
|
|
context.closePath();
|
|
}
|
|
|
|
if (this.oV == 1)
|
|
{
|
|
context.beginPath();
|
|
context.strokeStyle = 'rgb(255,0,0)';
|
|
context.moveTo(this.pos.x - this.radius, this.pos.y - this.radius);
|
|
context.lineTo(this.pos.x + this.radius, this.pos.y - this.radius);
|
|
context.stroke();
|
|
context.closePath();
|
|
}
|
|
else if (this.oV == -1)
|
|
{
|
|
context.beginPath();
|
|
context.strokeStyle = 'rgb(255,0,0)';
|
|
context.moveTo(this.pos.x - this.radius, this.pos.y + this.radius);
|
|
context.lineTo(this.pos.x + this.radius, this.pos.y + this.radius);
|
|
context.stroke();
|
|
context.closePath();
|
|
}
|
|
*/
|
|
|
|
}
|
|
|
|
public ResolveBoxTile(x, y, box, t) {
|
|
if (0 < t.ID)
|
|
{
|
|
return this.aabbTileProjections[t.CTYPE](x, y, box, t);
|
|
}
|
|
else
|
|
{
|
|
//trace("ResolveBoxTile() was called with an empty (or unknown) tile!: ID=" + t.ID + " ("+ t.i + "," + t.j + ")");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public ProjAABB_Full(x, y, obj, t) {
|
|
var l = Math.sqrt(x * x + y * y);
|
|
obj.ReportCollisionVsWorld(x, y, x / l, y / l, t);
|
|
|
|
return AABB.COL_AXIS;
|
|
}
|
|
|
|
public ProjAABB_Convex(x, y, obj, t) {
|
|
//if distance from "innermost" corner of AABB is less than than tile radius,
|
|
//collision is occuring and we need to project
|
|
|
|
var signx = t.signx;
|
|
var signy = t.signy;
|
|
|
|
var ox = (obj.pos.x - (signx * obj.xw)) - (t.pos.x - (signx * t.xw));//(ox,oy) is the vector from the circle center to
|
|
var oy = (obj.pos.y - (signy * obj.yw)) - (t.pos.y - (signy * t.yw));//the AABB
|
|
var len = Math.sqrt(ox * ox + oy * oy);
|
|
|
|
var twid = t.xw * 2;
|
|
var rad = Math.sqrt(twid * twid + 0);//this gives us the radius of a circle centered on the tile's corner and extending to the opposite edge of the tile;
|
|
//note that this should be precomputed at compile-time since it's constant
|
|
|
|
var pen = rad - len;
|
|
if (((signx * ox) < 0) || ((signy * oy) < 0))
|
|
{
|
|
//the test corner is "outside" the 1/4 of the circle we're interested in
|
|
var lenP = Math.sqrt(x * x + y * y);
|
|
obj.ReportCollisionVsWorld(x, y, x / lenP, y / lenP, t);
|
|
|
|
return AABB.COL_AXIS;//we need to report
|
|
}
|
|
else if (0 < pen)
|
|
{
|
|
//project along corner->circle vector
|
|
ox /= len;
|
|
oy /= len;
|
|
obj.ReportCollisionVsWorld(ox * pen, oy * pen, ox, oy, t);
|
|
|
|
return AABB.COL_OTHER;
|
|
}
|
|
|
|
return AABB.COL_NONE;
|
|
}
|
|
|
|
public ProjAABB_Concave(x, y, obj, t)
|
|
{
|
|
//if distance from "innermost" corner of AABB is further than tile radius,
|
|
//collision is occuring and we need to project
|
|
|
|
var signx = t.signx;
|
|
var signy = t.signy;
|
|
|
|
var ox = (t.pos.x + (signx * t.xw)) - (obj.pos.x - (signx * obj.xw));//(ox,oy) is the vector form the innermost AABB corner to the
|
|
var oy = (t.pos.y + (signy * t.yw)) - (obj.pos.y - (signy * obj.yw));//circle's center
|
|
|
|
var twid = t.xw * 2;
|
|
var rad = Math.sqrt(twid * twid + 0);//this gives us the radius of a circle centered on the tile's corner and extending to the opposite edge of the tile;
|
|
//note that this should be precomputed at compile-time since it's constant
|
|
|
|
var len = Math.sqrt(ox * ox + oy * oy);
|
|
var pen = len - rad;
|
|
if (0 < pen)
|
|
{
|
|
//collision; we need to either project along the axes, or project along corner->circlecenter vector
|
|
|
|
var lenP = Math.sqrt(x * x + y * y);
|
|
if (lenP < pen)
|
|
{
|
|
//it's shorter to move along axis directions
|
|
obj.ReportCollisionVsWorld(x, y, x / lenP, y / lenP, t);
|
|
|
|
return AABB.COL_AXIS;
|
|
}
|
|
else
|
|
{
|
|
//project along corner->circle vector
|
|
ox /= len;//len should never be 0, since if it IS 0, rad should be > than len
|
|
oy /= len;//and we should never reach here
|
|
|
|
obj.ReportCollisionVsWorld(ox * pen, oy * pen, ox, oy, t);
|
|
|
|
return AABB.COL_OTHER;
|
|
}
|
|
|
|
}
|
|
|
|
return AABB.COL_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
class TileMapCell {
|
|
|
|
//TILETYPE ENUMERATION
|
|
static TID_EMPTY = 0;
|
|
static TID_FULL = 1;//fullAABB tile
|
|
static TID_45DEGpn = 2;//45-degree triangle, whose normal is (+ve,-ve)
|
|
static TID_45DEGnn = 3;//(+ve,+ve)
|
|
static TID_45DEGnp = 4;//(-ve,+ve)
|
|
static TID_45DEGpp = 5;//(-ve,-ve)
|
|
static TID_CONCAVEpn = 6;//1/4-circle cutout
|
|
static TID_CONCAVEnn = 7;
|
|
static TID_CONCAVEnp = 8;
|
|
static TID_CONCAVEpp = 9;
|
|
static TID_CONVEXpn = 10;//1/4/circle
|
|
static TID_CONVEXnn = 11;
|
|
static TID_CONVEXnp = 12;
|
|
static TID_CONVEXpp = 13;
|
|
static TID_22DEGpnS = 14;//22.5 degree slope
|
|
static TID_22DEGnnS = 15;
|
|
static TID_22DEGnpS = 16;
|
|
static TID_22DEGppS = 17;
|
|
static TID_22DEGpnB = 18;
|
|
static TID_22DEGnnB = 19;
|
|
static TID_22DEGnpB = 20;
|
|
static TID_22DEGppB = 21;
|
|
static TID_67DEGpnS = 22;//67.5 degree slope
|
|
static TID_67DEGnnS = 23;
|
|
static TID_67DEGnpS = 24;
|
|
static TID_67DEGppS = 25;
|
|
static TID_67DEGpnB = 26;
|
|
static TID_67DEGnnB = 27;
|
|
static TID_67DEGnpB = 28;
|
|
static TID_67DEGppB = 29;
|
|
static TID_HALFd = 30;//half-full tiles
|
|
static TID_HALFr = 31;
|
|
static TID_HALFu = 32;
|
|
static TID_HALFl = 33;
|
|
|
|
//collision shape "types"
|
|
static CTYPE_EMPTY = 0;
|
|
static CTYPE_FULL = 1;
|
|
static CTYPE_45DEG = 2;
|
|
static CTYPE_CONCAVE = 6;
|
|
static CTYPE_CONVEX = 10;
|
|
static CTYPE_22DEGs = 14;
|
|
static CTYPE_22DEGb = 18;
|
|
static CTYPE_67DEGs = 22;
|
|
static CTYPE_67DEGb = 26;
|
|
static CTYPE_HALF = 30;
|
|
|
|
ID;
|
|
CTYPE;
|
|
pos: Phaser.Vec2;
|
|
xw;
|
|
yw;
|
|
minx;
|
|
maxx;
|
|
miny;
|
|
maxy;
|
|
signx;
|
|
signy;
|
|
sx;
|
|
sy;
|
|
|
|
constructor(x,y,xw,yw) {
|
|
|
|
this.ID = TileMapCell.TID_EMPTY; //all tiles start empty
|
|
this.CTYPE = TileMapCell.CTYPE_EMPTY;
|
|
|
|
this.pos = new Phaser.Vec2(x,y); //setup collision properties
|
|
this.xw = xw;
|
|
this.yw = yw;
|
|
this.minx = this.pos.x - this.xw;
|
|
this.maxx = this.pos.x + this.xw;
|
|
this.miny = this.pos.y - this.yw;
|
|
this.maxy = this.pos.y + this.yw;
|
|
|
|
//this stores tile-specific collision information
|
|
this.signx = 0;
|
|
this.signy = 0;
|
|
this.sx = 0;
|
|
this.sy = 0;
|
|
}
|
|
|
|
//these functions are used to update the cell
|
|
//note: ID is assumed to NOT be "empty" state..
|
|
//if it IS the empty state, the tile clears itself
|
|
SetState(ID) {
|
|
if (ID == TileMapCell.TID_EMPTY)
|
|
{
|
|
this.Clear();
|
|
}
|
|
else
|
|
{
|
|
//set tile state to a non-emtpy value, and update it's edges and those of the neighbors
|
|
this.ID = ID;
|
|
this.UpdateType();
|
|
//this.Draw();
|
|
}
|
|
return this;
|
|
}
|
|
|
|
Clear() {
|
|
//tile was on, turn it off
|
|
this.ID = TileMapCell.TID_EMPTY
|
|
this.UpdateType();
|
|
//this.Draw();
|
|
}
|
|
|
|
public render(context: CanvasRenderingContext2D) {
|
|
|
|
context.beginPath();
|
|
context.strokeStyle = 'rgb(255,255,0)';
|
|
context.strokeRect(this.minx, this.miny, this.xw * 2, this.yw * 2);
|
|
context.strokeRect(this.pos.x, this.pos.y, 2, 2);
|
|
context.closePath();
|
|
|
|
}
|
|
|
|
//this converts a tile from implicitly-defined (via ID), to explicit (via properties)
|
|
UpdateType() {
|
|
if (0 < this.ID)
|
|
{
|
|
//tile is non-empty; collide
|
|
if (this.ID < TileMapCell.CTYPE_45DEG)
|
|
{
|
|
//TID_FULL
|
|
this.CTYPE = TileMapCell.CTYPE_FULL;
|
|
this.signx = 0;
|
|
this.signy = 0;
|
|
this.sx = 0;
|
|
this.sy = 0;
|
|
|
|
}
|
|
else if (this.ID < TileMapCell.CTYPE_CONCAVE)
|
|
{
|
|
|
|
//45deg
|
|
this.CTYPE = TileMapCell.CTYPE_45DEG;
|
|
if (this.ID == TileMapCell.TID_45DEGpn)
|
|
{
|
|
console.log('set tile as 45deg pn');
|
|
this.signx = 1;
|
|
this.signy = -1;
|
|
this.sx = this.signx / Math.SQRT2;//get slope _unit_ normal
|
|
this.sy = this.signy / Math.SQRT2;//since normal is (1,-1), length is sqrt(1*1 + -1*-1) = sqrt(2)
|
|
|
|
}
|
|
else if (this.ID == TileMapCell.TID_45DEGnn)
|
|
{
|
|
this.signx = -1;
|
|
this.signy = -1;
|
|
this.sx = this.signx / Math.SQRT2;//get slope _unit_ normal
|
|
this.sy = this.signy / Math.SQRT2;//since normal is (1,-1), length is sqrt(1*1 + -1*-1) = sqrt(2)
|
|
|
|
}
|
|
else if (this.ID == TileMapCell.TID_45DEGnp)
|
|
{
|
|
this.signx = -1;
|
|
this.signy = 1;
|
|
this.sx = this.signx / Math.SQRT2;//get slope _unit_ normal
|
|
this.sy = this.signy / Math.SQRT2;//since normal is (1,-1), length is sqrt(1*1 + -1*-1) = sqrt(2)
|
|
}
|
|
else if (this.ID == TileMapCell.TID_45DEGpp)
|
|
{
|
|
this.signx = 1;
|
|
this.signy = 1;
|
|
this.sx = this.signx / Math.SQRT2;//get slope _unit_ normal
|
|
this.sy = this.signy / Math.SQRT2;//since normal is (1,-1), length is sqrt(1*1 + -1*-1) = sqrt(2)
|
|
}
|
|
else
|
|
{
|
|
//trace("BAAAD TILE!!!!!: ID=" + this.ID + " ("+ t.i + "," + t.j + ")");
|
|
return false;
|
|
}
|
|
}
|
|
else if (this.ID < TileMapCell.CTYPE_CONVEX)
|
|
{
|
|
|
|
//concave
|
|
this.CTYPE = TileMapCell.CTYPE_CONCAVE;
|
|
if (this.ID == TileMapCell.TID_CONCAVEpn)
|
|
{
|
|
this.signx = 1;
|
|
this.signy = -1;
|
|
this.sx = 0;
|
|
this.sy = 0;
|
|
}
|
|
else if (this.ID == TileMapCell.TID_CONCAVEnn)
|
|
{
|
|
this.signx = -1;
|
|
this.signy = -1;
|
|
this.sx = 0;
|
|
this.sy = 0;
|
|
}
|
|
else if (this.ID == TileMapCell.TID_CONCAVEnp)
|
|
{
|
|
this.signx = -1;
|
|
this.signy = 1;
|
|
this.sx = 0;
|
|
this.sy = 0;
|
|
}
|
|
else if (this.ID == TileMapCell.TID_CONCAVEpp)
|
|
{
|
|
this.signx = 1;
|
|
this.signy = 1;
|
|
this.sx = 0;
|
|
this.sy = 0;
|
|
}
|
|
else
|
|
{
|
|
//trace("BAAAD TILE!!!!!: ID=" + this.ID + " ("+ t.i + "," + t.j + ")");
|
|
return false;
|
|
}
|
|
}
|
|
else if (this.ID < TileMapCell.CTYPE_22DEGs)
|
|
{
|
|
|
|
//convex
|
|
this.CTYPE = TileMapCell.CTYPE_CONVEX;
|
|
if (this.ID == TileMapCell.TID_CONVEXpn)
|
|
{
|
|
this.signx = 1;
|
|
this.signy = -1;
|
|
this.sx = 0;
|
|
this.sy = 0;
|
|
}
|
|
else if (this.ID == TileMapCell.TID_CONVEXnn)
|
|
{
|
|
this.signx = -1;
|
|
this.signy = -1;
|
|
this.sx = 0;
|
|
this.sy = 0;
|
|
}
|
|
else if (this.ID == TileMapCell.TID_CONVEXnp)
|
|
{
|
|
this.signx = -1;
|
|
this.signy = 1;
|
|
this.sx = 0;
|
|
this.sy = 0;
|
|
}
|
|
else if (this.ID == TileMapCell.TID_CONVEXpp)
|
|
{
|
|
this.signx = 1;
|
|
this.signy = 1;
|
|
this.sx = 0;
|
|
this.sy = 0;
|
|
}
|
|
else
|
|
{
|
|
//trace("BAAAD TILE!!!!!: ID=" + this.ID + " ("+ t.i + "," + t.j + ")");
|
|
return false;
|
|
}
|
|
}
|
|
else if (this.ID < TileMapCell.CTYPE_22DEGb)
|
|
{
|
|
|
|
//22deg small
|
|
this.CTYPE = TileMapCell.CTYPE_22DEGs;
|
|
if (this.ID == TileMapCell.TID_22DEGpnS)
|
|
{
|
|
this.signx = 1;
|
|
this.signy = -1;
|
|
var slen = Math.sqrt(2 * 2 + 1 * 1);
|
|
this.sx = (this.signx * 1) / slen;
|
|
this.sy = (this.signy * 2) / slen;
|
|
}
|
|
else if (this.ID == TileMapCell.TID_22DEGnnS)
|
|
{
|
|
this.signx = -1;
|
|
this.signy = -1;
|
|
var slen = Math.sqrt(2 * 2 + 1 * 1);
|
|
this.sx = (this.signx * 1) / slen;
|
|
this.sy = (this.signy * 2) / slen;
|
|
}
|
|
else if (this.ID == TileMapCell.TID_22DEGnpS)
|
|
{
|
|
this.signx = -1;
|
|
this.signy = 1;
|
|
var slen = Math.sqrt(2 * 2 + 1 * 1);
|
|
this.sx = (this.signx * 1) / slen;
|
|
this.sy = (this.signy * 2) / slen;
|
|
}
|
|
else if (this.ID == TileMapCell.TID_22DEGppS)
|
|
{
|
|
this.signx = 1;
|
|
this.signy = 1;
|
|
var slen = Math.sqrt(2 * 2 + 1 * 1);
|
|
this.sx = (this.signx * 1) / slen;
|
|
this.sy = (this.signy * 2) / slen;
|
|
}
|
|
else
|
|
{
|
|
//trace("BAAAD TILE!!!!!: ID=" + this.ID + " ("+ t.i + "," + t.j + ")");
|
|
return false;
|
|
}
|
|
}
|
|
else if (this.ID < TileMapCell.CTYPE_67DEGs)
|
|
{
|
|
|
|
//22deg big
|
|
this.CTYPE = TileMapCell.CTYPE_22DEGb;
|
|
if (this.ID == TileMapCell.TID_22DEGpnB)
|
|
{
|
|
this.signx = 1;
|
|
this.signy = -1;
|
|
var slen = Math.sqrt(2 * 2 + 1 * 1);
|
|
this.sx = (this.signx * 1) / slen;
|
|
this.sy = (this.signy * 2) / slen;
|
|
}
|
|
else if (this.ID == TileMapCell.TID_22DEGnnB)
|
|
{
|
|
this.signx = -1;
|
|
this.signy = -1;
|
|
var slen = Math.sqrt(2 * 2 + 1 * 1);
|
|
this.sx = (this.signx * 1) / slen;
|
|
this.sy = (this.signy * 2) / slen;
|
|
}
|
|
else if (this.ID == TileMapCell.TID_22DEGnpB)
|
|
{
|
|
this.signx = -1;
|
|
this.signy = 1;
|
|
var slen = Math.sqrt(2 * 2 + 1 * 1);
|
|
this.sx = (this.signx * 1) / slen;
|
|
this.sy = (this.signy * 2) / slen;
|
|
}
|
|
else if (this.ID == TileMapCell.TID_22DEGppB)
|
|
{
|
|
this.signx = 1;
|
|
this.signy = 1;
|
|
var slen = Math.sqrt(2 * 2 + 1 * 1);
|
|
this.sx = (this.signx * 1) / slen;
|
|
this.sy = (this.signy * 2) / slen;
|
|
}
|
|
else
|
|
{
|
|
//trace("BAAAD TILE!!!!!: ID=" + this.ID + " ("+ t.i + "," + t.j + ")");
|
|
return false;
|
|
}
|
|
}
|
|
else if (this.ID < TileMapCell.CTYPE_67DEGb)
|
|
{
|
|
|
|
//67deg small
|
|
this.CTYPE = TileMapCell.CTYPE_67DEGs;
|
|
if (this.ID == TileMapCell.TID_67DEGpnS)
|
|
{
|
|
this.signx = 1;
|
|
this.signy = -1;
|
|
var slen = Math.sqrt(2 * 2 + 1 * 1);
|
|
this.sx = (this.signx * 2) / slen;
|
|
this.sy = (this.signy * 1) / slen;
|
|
}
|
|
else if (this.ID == TileMapCell.TID_67DEGnnS)
|
|
{
|
|
this.signx = -1;
|
|
this.signy = -1;
|
|
var slen = Math.sqrt(2 * 2 + 1 * 1);
|
|
this.sx = (this.signx * 2) / slen;
|
|
this.sy = (this.signy * 1) / slen;
|
|
}
|
|
else if (this.ID == TileMapCell.TID_67DEGnpS)
|
|
{
|
|
this.signx = -1;
|
|
this.signy = 1;
|
|
var slen = Math.sqrt(2 * 2 + 1 * 1);
|
|
this.sx = (this.signx * 2) / slen;
|
|
this.sy = (this.signy * 1) / slen;
|
|
}
|
|
else if (this.ID == TileMapCell.TID_67DEGppS)
|
|
{
|
|
this.signx = 1;
|
|
this.signy = 1;
|
|
var slen = Math.sqrt(2 * 2 + 1 * 1);
|
|
this.sx = (this.signx * 2) / slen;
|
|
this.sy = (this.signy * 1) / slen;
|
|
}
|
|
else
|
|
{
|
|
//trace("BAAAD TILE!!!!!: ID=" + this.ID + " ("+ t.i + "," + t.j + ")");
|
|
return false;
|
|
}
|
|
}
|
|
else if (this.ID < TileMapCell.CTYPE_HALF)
|
|
{
|
|
|
|
//67deg big
|
|
this.CTYPE = TileMapCell.CTYPE_67DEGb;
|
|
if (this.ID == TileMapCell.TID_67DEGpnB)
|
|
{
|
|
this.signx = 1;
|
|
this.signy = -1;
|
|
var slen = Math.sqrt(2 * 2 + 1 * 1);
|
|
this.sx = (this.signx * 2) / slen;
|
|
this.sy = (this.signy * 1) / slen;
|
|
}
|
|
else if (this.ID == TileMapCell.TID_67DEGnnB)
|
|
{
|
|
this.signx = -1;
|
|
this.signy = -1;
|
|
var slen = Math.sqrt(2 * 2 + 1 * 1);
|
|
this.sx = (this.signx * 2) / slen;
|
|
this.sy = (this.signy * 1) / slen;
|
|
}
|
|
else if (this.ID == TileMapCell.TID_67DEGnpB)
|
|
{
|
|
this.signx = -1;
|
|
this.signy = 1;
|
|
var slen = Math.sqrt(2 * 2 + 1 * 1);
|
|
this.sx = (this.signx * 2) / slen;
|
|
this.sy = (this.signy * 1) / slen;
|
|
}
|
|
else if (this.ID == TileMapCell.TID_67DEGppB)
|
|
{
|
|
this.signx = 1;
|
|
this.signy = 1;
|
|
var slen = Math.sqrt(2 * 2 + 1 * 1);
|
|
this.sx = (this.signx * 2) / slen;
|
|
this.sy = (this.signy * 1) / slen;
|
|
}
|
|
else
|
|
{
|
|
//trace("BAAAD TILE!!!!!: ID=" + this.ID + " ("+ t.i + "," + t.j + ")");
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//half-full tile
|
|
this.CTYPE = TileMapCell.CTYPE_HALF;
|
|
if (this.ID == TileMapCell.TID_HALFd)
|
|
{
|
|
this.signx = 0;
|
|
this.signy = -1;
|
|
this.sx = this.signx;
|
|
this.sy = this.signy;
|
|
}
|
|
else if (this.ID == TileMapCell.TID_HALFu)
|
|
{
|
|
this.signx = 0;
|
|
this.signy = 1;
|
|
this.sx = this.signx;
|
|
this.sy = this.signy;
|
|
}
|
|
else if (this.ID == TileMapCell.TID_HALFl)
|
|
{
|
|
this.signx = 1;
|
|
this.signy = 0;
|
|
this.sx = this.signx;
|
|
this.sy = this.signy;
|
|
}
|
|
else if (this.ID == TileMapCell.TID_HALFr)
|
|
{
|
|
this.signx = -1;
|
|
this.signy = 0;
|
|
this.sx = this.signx;
|
|
this.sy = this.signy;
|
|
}
|
|
else
|
|
{
|
|
//trace("BAAD TILE!!!: ID=" + this.ID + " ("+ t.i + "," + t.j + ")");
|
|
return false;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
//TID_EMPTY
|
|
this.CTYPE = TileMapCell.CTYPE_EMPTY;
|
|
this.signx = 0;
|
|
this.signy = 0;
|
|
this.sx = 0;
|
|
this.sy = 0;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
class Circle {
|
|
|
|
constructor(x, y, radius) {
|
|
|
|
this.pos = new Phaser.Vec2(x, y);
|
|
this.oldpos = Phaser.Vec2Utils.clone(this.pos);
|
|
this.radius = radius;
|
|
this.circleTileProjections = {};//hash object to hold tile-specific collision functions
|
|
this.circleTileProjections[TileMapCell.CTYPE_FULL] = this.ProjCircle_Full;
|
|
this.circleTileProjections[TileMapCell.CTYPE_45DEG] = this.ProjCircle_45Deg;
|
|
this.circleTileProjections[TileMapCell.CTYPE_CONCAVE] = this.ProjCircle_Concave;
|
|
this.circleTileProjections[TileMapCell.CTYPE_CONVEX] = this.ProjCircle_Convex;
|
|
|
|
//Proj_CircleTile[CTYPE_22DEGs] = ProjCircle_22DegS;
|
|
//Proj_CircleTile[CTYPE_22DEGb] = ProjCircle_22DegB;
|
|
//Proj_CircleTile[CTYPE_67DEGs] = ProjCircle_67DegS;
|
|
//Proj_CircleTile[CTYPE_67DEGb] = ProjCircle_67DegB;
|
|
//Proj_CircleTile[CTYPE_HALF] = ProjCircle_Half;
|
|
|
|
}
|
|
|
|
type:number = 1;
|
|
pos: Phaser.Vec2;
|
|
oldpos: Phaser.Vec2;
|
|
radius: number;
|
|
circleTileProjections;
|
|
public oH: number;
|
|
public oV: number;
|
|
static COL_NONE = 0;
|
|
static COL_AXIS = 1;
|
|
static COL_OTHER = 2;
|
|
|
|
public IntegrateVerlet() {
|
|
|
|
//var d = DRAG;
|
|
//var g = GRAV;
|
|
var d = 1;
|
|
var g = 0.2;
|
|
|
|
var p = this.pos;
|
|
var o = this.oldpos;
|
|
var px, py;
|
|
|
|
var ox = o.x; //we can't swap buffers since mcs/sticks point directly to vector2s..
|
|
var oy = o.y;
|
|
o.x = px = p.x; //get vector values
|
|
o.y = py = p.y; //p = position
|
|
//o = oldposition
|
|
|
|
//integrate
|
|
p.x += (d * px) - (d * ox);
|
|
p.y += (d * py) - (d * oy) + g;
|
|
|
|
}
|
|
|
|
public ReportCollisionVsWorld(px, py, dx, dy, obj: TileMapCell) {
|
|
|
|
var p = this.pos;
|
|
var o = this.oldpos;
|
|
|
|
//calc velocity
|
|
var vx = p.x - o.x;
|
|
var vy = p.y - o.y;
|
|
|
|
//find component of velocity parallel to collision normal
|
|
var dp = (vx * dx + vy * dy);
|
|
var nx = dp * dx;//project velocity onto collision normal
|
|
|
|
var ny = dp * dy;//nx,ny is normal velocity
|
|
|
|
var tx = vx - nx;//px,py is tangent velocity
|
|
var ty = vy - ny;
|
|
|
|
//we only want to apply collision response forces if the object is travelling into, and not out of, the collision
|
|
var b, bx, by, f, fx, fy;
|
|
|
|
if (dp < 0)
|
|
{
|
|
//f = FRICTION;
|
|
f = 0.05;
|
|
fx = tx * f;
|
|
fy = ty * f;
|
|
|
|
//b = 1 + BOUNCE;//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);
|
|
|
|
}
|
|
else
|
|
{
|
|
//moving out of collision, do not apply forces
|
|
bx = by = fx = fy = 0;
|
|
}
|
|
|
|
p.x += px;//project object out of collision
|
|
p.y += py;
|
|
|
|
o.x += px + bx + fx;//apply bounce+friction impulses which alter velocity
|
|
o.y += py + by + fy;
|
|
|
|
}
|
|
|
|
public CollideCircleVsWorldBounds() {
|
|
var p = this.pos;
|
|
var r = this.radius;
|
|
var XMIN = 0;
|
|
var XMAX = 800;
|
|
var YMIN = 0;
|
|
var YMAX = 600;
|
|
|
|
//collide vs. x-bounds
|
|
//test XMIN
|
|
var dx = XMIN - (p.x - r);
|
|
if (0 < dx)
|
|
{
|
|
//object is colliding with XMIN
|
|
this.ReportCollisionVsWorld(dx, 0, 1, 0, null);
|
|
}
|
|
else
|
|
{
|
|
//test XMAX
|
|
dx = (p.x + r) - XMAX;
|
|
if (0 < dx)
|
|
{
|
|
//object is colliding with XMAX
|
|
this.ReportCollisionVsWorld(-dx, 0, -1, 0, null);
|
|
}
|
|
}
|
|
|
|
//collide vs. y-bounds
|
|
//test YMIN
|
|
var dy = YMIN - (p.y - r);
|
|
if (0 < dy)
|
|
{
|
|
//object is colliding with YMIN
|
|
this.ReportCollisionVsWorld(0, dy, 0, 1, null);
|
|
}
|
|
else
|
|
{
|
|
//test YMAX
|
|
dy = (p.y + r) - YMAX;
|
|
if (0 < dy)
|
|
{
|
|
//object is colliding with YMAX
|
|
this.ReportCollisionVsWorld(0, -dy, 0, -1, null);
|
|
}
|
|
}
|
|
}
|
|
|
|
public render(context:CanvasRenderingContext2D) {
|
|
|
|
context.beginPath();
|
|
context.strokeStyle = 'rgb(0,255,0)';
|
|
context.arc(this.pos.x, this.pos.y, this.radius, 0, Math.PI * 2);
|
|
context.stroke();
|
|
context.closePath();
|
|
|
|
if (this.oH == 1)
|
|
{
|
|
context.beginPath();
|
|
context.strokeStyle = 'rgb(255,0,0)';
|
|
context.moveTo(this.pos.x - this.radius, this.pos.y - this.radius);
|
|
context.lineTo(this.pos.x - this.radius, this.pos.y + this.radius);
|
|
context.stroke();
|
|
context.closePath();
|
|
}
|
|
else if (this.oH == -1)
|
|
{
|
|
context.beginPath();
|
|
context.strokeStyle = 'rgb(255,0,0)';
|
|
context.moveTo(this.pos.x + this.radius, this.pos.y - this.radius);
|
|
context.lineTo(this.pos.x + this.radius, this.pos.y + this.radius);
|
|
context.stroke();
|
|
context.closePath();
|
|
}
|
|
|
|
if (this.oV == 1)
|
|
{
|
|
context.beginPath();
|
|
context.strokeStyle = 'rgb(255,0,0)';
|
|
context.moveTo(this.pos.x - this.radius, this.pos.y - this.radius);
|
|
context.lineTo(this.pos.x + this.radius, this.pos.y - this.radius);
|
|
context.stroke();
|
|
context.closePath();
|
|
}
|
|
else if (this.oV == -1)
|
|
{
|
|
context.beginPath();
|
|
context.strokeStyle = 'rgb(255,0,0)';
|
|
context.moveTo(this.pos.x - this.radius, this.pos.y + this.radius);
|
|
context.lineTo(this.pos.x + this.radius, this.pos.y + this.radius);
|
|
context.stroke();
|
|
context.closePath();
|
|
}
|
|
|
|
}
|
|
|
|
public CollideCircleVsTile(tile) {
|
|
var pos = this.pos;
|
|
var r = this.radius;
|
|
var c = tile;
|
|
|
|
var tx = c.pos.x;
|
|
var ty = c.pos.y;
|
|
var txw = c.xw;
|
|
var tyw = c.yw;
|
|
|
|
var dx = pos.x - tx;//tile->obj delta
|
|
var px = (txw + r) - Math.abs(dx);//penetration depth in x
|
|
|
|
if (0 < px)
|
|
{
|
|
var dy = pos.y - ty;//tile->obj delta
|
|
var py = (tyw + r) - Math.abs(dy);//pen depth in y
|
|
|
|
if (0 < py)
|
|
{
|
|
//object may be colliding with tile
|
|
|
|
//determine grid/voronoi region of circle center
|
|
this.oH = 0;
|
|
this.oV = 0;
|
|
if (dx < -txw)
|
|
{
|
|
//circle is on left side of tile
|
|
this.oH = -1;
|
|
}
|
|
else if (txw < dx)
|
|
{
|
|
//circle is on right side of tile
|
|
this.oH = 1;
|
|
}
|
|
|
|
if (dy < -tyw)
|
|
{
|
|
//circle is on top side of tile
|
|
this.oV = -1;
|
|
}
|
|
else if (tyw < dy)
|
|
{
|
|
//circle is on bottom side of tile
|
|
this.oV = 1;
|
|
}
|
|
|
|
this.ResolveCircleTile(px, py, this.oH, this.oV, this, c);
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
public ResolveCircleTile(x, y, oH, oV, obj, t) {
|
|
|
|
if (0 < t.ID)
|
|
{
|
|
return this.circleTileProjections[t.CTYPE](x, y, oH, oV, obj, t);
|
|
}
|
|
else
|
|
{
|
|
console.log("ResolveCircleTile() was called with an empty (or unknown) tile!: ID=" + t.ID + " (" + t.i + "," + t.j + ")");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public ProjCircle_Full(x, y, oH, oV, obj:Circle, t:TileMapCell) {
|
|
|
|
//if we're colliding vs. the current cell, we need to project along the
|
|
//smallest penetration vector.
|
|
//if we're colliding vs. horiz. or vert. neighb, we simply project horiz/vert
|
|
//if we're colliding diagonally, we need to collide vs. tile corner
|
|
|
|
if (oH == 0)
|
|
{
|
|
if (oV == 0)
|
|
{
|
|
//collision with current cell
|
|
if (x < y)
|
|
{
|
|
//penetration in x is smaller; project in x
|
|
var dx = obj.pos.x - t.pos.x;//get sign for projection along x-axis
|
|
|
|
//NOTE: should we handle the delta == 0 case?! and how? (project towards oldpos?)
|
|
if (dx < 0)
|
|
{
|
|
obj.ReportCollisionVsWorld(-x, 0, -1, 0, t);
|
|
return Circle.COL_AXIS;
|
|
}
|
|
else
|
|
{
|
|
obj.ReportCollisionVsWorld(x, 0, 1, 0, t);
|
|
return Circle.COL_AXIS;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//penetration in y is smaller; project in y
|
|
var dy = obj.pos.y - t.pos.y;//get sign for projection along y-axis
|
|
|
|
//NOTE: should we handle the delta == 0 case?! and how? (project towards oldpos?)
|
|
if (dy < 0)
|
|
{
|
|
obj.ReportCollisionVsWorld(0, -y, 0, -1, t);
|
|
return Circle.COL_AXIS;
|
|
}
|
|
else
|
|
{
|
|
obj.ReportCollisionVsWorld(0, y, 0, 1, t);
|
|
return Circle.COL_AXIS;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//collision with vertical neighbor
|
|
obj.ReportCollisionVsWorld(0, y * oV, 0, oV, t);
|
|
|
|
return Circle.COL_AXIS;
|
|
}
|
|
}
|
|
else if (oV == 0)
|
|
{
|
|
//collision with horizontal neighbor
|
|
obj.ReportCollisionVsWorld(x * oH, 0, oH, 0, t);
|
|
return Circle.COL_AXIS;
|
|
}
|
|
else
|
|
{
|
|
//diagonal collision
|
|
|
|
//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;//calc vert->circle vector
|
|
var dy = obj.pos.y - vy;
|
|
|
|
var len = Math.sqrt(dx * dx + dy * dy);
|
|
var pen = obj.radius - len;
|
|
if (0 < pen)
|
|
{
|
|
//vertex is in the circle; project outward
|
|
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 Circle.COL_OTHER;
|
|
}
|
|
}
|
|
|
|
return Circle.COL_NONE;
|
|
|
|
}
|
|
|
|
public ProjCircle_45Deg(x, y, oH, oV, obj: Circle, t: TileMapCell) {
|
|
|
|
//if we're colliding diagonally:
|
|
// -if obj is in the diagonal pointed to by the slope normal: we can't collide, do nothing
|
|
// -else, collide vs. the appropriate vertex
|
|
//if obj is in this tile: perform collision as for aabb-ve-45deg
|
|
//if obj is horiz OR very neighb in direction of slope: collide only vs. slope
|
|
//if obj is horiz or vert neigh against direction of slope: collide vs. face
|
|
|
|
var signx = t.signx;
|
|
var signy = t.signy;
|
|
var lenP;
|
|
|
|
if (oH == 0)
|
|
{
|
|
if (oV == 0)
|
|
{
|
|
//colliding with current tile
|
|
|
|
var sx = t.sx;
|
|
var sy = t.sy;
|
|
|
|
var ox = (obj.pos.x - (sx * obj.radius)) - t.pos.x;//this gives is the coordinates of the innermost
|
|
var oy = (obj.pos.y - (sy * obj.radius)) - t.pos.y;//point on the circle, relative to the tile center
|
|
|
|
//if the dotprod of (ox,oy) and (sx,sy) is negative, the innermost point 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 as the slope penetration vector
|
|
sx *= -dp;//(sx,sy) is now the penetration vector
|
|
sy *= -dp;
|
|
|
|
//find the smallest axial projection vector
|
|
if (x < y)
|
|
{
|
|
//penetration in x is smaller
|
|
lenP = x;
|
|
y = 0;
|
|
|
|
//get sign for projection along x-axis
|
|
if ((obj.pos.x - t.pos.x) < 0)
|
|
{
|
|
x *= -1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//penetration in y is smaller
|
|
lenP = y;
|
|
x = 0;
|
|
|
|
//get sign for projection along y-axis
|
|
if ((obj.pos.y - t.pos.y) < 0)
|
|
{
|
|
y *= -1;
|
|
}
|
|
}
|
|
|
|
var lenN = Math.sqrt(sx * sx + sy * sy);
|
|
|
|
if (lenP < lenN)
|
|
{
|
|
obj.ReportCollisionVsWorld(x, y, x / lenP, y / lenP, t);
|
|
|
|
return Circle.COL_AXIS;
|
|
}
|
|
else
|
|
{
|
|
obj.ReportCollisionVsWorld(sx, sy, t.sx, t.sy, t);
|
|
|
|
return Circle.COL_OTHER;
|
|
}
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
//colliding vertically
|
|
if ((signy * oV) < 0)
|
|
{
|
|
//colliding with face/edge
|
|
obj.ReportCollisionVsWorld(0, y * oV, 0, oV, t);
|
|
|
|
return 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 sx = t.sx;
|
|
var sy = t.sy;
|
|
|
|
var ox = obj.pos.x - (t.pos.x - (signx * t.xw));//this gives is the coordinates of the innermost
|
|
var oy = obj.pos.y - (t.pos.y + (oV * t.yw));//point on the circle, relative to the closest tile vert
|
|
|
|
//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 voronoi 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 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);//note: we don't need the abs because we know the dp will be positive, but just in case..
|
|
if (0 < pen)
|
|
{
|
|
//collision; circle out along normal by penetration amount
|
|
obj.ReportCollisionVsWorld(sx * pen, sy * pen, sx, sy, t);
|
|
|
|
return Circle.COL_OTHER;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (oV == 0)
|
|
{
|
|
//colliding horizontally
|
|
if ((signx * oH) < 0)
|
|
{
|
|
//colliding with face/edge
|
|
obj.ReportCollisionVsWorld(x * oH, 0, oH, 0, t);
|
|
|
|
return 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 sx = t.sx;
|
|
var sy = t.sy;
|
|
|
|
var ox = obj.pos.x - (t.pos.x + (oH * t.xw));//this gives is the coordinates of the innermost
|
|
var oy = obj.pos.y - (t.pos.y - (signy * t.yw));//point on the circle, relative to the closest tile vert
|
|
|
|
//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 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);//note: we don't need the abs because we know the dp will be positive, but just in case..
|
|
if (0 < pen)
|
|
{
|
|
//collision; circle out along normal by penetration amount
|
|
obj.ReportCollisionVsWorld(sx * pen, sy * pen, sx, sy, t);
|
|
|
|
return Circle.COL_OTHER;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//colliding diagonally
|
|
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, and
|
|
//it cannot possibly reach/touch/penetrate the slope
|
|
return Circle.COL_NONE;
|
|
}
|
|
else
|
|
{
|
|
//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;//calc vert->circle vector
|
|
var dy = obj.pos.y - vy;
|
|
|
|
var len = Math.sqrt(dx * dx + dy * dy);
|
|
var pen = obj.radius - len;
|
|
if (0 < pen)
|
|
{
|
|
//vertex is in the circle; project outward
|
|
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 Circle.COL_OTHER;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return Circle.COL_NONE;
|
|
}
|
|
|
|
public ProjCircle_Concave(x, y, oH, oV, obj: Circle, t: TileMapCell) {
|
|
|
|
//if we're colliding diagonally:
|
|
// -if obj is in the diagonal pointed to by the slope normal: we can't collide, do nothing
|
|
// -else, collide vs. the appropriate vertex
|
|
//if obj is in this tile: perform collision as for aabb
|
|
//if obj is horiz OR very neighb in direction of slope: collide vs vert
|
|
//if obj is horiz or vert neigh against direction of slope: collide vs. face
|
|
|
|
var signx = t.signx;
|
|
var signy = t.signy;
|
|
var lenP;
|
|
|
|
if (oH == 0)
|
|
{
|
|
if (oV == 0)
|
|
{
|
|
//colliding with current tile
|
|
|
|
var ox = (t.pos.x + (signx * t.xw)) - obj.pos.x;//(ox,oy) is the vector from the circle to
|
|
var oy = (t.pos.y + (signy * t.yw)) - obj.pos.y;//tile-circle's center
|
|
|
|
var twid = t.xw * 2;
|
|
var trad = Math.sqrt(twid * twid + 0);//this gives us the radius of a circle centered on the tile's corner and extending to the opposite edge of the tile;
|
|
//note that this should be precomputed at compile-time since it's constant
|
|
|
|
var len = Math.sqrt(ox * ox + oy * oy);
|
|
var pen = (len + obj.radius) - trad;
|
|
|
|
if (0 < pen)
|
|
{
|
|
//find the smallest axial projection vector
|
|
if (x < y)
|
|
{
|
|
//penetration in x is smaller
|
|
lenP = x;
|
|
y = 0;
|
|
|
|
//get sign for projection along x-axis
|
|
if ((obj.pos.x - t.pos.x) < 0)
|
|
{
|
|
x *= -1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//penetration in y is smaller
|
|
lenP = y;
|
|
x = 0;
|
|
|
|
//get sign for projection along y-axis
|
|
if ((obj.pos.y - t.pos.y) < 0)
|
|
{
|
|
y *= -1;
|
|
}
|
|
}
|
|
|
|
|
|
if (lenP < pen)
|
|
{
|
|
obj.ReportCollisionVsWorld(x, y, x / lenP, y / lenP, t);
|
|
|
|
return Circle.COL_AXIS;
|
|
}
|
|
else
|
|
{
|
|
//we can assume that len >0, because if we're here then
|
|
//(len + obj.radius) > trad, and since obj.radius <= trad
|
|
//len MUST be > 0
|
|
ox /= len;
|
|
oy /= len;
|
|
|
|
obj.ReportCollisionVsWorld(ox * pen, oy * pen, ox, oy, t);
|
|
|
|
return Circle.COL_OTHER;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return Circle.COL_NONE;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
//colliding vertically
|
|
if ((signy * oV) < 0)
|
|
{
|
|
//colliding with face/edge
|
|
obj.ReportCollisionVsWorld(0, y * oV, 0, oV, t);
|
|
|
|
return Circle.COL_AXIS;
|
|
}
|
|
else
|
|
{
|
|
//we could only be colliding vs the vertical tip
|
|
|
|
//get diag vertex position
|
|
var vx = t.pos.x - (signx * t.xw);
|
|
var vy = t.pos.y + (oV * t.yw);
|
|
|
|
var dx = obj.pos.x - vx;//calc vert->circle vector
|
|
var dy = obj.pos.y - vy;
|
|
|
|
var len = Math.sqrt(dx * dx + dy * dy);
|
|
var pen = obj.radius - len;
|
|
if (0 < pen)
|
|
{
|
|
//vertex is in the circle; project outward
|
|
if (len == 0)
|
|
{
|
|
//project out vertically
|
|
dx = 0;
|
|
dy = oV;
|
|
}
|
|
else
|
|
{
|
|
dx /= len;
|
|
dy /= len;
|
|
}
|
|
|
|
obj.ReportCollisionVsWorld(dx * pen, dy * pen, dx, dy, t);
|
|
|
|
return Circle.COL_OTHER;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (oV == 0)
|
|
{
|
|
//colliding horizontally
|
|
if ((signx * oH) < 0)
|
|
{
|
|
//colliding with face/edge
|
|
obj.ReportCollisionVsWorld(x * oH, 0, oH, 0, t);
|
|
|
|
return Circle.COL_AXIS;
|
|
}
|
|
else
|
|
{
|
|
//we could only be colliding vs the horizontal tip
|
|
|
|
//get diag vertex position
|
|
var vx = t.pos.x + (oH * t.xw);
|
|
var vy = t.pos.y - (signy * t.yw);
|
|
|
|
var dx = obj.pos.x - vx;//calc vert->circle vector
|
|
var dy = obj.pos.y - vy;
|
|
|
|
var len = Math.sqrt(dx * dx + dy * dy);
|
|
var pen = obj.radius - len;
|
|
if (0 < pen)
|
|
{
|
|
//vertex is in the circle; project outward
|
|
if (len == 0)
|
|
{
|
|
//project out horizontally
|
|
dx = oH;
|
|
dy = 0;
|
|
}
|
|
else
|
|
{
|
|
dx /= len;
|
|
dy /= len;
|
|
}
|
|
|
|
obj.ReportCollisionVsWorld(dx * pen, dy * pen, dx, dy, t);
|
|
|
|
return Circle.COL_OTHER;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//colliding diagonally
|
|
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, and
|
|
//it cannot possibly reach/touch/penetrate the slope
|
|
return Circle.COL_NONE;
|
|
}
|
|
else
|
|
{
|
|
//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;//calc vert->circle vector
|
|
var dy = obj.pos.y - vy;
|
|
|
|
var len = Math.sqrt(dx * dx + dy * dy);
|
|
var pen = obj.radius - len;
|
|
if (0 < pen)
|
|
{
|
|
//vertex is in the circle; project outward
|
|
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 Circle.COL_OTHER;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return Circle.COL_NONE;
|
|
|
|
}
|
|
|
|
public ProjCircle_Convex(x, y, oH, oV, obj: Circle, t: TileMapCell) {
|
|
//if the object is horiz AND/OR vertical neighbor in the normal (signx,signy)
|
|
//direction, collide vs. tile-circle only.
|
|
//if we're colliding diagonally:
|
|
// -else, collide vs. the appropriate vertex
|
|
//if obj is in this tile: perform collision as for aabb
|
|
//if obj is horiz or vert neigh against direction of slope: collide vs. face
|
|
|
|
var signx = t.signx;
|
|
var signy = t.signy;
|
|
var lenP;
|
|
|
|
if (oH == 0)
|
|
{
|
|
if (oV == 0)
|
|
{
|
|
//colliding with current tile
|
|
|
|
|
|
var ox = obj.pos.x - (t.pos.x - (signx * t.xw));//(ox,oy) is the vector from the tile-circle to
|
|
var oy = obj.pos.y - (t.pos.y - (signy * t.yw));//the circle's center
|
|
|
|
var twid = t.xw * 2;
|
|
var trad = Math.sqrt(twid * twid + 0);//this gives us the radius of a circle centered on the tile's corner and extending to the opposite edge of the tile;
|
|
//note that this should be precomputed at compile-time since it's constant
|
|
|
|
var len = Math.sqrt(ox * ox + oy * oy);
|
|
var pen = (trad + obj.radius) - len;
|
|
|
|
if (0 < pen)
|
|
{
|
|
//find the smallest axial projection vector
|
|
if (x < y)
|
|
{
|
|
//penetration in x is smaller
|
|
lenP = x;
|
|
y = 0;
|
|
|
|
//get sign for projection along x-axis
|
|
if ((obj.pos.x - t.pos.x) < 0)
|
|
{
|
|
x *= -1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//penetration in y is smaller
|
|
lenP = y;
|
|
x = 0;
|
|
|
|
//get sign for projection along y-axis
|
|
if ((obj.pos.y - t.pos.y) < 0)
|
|
{
|
|
y *= -1;
|
|
}
|
|
}
|
|
|
|
|
|
if (lenP < pen)
|
|
{
|
|
obj.ReportCollisionVsWorld(x, y, x / lenP, y / lenP, t);
|
|
|
|
return Circle.COL_AXIS;
|
|
}
|
|
else
|
|
{
|
|
//note: len should NEVER be == 0, because if it is,
|
|
//projeciton by an axis shoudl always be shorter, and we should
|
|
//never arrive here
|
|
ox /= len;
|
|
oy /= len;
|
|
|
|
obj.ReportCollisionVsWorld(ox * pen, oy * pen, ox, oy, t);
|
|
|
|
return Circle.COL_OTHER;
|
|
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//colliding vertically
|
|
if ((signy * oV) < 0)
|
|
{
|
|
//colliding with face/edge
|
|
obj.ReportCollisionVsWorld(0, y * oV, 0, oV, t);
|
|
|
|
return Circle.COL_AXIS;
|
|
}
|
|
else
|
|
{
|
|
//obj in neighboring cell pointed at by tile normal;
|
|
//we could only be colliding vs the tile-circle surface
|
|
|
|
var ox = obj.pos.x - (t.pos.x - (signx * t.xw));//(ox,oy) is the vector from the tile-circle to
|
|
var oy = obj.pos.y - (t.pos.y - (signy * t.yw));//the circle's center
|
|
|
|
var twid = t.xw * 2;
|
|
var trad = Math.sqrt(twid * twid + 0);//this gives us the radius of a circle centered on the tile's corner and extending to the opposite edge of the tile;
|
|
//note that this should be precomputed at compile-time since it's constant
|
|
|
|
var len = Math.sqrt(ox * ox + oy * oy);
|
|
var pen = (trad + obj.radius) - len;
|
|
|
|
if (0 < pen)
|
|
{
|
|
|
|
//note: len should NEVER be == 0, because if it is,
|
|
//obj is not in a neighboring cell!
|
|
ox /= len;
|
|
oy /= len;
|
|
|
|
obj.ReportCollisionVsWorld(ox * pen, oy * pen, ox, oy, t);
|
|
|
|
return Circle.COL_OTHER;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (oV == 0)
|
|
{
|
|
//colliding horizontally
|
|
if ((signx * oH) < 0)
|
|
{
|
|
//colliding with face/edge
|
|
obj.ReportCollisionVsWorld(x * oH, 0, oH, 0, t);
|
|
|
|
return Circle.COL_AXIS;
|
|
}
|
|
else
|
|
{
|
|
//obj in neighboring cell pointed at by tile normal;
|
|
//we could only be colliding vs the tile-circle surface
|
|
|
|
var ox = obj.pos.x - (t.pos.x - (signx * t.xw));//(ox,oy) is the vector from the tile-circle to
|
|
var oy = obj.pos.y - (t.pos.y - (signy * t.yw));//the circle's center
|
|
|
|
var twid = t.xw * 2;
|
|
var trad = Math.sqrt(twid * twid + 0);//this gives us the radius of a circle centered on the tile's corner and extending to the opposite edge of the tile;
|
|
//note that this should be precomputed at compile-time since it's constant
|
|
|
|
var len = Math.sqrt(ox * ox + oy * oy);
|
|
var pen = (trad + obj.radius) - len;
|
|
|
|
if (0 < pen)
|
|
{
|
|
|
|
//note: len should NEVER be == 0, because if it is,
|
|
//obj is not in a neighboring cell!
|
|
ox /= len;
|
|
oy /= len;
|
|
|
|
obj.ReportCollisionVsWorld(ox * pen, oy * pen, ox, oy, t);
|
|
|
|
return Circle.COL_OTHER;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//colliding diagonally
|
|
if (0 < ((signx * oH) + (signy * oV)))
|
|
{
|
|
//obj in diag neighb cell pointed at by tile normal;
|
|
//we could only be colliding vs the tile-circle surface
|
|
|
|
var ox = obj.pos.x - (t.pos.x - (signx * t.xw));//(ox,oy) is the vector from the tile-circle to
|
|
var oy = obj.pos.y - (t.pos.y - (signy * t.yw));//the circle's center
|
|
|
|
var twid = t.xw * 2;
|
|
var trad = Math.sqrt(twid * twid + 0);//this gives us the radius of a circle centered on the tile's corner and extending to the opposite edge of the tile;
|
|
//note that this should be precomputed at compile-time since it's constant
|
|
|
|
var len = Math.sqrt(ox * ox + oy * oy);
|
|
var pen = (trad + obj.radius) - len;
|
|
|
|
if (0 < pen)
|
|
{
|
|
|
|
//note: len should NEVER be == 0, because if it is,
|
|
//obj is not in a neighboring cell!
|
|
ox /= len;
|
|
oy /= len;
|
|
|
|
obj.ReportCollisionVsWorld(ox * pen, oy * pen, ox, oy, t);
|
|
|
|
return Circle.COL_OTHER;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//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;//calc vert->circle vector
|
|
var dy = obj.pos.y - vy;
|
|
|
|
var len = Math.sqrt(dx * dx + dy * dy);
|
|
var pen = obj.radius - len;
|
|
if (0 < pen)
|
|
{
|
|
//vertex is in the circle; project outward
|
|
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 Circle.COL_OTHER;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return Circle.COL_NONE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
(function () {
|
|
|
|
var game = new Phaser.Game(this, 'game', 800, 600, init, create, update, render);
|
|
|
|
function init() {
|
|
|
|
game.load.image('ball', 'assets/sprites/shinyball.png');
|
|
game.load.image('card', 'assets/sprites/mana_card.png');
|
|
|
|
}
|
|
|
|
var cells;
|
|
var physics: NPhysics;
|
|
var b: AABB;
|
|
var c: Circle;
|
|
var t: TileMapCell;
|
|
var ball: Phaser.Sprite;
|
|
var card: Phaser.Sprite;
|
|
|
|
function create() {
|
|
|
|
this.ball = game.add.sprite(0, 0, 'ball');
|
|
this.ball.origin.setTo(0.5, 0.5);
|
|
|
|
this.card = game.add.sprite(0, 0, 'card');
|
|
this.card.rotation = 30;
|
|
//this.card.origin.setTo(0.5, 0.5);
|
|
|
|
this.physics = new NPhysics();
|
|
this.c = new Circle(200, 100, 16);
|
|
this.b = new AABB(200, 200, 74/2, 128/2);
|
|
|
|
// pos is center, not upper-left
|
|
this.cells = [];
|
|
|
|
var tid;
|
|
|
|
for (var i = 0; i < 10; i++)
|
|
{
|
|
if (i % 2 == 0)
|
|
{
|
|
console.log('pn');
|
|
tid = TileMapCell.TID_CONCAVEpn;
|
|
}
|
|
else
|
|
{
|
|
console.log('nn');
|
|
tid = TileMapCell.TID_CONCAVEnn;
|
|
}
|
|
|
|
//this.cells.push(new TileMapCell(100 + (i * 100), 400, 50, 100).SetState(TileMapCell.TID_FULL));
|
|
|
|
this.cells.push(new TileMapCell(100 + (i * 100), 400, 50, 50).SetState(tid));
|
|
|
|
//this.cells.push(new TileMapCell(100 + (i * 100), 500, 50, 50).SetState(TileMapCell.TID_FULL));
|
|
//this.cells.push(new TileMapCell(100 + (i * 100), 500, 50, 50).SetState(TileMapCell.TID_CONCAVEpn));
|
|
}
|
|
|
|
//this.t = new TileMapCell(200, 500, 100, 100);
|
|
//this.t.SetState(TileMapCell.TID_FULL);
|
|
//this.t.SetState(TileMapCell.TID_45DEGpn);
|
|
//this.t.SetState(TileMapCell.TID_CONCAVEpn);
|
|
//this.t.SetState(TileMapCell.TID_CONVEXpn);
|
|
|
|
}
|
|
|
|
function update() {
|
|
|
|
var fx = 0;
|
|
var fy = 0;
|
|
|
|
if (game.input.keyboard.isDown(Phaser.Keyboard.LEFT))
|
|
{
|
|
fx -= 0.2;
|
|
}
|
|
else if (game.input.keyboard.isDown(Phaser.Keyboard.RIGHT))
|
|
{
|
|
fx += 0.2;
|
|
}
|
|
|
|
if (game.input.keyboard.isDown(Phaser.Keyboard.UP))
|
|
{
|
|
fy -= 0.2 + 0.2;
|
|
}
|
|
else if (game.input.keyboard.isDown(Phaser.Keyboard.DOWN))
|
|
{
|
|
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]);
|
|
}
|
|
|
|
this.c.CollideCircleVsWorldBounds();
|
|
this.b.CollideAABBVsWorldBounds();
|
|
|
|
|
|
|
|
this.ball.x = this.c.pos.x;
|
|
this.ball.y = this.c.pos.y;
|
|
|
|
this.card.transform.centerOn(this.b.pos.x, this.b.pos.y);
|
|
//this.card.x = this.b.pos.x;
|
|
//this.card.y = this.b.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);
|
|
}
|
|
|
|
}
|
|
|
|
})();
|