Merge branch 'photonstorm/097'

This commit is contained in:
Sean 2013-06-16 09:39:13 +08:00
commit 80f5c0a67d
34 changed files with 13614 additions and 52 deletions

View file

@ -56,7 +56,9 @@
<TypeScriptOutFile>../build/phaser.js</TypeScriptOutFile>
<TypeScriptGeneratesDeclarations>true</TypeScriptGeneratesDeclarations>
</PropertyGroup>
<ItemGroup />
<ItemGroup>
<Folder Include="physics\arcade\" />
</ItemGroup>
<ItemGroup>
<Content Include="components\animation\AnimationManager.js">
<DependentUpon>AnimationManager.ts</DependentUpon>
@ -161,12 +163,88 @@
</Content>
<TypeScriptCompile Include="Motion.ts" />
<TypeScriptCompile Include="math\Vec2.ts" />
<TypeScriptCompile Include="math\Transform.ts" />
<Content Include="math\Transform.js">
<DependentUpon>Transform.ts</DependentUpon>
</Content>
<TypeScriptCompile Include="math\TransformUtils.ts" />
<Content Include="math\TransformUtils.js">
<DependentUpon>TransformUtils.ts</DependentUpon>
</Content>
<Content Include="math\Vec2.js">
<DependentUpon>Vec2.ts</DependentUpon>
</Content>
<Content Include="Motion.js">
<DependentUpon>Motion.ts</DependentUpon>
</Content>
<TypeScriptCompile Include="physics\ArcadePhysics.ts" />
<TypeScriptCompile Include="physics\advanced\Body.ts" />
<Content Include="physics\advanced\Body.js">
<DependentUpon>Body.ts</DependentUpon>
</Content>
<TypeScriptCompile Include="physics\advanced\Bounds.ts" />
<Content Include="physics\advanced\Bounds.js">
<DependentUpon>Bounds.ts</DependentUpon>
</Content>
<TypeScriptCompile Include="physics\advanced\Contact.ts" />
<TypeScriptCompile Include="physics\advanced\Collision.ts" />
<Content Include="physics\advanced\Collision.js">
<DependentUpon>Collision.ts</DependentUpon>
</Content>
<Content Include="physics\advanced\Contact.js">
<DependentUpon>Contact.ts</DependentUpon>
</Content>
<TypeScriptCompile Include="physics\advanced\ContactSolver.ts" />
<Content Include="physics\advanced\ContactSolver.js">
<DependentUpon>ContactSolver.ts</DependentUpon>
</Content>
<TypeScriptCompile Include="physics\advanced\Manager.ts" />
<TypeScriptCompile Include="physics\advanced\joints\IJoint.ts" />
<Content Include="physics\advanced\joints\IJoint.js">
<DependentUpon>IJoint.ts</DependentUpon>
</Content>
<TypeScriptCompile Include="physics\advanced\joints\Joint.ts" />
<Content Include="physics\advanced\joints\Joint.js">
<DependentUpon>Joint.ts</DependentUpon>
</Content>
<Content Include="physics\advanced\Manager.js">
<DependentUpon>Manager.ts</DependentUpon>
</Content>
<TypeScriptCompile Include="physics\advanced\shapes\Shape.ts" />
<TypeScriptCompile Include="physics\advanced\shapes\IShape.ts" />
<TypeScriptCompile Include="physics\advanced\shapes\Box.ts" />
<Content Include="physics\advanced\shapes\Box.js">
<DependentUpon>Box.ts</DependentUpon>
</Content>
<TypeScriptCompile Include="physics\advanced\shapes\Circle.ts" />
<Content Include="physics\advanced\shapes\Circle.js">
<DependentUpon>Circle.ts</DependentUpon>
</Content>
<Content Include="physics\advanced\shapes\IShape.js">
<DependentUpon>IShape.ts</DependentUpon>
</Content>
<TypeScriptCompile Include="physics\advanced\shapes\Poly.ts" />
<Content Include="physics\advanced\shapes\Poly.js">
<DependentUpon>Poly.ts</DependentUpon>
</Content>
<TypeScriptCompile Include="physics\advanced\shapes\Segment.ts" />
<Content Include="physics\advanced\shapes\Segment.js">
<DependentUpon>Segment.ts</DependentUpon>
</Content>
<Content Include="physics\advanced\shapes\Shape.js">
<DependentUpon>Shape.ts</DependentUpon>
</Content>
<TypeScriptCompile Include="physics\advanced\shapes\Triangle.ts" />
<Content Include="physics\advanced\shapes\Triangle.js">
<DependentUpon>Triangle.ts</DependentUpon>
</Content>
<TypeScriptCompile Include="physics\advanced\Space.ts" />
<Content Include="physics\advanced\Space.js">
<DependentUpon>Space.ts</DependentUpon>
</Content>
<Content Include="physics\ArcadePhysics.js">
<DependentUpon>ArcadePhysics.ts</DependentUpon>
</Content>
<Content Include="physics\Body.js">
<DependentUpon>Body.ts</DependentUpon>
</Content>

View file

@ -25,9 +25,9 @@ module Phaser {
static GEOM_POLYGON: number = 4;
static BODY_DISABLED: number = 0;
static BODY_DYNAMIC: number = 1;
static BODY_STATIC: number = 2;
static BODY_KINEMATIC: number = 3;
static BODY_STATIC: number = 1;
static BODY_KINETIC: number = 2;
static BODY_DYNAMIC: number = 3;
/**
* Flag used to allow GameObjects to collide on their left side

View file

@ -75,7 +75,7 @@ module Phaser {
}
/**
* Called one by Game during the boot process.
* Called once by Game during the boot process.
*/
public boot() {

View file

@ -623,7 +623,6 @@ module Phaser {
this.sort();
// What's the z index of the top most child?
var tempZ: number = child.z;
var childIndex: number = this._zCounter;
this._i = 0;
@ -632,17 +631,21 @@ module Phaser {
{
this._member = this.members[this._i++];
if (this._i > childIndex)
if (this._member)
{
this._member.z--;
}
else if (this._member.z == child.z)
{
childIndex = this._i;
this._member.z = this._zCounter;
if (this._i > childIndex)
{
this._member.z--;
}
else if (this._member.z == child.z)
{
childIndex = this._i;
this._member.z = this._zCounter;
}
}
}
// Maybe redundant?
this.sort();
return true;

69
Phaser/math/Transform.ts Normal file
View file

@ -0,0 +1,69 @@
/// <reference path="../Game.ts" />
/// <reference path="Vec2Utils.ts" />
/**
* Phaser - 2D Transform
*
* A 2D Transform
*/
module Phaser {
export class Transform {
/**
* Creates a new 2D Transform object.
* @class Transform
* @constructor
* @return {Transform} This object
**/
constructor(pos: Phaser.Vec2, angle: number) {
this.t = Phaser.Vec2Utils.clone(pos);
this.c = Math.cos(angle);
this.s = Math.sin(angle);
}
public t: Phaser.Vec2;
public c: number;
public s: number;
public setTo(pos:Phaser.Vec2, angle:number) {
this.t.copyFrom(pos);
this.c = Math.cos(angle);
this.s = Math.sin(angle);
return this;
}
public setRotation(angle:number) {
this.c = Math.cos(angle);
this.s = Math.sin(angle);
return this;
}
public setPosition(p:Phaser.Vec2) {
this.t.copyFrom(p);
return this;
}
public identity() {
this.t.setTo(0, 0);
this.c = 1;
this.s = 0;
return this;
}
}
}

View file

@ -0,0 +1,39 @@
/// <reference path="../Game.ts" />
/// <reference path="Vec2.ts" />
/// <reference path="Transform.ts" />
/**
* Phaser - TransformUtils
*
* A collection of methods useful for manipulating and performing operations on 2D Transforms.
*
*/
module Phaser {
export class TransformUtils {
public static rotate(t: Transform, v:Phaser.Vec2, out?: Vec2 = new Vec2):Phaser.Vec2 {
return out.setTo(v.x * t.c - v.y * t.s, v.x * t.s + v.y * t.c);
}
public static unrotate(t: Transform, v:Phaser.Vec2, out?: Vec2 = new Vec2):Phaser.Vec2 {
return out.setTo(v.x * t.c + v.y * t.s, -v.x * t.s + v.y * t.c);
}
public static transform(t: Transform, v:Phaser.Vec2, out?: Vec2 = new Vec2):Phaser.Vec2 {
return out.setTo(v.x * t.c - v.y * t.s + t.t.x, v.x * t.s + v.y * t.c + t.t.y);
}
public static untransform(t: Transform, v:Phaser.Vec2, out?: Vec2 = new Vec2):Phaser.Vec2 {
var px = v.x - t.t.x;
var py = v.y - t.t.y;
return out.setTo(px * t.c + py * t.s, -px * t.s + py * t.c);
}
}
}

View file

@ -137,6 +137,20 @@ module Phaser {
return (this.x * this.x) + (this.y * this.y);
}
/**
* Normalize this vector.
*
* @return {Vec2} This for chaining.
*/
public normalize(): Vec2 {
var inv = (this.x != 0 || this.y != 0) ? 1 / Math.sqrt(this.x * this.x + this.y * this.y) : 0;
this.x *= inv;
this.y *= inv;
return this;
}
/**
* The dot product of two 2D vectors.
*
@ -217,6 +231,21 @@ module Phaser {
}
/**
* Adds the given vector to this vector then multiplies by the given scalar.
*
* @param {Vec2} a Reference to a source Vec2 object.
* @param {number} scalar
* @return {Vec2} This for chaining.
*/
public multiplyAddByScalar(a: Vec2, scalar: number): Vec2 {
this.x += a.x * scalar;
this.y += a.y * scalar;
return this;
}
/**
* Divide this vector by the given scalar.
*

View file

@ -1,5 +1,5 @@
/// <reference path="../Game.ts" />
/// <reference path="../math/Vec2.ts" />
/// <reference path="Vec2.ts" />
/**
* Phaser - Vec2Utils
@ -73,13 +73,48 @@ module Phaser {
}
/**
* Rotate a 2D vector by 90 degrees.
* Adds two 2D vectors together and multiplies the result by the given scalar.
*
* @param {Vec2} a Reference to a source Vec2 object.
* @param {Vec2} b Reference to a source Vec2 object.
* @param {number} s Scaling value.
* @param {Vec2} out The output Vec2 that is the result of the operation.
* @return {Vec2} A Vec2 that is the sum of the two vectors added and multiplied.
*/
static multiplyAdd(a: Vec2, b: Vec2, s: number, out?: Vec2 = new Vec2): Vec2 {
return out.setTo(a.x + b.x * s, a.y + b.y * s);
}
/**
* Return a negative vector.
*
* @param {Vec2} a Reference to a source Vec2 object.
* @param {Vec2} out The output Vec2 that is the result of the operation.
* @return {Vec2} A Vec2 that is the negative vector.
*/
static negative(a: Vec2, out?: Vec2 = new Vec2): Vec2 {
return out.setTo(-a.x, -a.y);
}
/**
* Return a perpendicular vector (90 degrees rotation)
*
* @param {Vec2} a Reference to a source Vec2 object.
* @param {Vec2} out The output Vec2 that is the result of the operation.
* @return {Vec2} A Vec2 that is the scaled vector.
*/
static perp(a: Vec2, out?: Vec2 = new Vec2): Vec2 {
return out.setTo(-a.y, a.x);
}
/**
* Return a perpendicular vector (-90 degrees rotation)
*
* @param {Vec2} a Reference to a source Vec2 object.
* @param {Vec2} out The output Vec2 that is the result of the operation.
* @return {Vec2} A Vec2 that is the scaled vector.
*/
static rperp(a: Vec2, out?: Vec2 = new Vec2): Vec2 {
return out.setTo(a.y, -a.x);
}
@ -253,12 +288,30 @@ module Phaser {
* @param {Vec2} out The output Vec2 that is the result of the operation.
* @return {Vec2} A Vec2.
*/
static rotate(a: Vec2, b: Vec2, theta: number, out?: Vec2 = new Vec2): Vec2 {
static rotateAroundOrigin(a: Vec2, b: Vec2, theta: number, out?: Vec2 = new Vec2): Vec2 {
var x = a.x - b.x;
var y = a.y - b.y;
return out.setTo(x * Math.cos(theta) - y * Math.sin(theta) + b.x, x * Math.sin(theta) + y * Math.cos(theta) + b.y);
}
/**
* Rotate a 2D vector to the given angle (theta).
*
* @param {Vec2} a Reference to a source Vec2 object.
* @param {Vec2} b Reference to a source Vec2 object.
* @param {Number} theta The angle of rotation in radians.
* @param {Vec2} out The output Vec2 that is the result of the operation.
* @return {Vec2} A Vec2.
*/
static rotate(a: Vec2, theta: number, out?: Vec2 = new Vec2): Vec2 {
var c = Math.cos(theta);
var s = Math.sin(theta);
return out.setTo(a.x * c - a.y * s, a.x * s + a.y * c);
}
/**
* Clone a 2D vector.
*

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,589 @@
/// <reference path="../../math/Vec2.ts" />
/// <reference path="../../geom/Point.ts" />
/// <reference path="../../math/Vec2Utils.ts" />
/// <reference path="../../math/Transform.ts" />
/// <reference path="../../math/TransformUtils.ts" />
/// <reference path="Manager.ts" />
/// <reference path="joints/Joint.ts" />
/// <reference path="Bounds.ts" />
/// <reference path="Space.ts" />
/// <reference path="shapes/IShape.ts" />
/**
* Phaser - Advanced Physics - Body
*
* Based on the work Ju Hyung Lee started in JS PhyRus.
*/
module Phaser.Physics.Advanced {
export class Body {
constructor(sprite: Phaser.Sprite, type: number, x?: number = 0, y?: number = 0) {
this.id = Phaser.Physics.Advanced.Manager.bodyCounter++;
this.name = 'body' + this.id;
this.type = type;
if (sprite)
{
this.sprite = sprite;
this.game = sprite.game;
this.position = new Phaser.Vec2(sprite.x, sprite.y);
this.angle = sprite.rotation;
}
else
{
this.position = new Phaser.Vec2(x, y);
this.angle = 0;
}
this.transform = new Phaser.Transform(this.position, this.angle);
this.centroid = new Phaser.Vec2;
this.velocity = new Phaser.Vec2;
this.force = new Phaser.Vec2;
this.angularVelocity = 0;
this.torque = 0;
this.linearDamping = 0;
this.angularDamping = 0;
this.sleepTime = 0;
this.awaked = false;
this.shapes = [];
this.joints = [];
this.jointHash = {};
this.bounds = new Bounds;
this.fixedRotation = false;
this.categoryBits = 0x0001;
this.maskBits = 0xFFFF;
this.stepCount = 0;
}
/**
* Reference to Phaser.Game
*/
public game: Game;
/**
* Reference to the parent Sprite
*/
public sprite: Phaser.Sprite;
/**
* The Body ID
*/
public id: number;
/**
* The Body name
*/
public name: string;
/**
* The type of Body (disabled, dynamic, static or kinematic)
* Disabled = skips all physics operations / tests (default)
* Dynamic = gives and receives impacts
* Static = gives but doesn't receive impacts, cannot be moved by physics
* Kinematic = gives impacts, but never receives, can be moved by physics
* @type {number}
*/
public type: number;
public angle: number;
// Local to world transform
public transform: Phaser.Transform;
// Local center of mass
public centroid: Phaser.Vec2;
// World position of centroid
public position: Phaser.Vec2;
// Velocity
public velocity: Phaser.Vec2;
// Force
public force: Phaser.Vec2;
// Angular velocity
public angularVelocity: number;
// Torque
public torque: number;
// Linear damping
public linearDamping: number;
// Angular damping
public angularDamping: number;
// Sleep time
public sleepTime: number;
// Awaked
public awaked: bool;
// Shapes
public shapes: IShape[] = [];
// Joints
public joints: IJoint[] = [];
public jointHash = {};
// Bounds of all shapes
public bounds: Bounds;
public fixedRotation = false;
public categoryBits = 0x0001;
public maskBits = 0xFFFF;
public stepCount = 0;
public space: Space;
public duplicate() {
//console.log('body duplicate called');
//var body = new Body(this.type, this.transform.t, this.angle);
//for (var i = 0; i < this.shapes.length; i++)
//{
// body.addShape(this.shapes[i].duplicate());
//}
//body.resetMassData();
//return body;
}
public get isDisabled(): bool {
return this.type == Phaser.Types.BODY_DISABLED ? true : false;
}
public get isStatic(): bool {
return this.type == Phaser.Types.BODY_STATIC ? true : false;
}
public get isKinetic(): bool {
return this.type == Phaser.Types.BODY_KINETIC ? true : false;
}
public get isDynamic(): bool {
return this.type == Phaser.Types.BODY_DYNAMIC ? true : false;
}
public setType(type: number) {
if (type == this.type)
{
return;
}
this.force.setTo(0, 0);
this.velocity.setTo(0, 0);
this.torque = 0;
this.angularVelocity = 0;
this.type = type;
this.awake(true);
}
public addShape(shape) {
// Check not already part of this body
shape.body = this;
this.shapes.push(shape);
return shape;
}
public removeShape(shape) {
var index = this.shapes.indexOf(shape);
if (index != -1)
{
this.shapes.splice(index, 1);
shape.body = undefined;
}
}
public mass: number;
public massInverted: number;
public inertia: number;
public inertiaInverted: number;
private setMass(mass) {
this.mass = mass;
this.massInverted = mass > 0 ? 1 / mass : 0;
}
private setInertia(inertia) {
this.inertia = inertia;
this.inertiaInverted = inertia > 0 ? 1 / inertia : 0;
}
public setTransform(pos, angle) {
this.transform.setTo(pos, angle);
// inject the transform into this.position
Phaser.TransformUtils.transform(this.transform, this.centroid, this.position);
//this.position.copyFrom(this.transform.transform(this.centroid));
this.angle = angle;
}
public syncTransform() {
this.transform.setRotation(this.angle);
//var rotc: Phaser.Vec2 = this.transform.rotate(this.centroid);
//var sub: Phaser.Vec2 = Phaser.Vec2Utils.subtract(this.position, rotc);
//this.transform.setPosition(sub);
// this.transform.setPosition(vec2.sub(this.position, this.transform.rotate(this.centroid)));
//Phaser.Vec2Utils.subtract(this.position, this.transform.rotate(this.centroid), this.transform.t);
// OPTIMISE: Creating new vector
Phaser.Vec2Utils.subtract(this.position, Phaser.TransformUtils.rotate(this.transform, this.centroid), this.transform.t);
}
public getWorldPoint(p:Phaser.Vec2) {
// OPTIMISE: Creating new vector
return Phaser.TransformUtils.transform(this.transform, p);
}
public getWorldVector(v) {
// OPTIMISE: Creating new vector
return Phaser.TransformUtils.rotate(this.transform, v);
}
public getLocalPoint(p) {
// OPTIMISE: Creating new vector
return Phaser.TransformUtils.untransform(this.transform, p);
}
public getLocalVector(v) {
// OPTIMISE: Creating new vector
return Phaser.TransformUtils.unrotate(this.transform, v);
}
public setFixedRotation(flag) {
this.fixedRotation = flag;
this.resetMassData();
}
public resetMassData() {
this.centroid.setTo(0, 0);
this.mass = 0;
this.massInverted = 0;
this.inertia = 0;
this.inertiaInverted = 0;
if (this.isDynamic == false)
{
Phaser.TransformUtils.transform(this.transform, this.centroid, this.position);
//this.position.copyFrom(this.transform.transform(this.centroid));
return;
}
var totalMassCentroid = new Phaser.Vec2(0, 0);
var totalMass = 0;
var totalInertia = 0;
for (var i = 0; i < this.shapes.length; i++)
{
var shape = this.shapes[i];
var centroid = shape.centroid();
var mass = shape.area() * shape.density;
var inertia = shape.inertia(mass);
//console.log('rmd', centroid, shape);
totalMassCentroid.multiplyAddByScalar(centroid, mass);
totalMass += mass;
totalInertia += inertia;
}
//this.centroid.copy(vec2.scale(totalMassCentroid, 1 / totalMass));
Phaser.Vec2Utils.scale(totalMassCentroid, 1 / totalMass, this.centroid);
this.setMass(totalMass);
if (!this.fixedRotation)
{
//this.setInertia(totalInertia - totalMass * vec2.dot(this.centroid, this.centroid));
this.setInertia(totalInertia - totalMass * Phaser.Vec2Utils.dot(this.centroid, this.centroid));
}
//console.log("mass = " + this.m + " inertia = " + this.i);
// Move center of mass
var oldPosition: Phaser.Vec2 = Phaser.Vec2Utils.clone(this.position);
//this.position.copyFrom(this.transform.transform(this.centroid));
Phaser.TransformUtils.transform(this.transform, this.centroid, this.position);
// Update center of mass velocity
//this.velocity.mad(vec2.perp(vec2.sub(this.position, old_p)), this.angularVelocity);
oldPosition.subtract(this.position);
this.velocity.multiplyAddByScalar(Phaser.Vec2Utils.perp(oldPosition, oldPosition), this.angularVelocity);
}
public resetJointAnchors() {
for (var i = 0; i < this.joints.length; i++)
{
var joint = this.joints[i];
if (!joint)
{
continue;
}
var anchor1 = joint.getWorldAnchor1();
var anchor2 = joint.getWorldAnchor2();
joint.setWorldAnchor1(anchor1);
joint.setWorldAnchor2(anchor2);
}
}
public cacheData() {
//console.log('Body cacheData', this.name, 'len', this.shapes.length);
this.bounds.clear();
for (var i = 0; i < this.shapes.length; i++)
{
var shape = this.shapes[i];
shape.cacheData(this.transform);
this.bounds.addBounds(shape.bounds);
}
}
private _tempVec2: Phaser.Vec2 = new Phaser.Vec2;
public updateVelocity(gravity, dt, damping) {
// this.velocity = vec2.mad(this.velocity, vec2.mad(gravity, this.force, this.massInverted), dt);
Phaser.Vec2Utils.multiplyAdd(gravity, this.force, this.massInverted, this._tempVec2);
Phaser.Vec2Utils.multiplyAdd(this.velocity, this._tempVec2, dt, this.velocity);
this.angularVelocity = this.angularVelocity + this.torque * this.inertiaInverted * dt;
// Apply damping.
// ODE: dv/dt + c * v = 0
// Solution: v(t) = v0 * exp(-c * t)
// Time step: v(t + dt) = v0 * exp(-c * (t + dt)) = v0 * exp(-c * t) * exp(-c * dt) = v * exp(-c * dt)
// v2 = exp(-c * dt) * v1
// Taylor expansion:
// v2 = (1.0f - c * dt) * v1
this.velocity.scale(this.game.math.clamp(1 - dt * (damping + this.linearDamping), 0, 1));
this.angularVelocity *= this.game.math.clamp(1 - dt * (damping + this.angularDamping), 0, 1);
this.force.setTo(0, 0);
this.torque = 0;
}
public updatePosition(dt) {
//console.log('body update pos', this.position.y);
//console.log('pre add temp', this._tempVec2.y);
//this.position.addself(vec2.scale(this.velocity, dt));
this.position.add(Phaser.Vec2Utils.scale(this.velocity, dt, this._tempVec2));
//console.log('post add temp', this._tempVec2.y);
//console.log('post add', this.position.y);
this.angle += this.angularVelocity * dt;
}
public resetForce() {
this.force.setTo(0, 0);
this.torque = 0;
}
public applyForce(force, p) {
if (this.isDynamic == false)
{
return;
}
if (this.isAwake == false)
{
this.awake(true);
}
this.force.add(force);
// this.f.addself(force);
// this.torque += vec2.cross(vec2.sub(p, this.p), force);
Phaser.Vec2Utils.subtract(p, this.position, this._tempVec2);
this.torque += Phaser.Vec2Utils.cross(this._tempVec2, force);
}
public applyForceToCenter(force) {
if (this.isDynamic == false)
{
return;
}
if (this.isAwake == false)
{
this.awake(true);
}
this.force.add(force);
}
public applyTorque(torque) {
if (this.isDynamic == false)
{
return;
}
if (this.isAwake == false)
{
this.awake(true);
}
this.torque += torque;
}
public applyLinearImpulse(impulse, p) {
if (this.isDynamic == false)
{
return;
}
if (this.isAwake == false)
{
this.awake(true);
}
this.velocity.multiplyAddByScalar(impulse, this.massInverted);
// this.angularVelocity += vec2.cross(vec2.sub(p, this.position), impulse) * this.inertiaInverted;
Phaser.Vec2Utils.subtract(p, this.position, this._tempVec2);
this.angularVelocity += Phaser.Vec2Utils.cross(this._tempVec2, impulse) * this.inertiaInverted;
}
public applyAngularImpulse(impulse: number) {
if (this.isDynamic == false)
{
return;
}
if (this.isAwake == false)
{
this.awake(true);
}
this.angularVelocity += impulse * this.inertiaInverted;
}
public kineticEnergy() {
var vsq = this.velocity.dot(this.velocity);
var wsq = this.angularVelocity * this.angularVelocity;
return 0.5 * (this.mass * vsq + this.inertia * wsq);
}
public get isAwake(): bool {
return this.awaked;
}
public awake(flag) {
this.awaked = flag;
if (flag)
{
this.sleepTime = 0;
}
else
{
this.velocity.setTo(0, 0);
this.angularVelocity = 0;
this.force.setTo(0, 0);
this.torque = 0;
}
}
public isCollidable(other) {
if (this == other)
{
return false;
}
if (this.isDynamic == false && other.isDynamic == false)
{
return false;
}
if (!(this.maskBits & other.categoryBits) || !(other.maskBits & this.categoryBits))
{
return false;
}
for (var i = 0; i < this.joints.length; i++)
{
var joint = this.joints[i];
if (!joint)
{
continue;
}
if (!joint.collideConnected && other.jointHash[joint.id] != undefined)
{
return false;
}
}
return true;
}
}
}

View file

@ -0,0 +1,173 @@
/// <reference path="../../Game.ts" />
/// <reference path="../../math/Vec2.ts" />
/// <reference path="../../math/Vec2Utils.ts" />
/**
* Phaser - 2D AABB
*
* A 2D AABB object
*/
module Phaser.Physics.Advanced {
export class Bounds {
/**
* Creates a new 2D AABB object.
* @class Bounds
* @constructor
* @return {Bounds} This object
**/
constructor(mins?: Phaser.Vec2 = null, maxs?: Phaser.Vec2 = null) {
if (mins)
{
this.mins = Phaser.Vec2Utils.clone(mins);
}
else
{
this.mins = new Phaser.Vec2(999999, 999999);
}
if (maxs)
{
this.maxs = Phaser.Vec2Utils.clone(maxs);
}
else
{
this.maxs = new Phaser.Vec2(999999, 999999);
}
}
public mins: Phaser.Vec2;
public maxs: Phaser.Vec2;
public toString() {
return ["mins:", this.mins.toString(), "maxs:", this.maxs.toString()].join(" ");
}
public setTo(mins: Phaser.Vec2, maxs: Phaser.Vec2) {
this.mins.setTo(mins.x, mins.y);
this.maxs.setTo(maxs.x, maxs.y);
}
public copy(b: Bounds): Bounds {
this.mins.copyFrom(b.mins);
this.maxs.copyFrom(b.maxs);
return this;
}
public clear(): Bounds {
this.mins.setTo(999999, 999999);
this.maxs.setTo(-999999, -999999);
return this;
}
public isEmpty(): bool {
return (this.mins.x > this.maxs.x || this.mins.y > this.maxs.y);
}
/*
public getCenter() {
return vec2.scale(vec2.add(this.mins, this.maxs), 0.5);
}
public getExtent() {
return vec2.scale(vec2.sub(this.maxs, this.mins), 0.5);
}
*/
public getPerimeter(): number {
return (this.maxs.x - this.mins.x + this.maxs.y - this.mins.y) * 2;
}
public addPoint(p: Phaser.Vec2): Bounds {
if (this.mins.x > p.x) this.mins.x = p.x;
if (this.maxs.x < p.x) this.maxs.x = p.x;
if (this.mins.y > p.y) this.mins.y = p.y;
if (this.maxs.y < p.y) this.maxs.y = p.y;
return this;
}
public addBounds(b: Bounds): Bounds {
if (this.mins.x > b.mins.x) this.mins.x = b.mins.x;
if (this.maxs.x < b.maxs.x) this.maxs.x = b.maxs.x;
if (this.mins.y > b.mins.y) this.mins.y = b.mins.y;
if (this.maxs.y < b.maxs.y) this.maxs.y = b.maxs.y;
return this;
}
public addBounds2(mins, maxs) {
if (this.mins.x > mins.x) this.mins.x = mins.x;
if (this.maxs.x < maxs.x) this.maxs.x = maxs.x;
if (this.mins.y > mins.y) this.mins.y = mins.y;
if (this.maxs.y < maxs.y) this.maxs.y = maxs.y;
return this;
}
public addExtents(center: Phaser.Vec2, extent_x: number, extent_y: number): Bounds {
if (this.mins.x > center.x - extent_x) this.mins.x = center.x - extent_x;
if (this.maxs.x < center.x + extent_x) this.maxs.x = center.x + extent_x;
if (this.mins.y > center.y - extent_y) this.mins.y = center.y - extent_y;
if (this.maxs.y < center.y + extent_y) this.maxs.y = center.y + extent_y;
return this;
}
public expand(ax: number, ay: number): Bounds {
this.mins.x -= ax;
this.mins.y -= ay;
this.maxs.x += ax;
this.maxs.y += ay;
return this;
}
public containPoint(p: Phaser.Vec2): bool {
if (p.x < this.mins.x || p.x > this.maxs.x || p.y < this.mins.y || p.y > this.maxs.y)
{
return false;
}
return true;
}
public intersectsBounds(b: Bounds): bool {
if (this.mins.x > b.maxs.x || this.maxs.x < b.mins.x || this.mins.y > b.maxs.y || this.maxs.y < b.mins.y)
{
return false;
}
return true;
}
public static expand(b: Bounds, ax, ay) {
var b = new Bounds(b.mins, b.maxs);
b.expand(ax, ay);
return b;
}
}
}

View file

@ -0,0 +1,558 @@
/// <reference path="../../math/Vec2.ts" />
/// <reference path="../../geom/Point.ts" />
/// <reference path="../../math/Vec2Utils.ts" />
/// <reference path="shapes/Shape.ts" />
/// <reference path="shapes/Circle.ts" />
/// <reference path="shapes/Poly.ts" />
/// <reference path="shapes/Segment.ts" />
/// <reference path="Manager.ts" />
/// <reference path="Body.ts" />
/// <reference path="Contact.ts" />
/**
* Phaser - Advanced Physics - Collision Handlers
*
* Based on the work Ju Hyung Lee started in JS PhyRus.
*/
module Phaser.Physics.Advanced {
export class Collision {
constructor() {
}
public collide(a, b, contacts: Contact[]) {
// Circle (a is the circle)
if (a.type == Manager.SHAPE_TYPE_CIRCLE)
{
if (b.type == Manager.SHAPE_TYPE_CIRCLE)
{
return this.circle2Circle(a, b, contacts);
}
else if (b.type == Manager.SHAPE_TYPE_SEGMENT)
{
return this.circle2Segment(a, b, contacts);
}
else if (b.type == Manager.SHAPE_TYPE_POLY)
{
return this.circle2Poly(a, b, contacts);
}
}
// Segment (a is the segment)
if (a.type == Manager.SHAPE_TYPE_SEGMENT)
{
if (b.type == Manager.SHAPE_TYPE_CIRCLE)
{
return this.circle2Segment(b, a, contacts);
}
else if (b.type == Manager.SHAPE_TYPE_SEGMENT)
{
return this.segment2Segment(a, b, contacts);
}
else if (b.type == Manager.SHAPE_TYPE_POLY)
{
return this.segment2Poly(a, b, contacts);
}
}
// Poly (a is the poly)
if (a.type == Manager.SHAPE_TYPE_POLY)
{
if (b.type == Manager.SHAPE_TYPE_CIRCLE)
{
return this.circle2Poly(b, a, contacts);
}
else if (b.type == Manager.SHAPE_TYPE_SEGMENT)
{
return this.segment2Poly(b, a, contacts);
}
else if (b.type == Manager.SHAPE_TYPE_POLY)
{
return this.poly2Poly(a, b, contacts);
}
}
}
private _circle2Circle(c1, r1, c2, r2, contactArr) {
var rmax = r1 + r2;
var t: Phaser.Vec2 = new Phaser.Vec2;
//var t = vec2.sub(c2, c1);
Phaser.Vec2Utils.subtract(c2, c1, t);
var distsq = t.lengthSq();
if (distsq > rmax * rmax)
{
return 0;
}
var dist = Math.sqrt(distsq);
var p: Phaser.Vec2 = new Phaser.Vec2;
Phaser.Vec2Utils.multiplyAdd(c1, t, 0.5 + (r1 - r2) * 0.5 / dist, p);
//var p = vec2.mad(c1, t, 0.5 + (r1 - r2) * 0.5 / dist);
var n: Phaser.Vec2 = new Phaser.Vec2;
//var n = (dist != 0) ? vec2.scale(t, 1 / dist) : vec2.zero;
if (dist != 0)
{
Phaser.Vec2Utils.scale(t, 1 / dist, n);
}
var d = dist - rmax;
contactArr.push(new Contact(p, n, d, 0));
return 1;
}
public circle2Circle(circ1: Phaser.Physics.Advanced.Shapes.Circle, circ2: Phaser.Physics.Advanced.Shapes.Circle, contactArr: Contact[]) {
return this._circle2Circle(circ1.tc, circ1.radius, circ2.tc, circ2.radius, contactArr);
}
public circle2Segment(circ: Phaser.Physics.Advanced.Shapes.Circle, seg: Phaser.Physics.Advanced.Shapes.Segment, contactArr: Contact[]) {
var rsum = circ.radius + seg.radius;
// Normal distance from segment
var dn = Phaser.Vec2Utils.dot(circ.tc, seg.tn) - Phaser.Vec2Utils.dot(seg.ta, seg.tn);
var dist = (dn < 0 ? dn * -1 : dn) - rsum;
if (dist > 0)
{
return 0;
}
// Tangential distance along segment
var dt = Phaser.Vec2Utils.cross(circ.tc, seg.tn);
var dtMin = Phaser.Vec2Utils.cross(seg.ta, seg.tn);
var dtMax = Phaser.Vec2Utils.cross(seg.tb, seg.tn);
if (dt < dtMin)
{
if (dt < dtMin - rsum)
{
return 0;
}
return this._circle2Circle(circ.tc, circ.radius, seg.ta, seg.radius, contactArr);
}
else if (dt > dtMax)
{
if (dt > dtMax + rsum)
{
return 0;
}
return this._circle2Circle(circ.tc, circ.radius, seg.tb, seg.radius, contactArr);
}
var n: Phaser.Vec2 = new Phaser.Vec2;
if (dn > 0)
{
n.copyFrom(seg.tn);
}
else
{
Phaser.Vec2Utils.negative(seg.tn, n);
}
//var n = (dn > 0) ? seg.tn : vec2.neg(seg.tn);
var c1: Phaser.Vec2 = new Phaser.Vec2;
Phaser.Vec2Utils.multiplyAdd(circ.tc, n, -(circ.radius + dist * 0.5), c1);
var c2: Phaser.Vec2 = new Phaser.Vec2;
Phaser.Vec2Utils.negative(n, c2);
contactArr.push(new Contact(c1, c2, dist, 0));
//contactArr.push(new Contact(vec2.mad(circ.tc, n, -(circ.r + dist * 0.5)), vec2.neg(n), dist, 0));
return 1;
}
public circle2Poly(circ: Phaser.Physics.Advanced.Shapes.Circle, poly: Phaser.Physics.Advanced.Shapes.Poly, contactArr: Contact[]) {
var minDist = -999999;
var minIdx = -1;
for (var i = 0; i < poly.verts.length; i++)
{
var plane = poly.tplanes[i];
var dist = Phaser.Vec2Utils.dot(circ.tc, plane.n) - plane.d - circ.radius;
if (dist > 0)
{
return 0;
}
else if (dist > minDist)
{
minDist = dist;
minIdx = i;
}
}
var n = poly.tplanes[minIdx].n;
var a = poly.tverts[minIdx];
var b = poly.tverts[(minIdx + 1) % poly.verts.length];
var dta = Phaser.Vec2Utils.cross(a, n);
var dtb = Phaser.Vec2Utils.cross(b, n);
var dt = Phaser.Vec2Utils.cross(circ.tc, n);
if (dt > dta)
{
return this._circle2Circle(circ.tc, circ.radius, a, 0, contactArr);
}
else if (dt < dtb)
{
return this._circle2Circle(circ.tc, circ.radius, b, 0, contactArr);
}
var c1: Phaser.Vec2 = new Phaser.Vec2;
Phaser.Vec2Utils.multiplyAdd(circ.tc, n, -(circ.radius + minDist * 0.5), c1);
var c2: Phaser.Vec2 = new Phaser.Vec2;
Phaser.Vec2Utils.negative(n, c2);
contactArr.push(new Contact(c1, c2, minDist, 0));
//contactArr.push(new Contact(vec2.mad(circ.tc, n, -(circ.r + minDist * 0.5)), vec2.neg(n), minDist, 0));
return 1;
}
public segmentPointDistanceSq(seg: Phaser.Physics.Advanced.Shapes.Segment, p) {
var w: Phaser.Vec2 = new Phaser.Vec2;
var d: Phaser.Vec2 = new Phaser.Vec2;
Phaser.Vec2Utils.subtract(p, seg.ta, w);
Phaser.Vec2Utils.subtract(seg.tb, seg.ta, d);
//var w = vec2.sub(p, seg.ta);
//var d = vec2.sub(seg.tb, seg.ta);
var proj = w.dot(d);
if (proj <= 0)
{
return w.dot(w);
}
var vsq = d.dot(d);
if (proj >= vsq)
{
return w.dot(w) - 2 * proj + vsq;
}
return w.dot(w) - proj * proj / vsq;
}
// FIXME and optimise me lots!!!
public segment2Segment(seg1: Phaser.Physics.Advanced.Shapes.Segment, seg2: Phaser.Physics.Advanced.Shapes.Segment, contactArr: Contact[]) {
var d = [];
d[0] = this.segmentPointDistanceSq(seg1, seg2.ta);
d[1] = this.segmentPointDistanceSq(seg1, seg2.tb);
d[2] = this.segmentPointDistanceSq(seg2, seg1.ta);
d[3] = this.segmentPointDistanceSq(seg2, seg1.tb);
var idx1 = d[0] < d[1] ? 0 : 1;
var idx2 = d[2] < d[3] ? 2 : 3;
var idxm = d[idx1] < d[idx2] ? idx1 : idx2;
var s, t;
var u = Phaser.Vec2Utils.subtract(seg1.tb, seg1.ta);
var v = Phaser.Vec2Utils.subtract(seg2.tb, seg2.ta);
switch (idxm)
{
case 0:
s = Phaser.Vec2Utils.dot(Phaser.Vec2Utils.subtract(seg2.ta, seg1.ta), u) / Phaser.Vec2Utils.dot(u, u);
s = s < 0 ? 0 : (s > 1 ? 1 : s);
t = 0;
break;
case 1:
s = Phaser.Vec2Utils.dot(Phaser.Vec2Utils.subtract(seg2.tb, seg1.ta), u) / Phaser.Vec2Utils.dot(u, u);
s = s < 0 ? 0 : (s > 1 ? 1 : s);
t = 1;
break;
case 2:
s = 0;
t = Phaser.Vec2Utils.dot(Phaser.Vec2Utils.subtract(seg1.ta, seg2.ta), v) / Phaser.Vec2Utils.dot(v, v);
t = t < 0 ? 0 : (t > 1 ? 1 : t);
break;
case 3:
s = 1;
t = Phaser.Vec2Utils.dot(Phaser.Vec2Utils.subtract(seg1.tb, seg2.ta), v) / Phaser.Vec2Utils.dot(v, v);
t = t < 0 ? 0 : (t > 1 ? 1 : t);
break;
}
var minp1 = Phaser.Vec2Utils.multiplyAdd(seg1.ta, u, s);
var minp2 = Phaser.Vec2Utils.multiplyAdd(seg2.ta, v, t);
return this._circle2Circle(minp1, seg1.radius, minp2, seg2.radius, contactArr);
}
// Identify vertexes that have penetrated the segment.
public findPointsBehindSeg(contactArr: Contact[], seg: Phaser.Physics.Advanced.Shapes.Segment, poly: Phaser.Physics.Advanced.Shapes.Poly, dist: number, coef: number) {
var dta = Phaser.Vec2Utils.cross(seg.tn, seg.ta);
var dtb = Phaser.Vec2Utils.cross(seg.tn, seg.tb);
var n: Phaser.Vec2 = new Phaser.Vec2;
Phaser.Vec2Utils.scale(seg.tn, coef, n);
//var n = vec2.scale(seg.tn, coef);
for (var i = 0; i < poly.verts.length; i++)
{
var v = poly.tverts[i];
if (Phaser.Vec2Utils.dot(v, n) < Phaser.Vec2Utils.dot(seg.tn, seg.ta) * coef + seg.radius)
{
var dt = Phaser.Vec2Utils.cross(seg.tn, v);
if (dta >= dt && dt >= dtb)
{
contactArr.push(new Contact(v, n, dist, (poly.id << 16) | i));
}
}
}
}
public segment2Poly(seg: Phaser.Physics.Advanced.Shapes.Segment, poly: Phaser.Physics.Advanced.Shapes.Poly, contactArr: Contact[]) {
var seg_td = Phaser.Vec2Utils.dot(seg.tn, seg.ta);
var seg_d1 = poly.distanceOnPlane(seg.tn, seg_td) - seg.radius;
if (seg_d1 > 0)
{
return 0;
}
var n: Phaser.Vec2 = new Phaser.Vec2;
Phaser.Vec2Utils.negative(seg.tn, n);
var seg_d2 = poly.distanceOnPlane(n, -seg_td) - seg.radius;
//var seg_d2 = poly.distanceOnPlane(vec2.neg(seg.tn), -seg_td) - seg.r;
if (seg_d2 > 0)
{
return 0;
}
var poly_d = -999999;
var poly_i = -1;
for (var i = 0; i < poly.verts.length; i++)
{
var plane = poly.tplanes[i];
var dist = seg.distanceOnPlane(plane.n, plane.d);
if (dist > 0)
{
return 0;
}
if (dist > poly_d)
{
poly_d = dist;
poly_i = i;
}
}
var poly_n: Phaser.Vec2 = new Phaser.Vec2;
Phaser.Vec2Utils.negative(poly.tplanes[poly_i].n, poly_n);
//var poly_n = vec2.neg(poly.tplanes[poly_i].n);
var va: Phaser.Vec2 = new Phaser.Vec2;
Phaser.Vec2Utils.multiplyAdd(seg.ta, poly_n, seg.radius, va);
//var va = vec2.mad(seg.ta, poly_n, seg.r);
var vb: Phaser.Vec2 = new Phaser.Vec2;
Phaser.Vec2Utils.multiplyAdd(seg.tb, poly_n, seg.radius, vb);
//var vb = vec2.mad(seg.tb, poly_n, seg.r);
if (poly.containPoint(va))
{
contactArr.push(new Contact(va, poly_n, poly_d, (seg.id << 16) | 0));
}
if (poly.containPoint(vb))
{
contactArr.push(new Contact(vb, poly_n, poly_d, (seg.id << 16) | 1));
}
// Floating point precision problems here.
// This will have to do for now.
poly_d -= 0.1
if (seg_d1 >= poly_d || seg_d2 >= poly_d)
{
if (seg_d1 > seg_d2)
{
this.findPointsBehindSeg(contactArr, seg, poly, seg_d1, 1);
}
else
{
this.findPointsBehindSeg(contactArr, seg, poly, seg_d2, -1);
}
}
// If no other collision points are found, try colliding endpoints.
if (contactArr.length == 0)
{
var poly_a = poly.tverts[poly_i];
var poly_b = poly.tverts[(poly_i + 1) % poly.verts.length];
if (this._circle2Circle(seg.ta, seg.radius, poly_a, 0, contactArr))
{
return 1;
}
if (this._circle2Circle(seg.tb, seg.radius, poly_a, 0, contactArr))
{
return 1;
}
if (this._circle2Circle(seg.ta, seg.radius, poly_b, 0, contactArr))
{
return 1;
}
if (this._circle2Circle(seg.tb, seg.radius, poly_b, 0, contactArr))
{
return 1;
}
}
return contactArr.length;
}
// Find the minimum separating axis for the given poly and plane list.
public findMSA(poly: Phaser.Physics.Advanced.Shapes.Poly, planes, num: number) {
var min_dist = -999999;
var min_index = -1;
for (var i = 0; i < num; i++)
{
var dist = poly.distanceOnPlane(planes[i].n, planes[i].d);
if (dist > 0)
{
// no collision
return { dist: 0, index: -1 };
}
else if (dist > min_dist)
{
min_dist = dist;
min_index = i;
}
}
// new object - see what we can do here
return { dist: min_dist, index: min_index };
}
public findVertsFallback(contactArr: Contact[], poly1: Phaser.Physics.Advanced.Shapes.Poly, poly2: Phaser.Physics.Advanced.Shapes.Poly, n, dist: number) {
var num = 0;
for (var i = 0; i < poly1.verts.length; i++)
{
var v = poly1.tverts[i];
if (poly2.containPointPartial(v, n))
{
contactArr.push(new Contact(v, n, dist, (poly1.id << 16) | i));
num++;
}
}
for (var i = 0; i < poly2.verts.length; i++)
{
var v = poly2.tverts[i];
if (poly1.containPointPartial(v, n))
{
contactArr.push(new Contact(v, n, dist, (poly2.id << 16) | i));
num++;
}
}
return num;
}
// Find the overlapped vertices.
public findVerts(contactArr: Contact[], poly1: Phaser.Physics.Advanced.Shapes.Poly, poly2: Phaser.Physics.Advanced.Shapes.Poly, n, dist: number) {
var num = 0;
for (var i = 0; i < poly1.verts.length; i++)
{
var v = poly1.tverts[i];
if (poly2.containPoint(v))
{
contactArr.push(new Contact(v, n, dist, (poly1.id << 16) | i));
num++;
}
}
for (var i = 0; i < poly2.verts.length; i++)
{
var v = poly2.tverts[i];
if (poly1.containPoint(v))
{
contactArr.push(new Contact(v, n, dist, (poly2.id << 16) | i));
num++;
}
}
return num > 0 ? num : this.findVertsFallback(contactArr, poly1, poly2, n, dist);
}
public poly2Poly(poly1: Phaser.Physics.Advanced.Shapes.Poly, poly2: Phaser.Physics.Advanced.Shapes.Poly, contactArr: Contact[]) {
var msa1 = this.findMSA(poly2, poly1.tplanes, poly1.verts.length);
if (msa1.index == -1)
{
return 0;
}
var msa2 = this.findMSA(poly1, poly2.tplanes, poly2.verts.length);
if (msa2.index == -1)
{
return 0;
}
// Penetration normal direction shoud be from poly1 to poly2
if (msa1.dist > msa2.dist)
{
return this.findVerts(contactArr, poly1, poly2, poly1.tplanes[msa1.index].n, msa1.dist);
}
return this.findVerts(contactArr, poly1, poly2, Phaser.Vec2Utils.negative(poly2.tplanes[msa2.index].n), msa2.dist);
}
}
}

View file

@ -0,0 +1,62 @@
/// <reference path="../../math/Vec2.ts" />
/// <reference path="../../math/Vec2Utils.ts" />
/// <reference path="Manager.ts" />
/// <reference path="Body.ts" />
/// <reference path="shapes/Shape.ts" />
/**
* Phaser - Advanced Physics - Contact
*
* Based on the work Ju Hyung Lee started in JS PhyRus.
*/
module Phaser.Physics.Advanced {
export class Contact {
constructor(p, n, d, hash) {
this.hash = hash;
this.point = p;
this.normal = n;
this.depth = d;
this.lambdaNormal = 0;
this.lambdaTangential = 0;
this.r1 = new Phaser.Vec2;
this.r2 = new Phaser.Vec2;
this.r1_local = new Phaser.Vec2;
this.r2_local = new Phaser.Vec2;
}
public hash;
// Linear velocities at contact point
public r1: Phaser.Vec2;
public r2: Phaser.Vec2;
public r1_local: Phaser.Vec2;
public r2_local: Phaser.Vec2;
// Bounce velocity
public bounce: number;
public emn: number;
public emt: number;
// Contact point
public point;
// Contact normal (toward shape2)
public normal: Phaser.Vec2;
// Penetration depth (d < 0)
public depth;
// Accumulated normal constraint impulse
public lambdaNormal;
// Accumulated tangential constraint impulse
public lambdaTangential;
}
}

View file

@ -0,0 +1,359 @@
/// <reference path="../../math/Vec2.ts" />
/// <reference path="../../geom/Point.ts" />
/// <reference path="../../math/Vec2Utils.ts" />
/// <reference path="Manager.ts" />
/// <reference path="Body.ts" />
/// <reference path="shapes/Shape.ts" />
/// <reference path="Contact.ts" />
/**
* Phaser - Advanced Physics - ContactSolver
*
* Based on the work Ju Hyung Lee started in JS PhyRus.
*/
//-------------------------------------------------------------------------------------------------
// Contact Constraint
//
// Non-penetration constraint:
// C = dot(p2 - p1, n)
// Cdot = dot(v2 - v1, n)
// J = [ -n, -cross(r1, n), n, cross(r2, n) ]
//
// impulse = JT * lambda = [ -n * lambda, -cross(r1, n) * lambda, n * lambda, cross(r1, n) * lambda ]
//
// Friction constraint:
// C = dot(p2 - p1, t)
// Cdot = dot(v2 - v1, t)
// J = [ -t, -cross(r1, t), t, cross(r2, t) ]
//
// impulse = JT * lambda = [ -t * lambda, -cross(r1, t) * lambda, t * lambda, cross(r1, t) * lambda ]
//
// NOTE: lambda is an impulse in constraint space.
//-------------------------------------------------------------------------------------------------
module Phaser.Physics.Advanced {
export class ContactSolver {
constructor(shape1, shape2) {
//console.log('ContactSolver super');
this.shape1 = shape1;
this.shape2 = shape2;
this.contacts = [];
this.elasticity = 1;
this.friction = 1;
}
public shape1;
public shape2;
// Contact list
public contacts: Contact[];
// Coefficient of restitution (elasticity)
public elasticity: number;
// Frictional coefficient
public friction: number;
public update(newContactArr: Contact[]) {
for (var i = 0; i < newContactArr.length; i++)
{
var newContact = newContactArr[i];
var k = -1;
for (var j = 0; j < this.contacts.length; j++)
{
if (newContact.hash == this.contacts[j].hash)
{
k = j;
break;
}
}
if (k > -1)
{
newContact.lambdaNormal = this.contacts[k].lambdaNormal;
newContact.lambdaTangential = this.contacts[k].lambdaTangential;
}
}
this.contacts = newContactArr;
}
public initSolver(dt_inv) {
var body1: Body = this.shape1.body;
var body2: Body = this.shape2.body;
var sum_m_inv = body1.massInverted + body2.massInverted;
for (var i = 0; i < this.contacts.length; i++)
{
var con: Contact = this.contacts[i];
//console.log('initSolver con');
//console.log(con);
// Transformed r1, r2
Phaser.Vec2Utils.subtract(con.point, body1.position, con.r1);
Phaser.Vec2Utils.subtract(con.point, body2.position, con.r2);
//con.r1 = vec2.sub(con.point, body1.p);
//con.r2 = vec2.sub(con.point, body2.p);
// Local r1, r2
Phaser.TransformUtils.unrotate(body1.transform, con.r1, con.r1_local);
Phaser.TransformUtils.unrotate(body2.transform, con.r2, con.r2_local);
//con.r1_local = body1.transform.unrotate(con.r1);
//con.r2_local = body2.transform.unrotate(con.r2);
var n = con.normal;
var t = Phaser.Vec2Utils.perp(con.normal);
// invEMn = J * invM * JT
// J = [ -n, -cross(r1, n), n, cross(r2, n) ]
var sn1 = Phaser.Vec2Utils.cross(con.r1, n);
var sn2 = Phaser.Vec2Utils.cross(con.r2, n);
var emn_inv = sum_m_inv + body1.inertiaInverted * sn1 * sn1 + body2.inertiaInverted * sn2 * sn2;
con.emn = emn_inv == 0 ? 0 : 1 / emn_inv;
// invEMt = J * invM * JT
// J = [ -t, -cross(r1, t), t, cross(r2, t) ]
var st1 = Phaser.Vec2Utils.cross(con.r1, t);
var st2 = Phaser.Vec2Utils.cross(con.r2, t);
var emt_inv = sum_m_inv + body1.inertiaInverted * st1 * st1 + body2.inertiaInverted * st2 * st2;
con.emt = emt_inv == 0 ? 0 : 1 / emt_inv;
// Linear velocities at contact point
// in 2D: cross(w, r) = perp(r) * w
var v1 = new Phaser.Vec2;
var v2 = new Phaser.Vec2;
Phaser.Vec2Utils.multiplyAdd(body1.velocity, Phaser.Vec2Utils.perp(con.r1), body1.angularVelocity, v1);
Phaser.Vec2Utils.multiplyAdd(body2.velocity, Phaser.Vec2Utils.perp(con.r2), body2.angularVelocity, v2);
//var v1 = vec2.mad(body1.v, vec2.perp(con.r1), body1.w);
//var v2 = vec2.mad(body2.v, vec2.perp(con.r2), body2.w);
// relative velocity at contact point
var rv = new Phaser.Vec2;
Phaser.Vec2Utils.subtract(v2, v1, rv);
//var rv = vec2.sub(v2, v1);
// bounce velocity dot n
con.bounce = Phaser.Vec2Utils.dot(rv, con.normal) * this.elasticity;
}
}
public warmStart() {
var body1: Body = this.shape1.body;
var body2: Body = this.shape2.body;
for (var i = 0; i < this.contacts.length; i++)
{
var con = this.contacts[i];
var n = con.normal;
var lambda_n = con.lambdaNormal;
var lambda_t = con.lambdaTangential;
// Apply accumulated impulses
//var impulse = vec2.rotate_vec(new vec2(lambda_n, lambda_t), n);
//var impulse = new vec2(lambda_n * n.x - lambda_t * n.y, lambda_t * n.x + lambda_n * n.y);
var impulse = new Phaser.Vec2(lambda_n * n.x - lambda_t * n.y, lambda_t * n.x + lambda_n * n.y);
body1.velocity.multiplyAddByScalar(impulse, -body1.massInverted);
//body1.v.mad(impulse, -body1.m_inv);
body1.angularVelocity -= Phaser.Vec2Utils.cross(con.r1, impulse) * body1.inertiaInverted;
//body1.w -= vec2.cross(con.r1, impulse) * body1.i_inv;
body2.velocity.multiplyAddByScalar(impulse, -body2.massInverted);
//body2.v.mad(impulse, body2.m_inv);
body2.angularVelocity -= Phaser.Vec2Utils.cross(con.r2, impulse) * body2.inertiaInverted;
//body2.w += vec2.cross(con.r2, impulse) * body2.i_inv;
}
}
public solveVelocityConstraints() {
var body1: Body = this.shape1.body;
var body2: Body = this.shape2.body;
var m1_inv = body1.massInverted;
var i1_inv = body1.inertiaInverted;
var m2_inv = body2.massInverted;
var i2_inv = body2.inertiaInverted;
for (var i = 0; i < this.contacts.length; i++)
{
var con = this.contacts[i];
var n = con.normal;
var t = Phaser.Vec2Utils.perp(n);
var r1 = con.r1;
var r2 = con.r2;
// Linear velocities at contact point
// in 2D: cross(w, r) = perp(r) * w
var v1 = new Phaser.Vec2;
var v2 = new Phaser.Vec2;
Phaser.Vec2Utils.multiplyAdd(body1.velocity, Phaser.Vec2Utils.perp(r1), body1.angularVelocity, v1);
//var v1 = vec2.mad(body1.v, vec2.perp(r1), body1.w);
Phaser.Vec2Utils.multiplyAdd(body2.velocity, Phaser.Vec2Utils.perp(r2), body2.angularVelocity, v2);
//var v2 = vec2.mad(body2.v, vec2.perp(r2), body2.w);
// Relative velocity at contact point
var rv = new Phaser.Vec2;
Phaser.Vec2Utils.subtract(v2, v1, rv);
//var rv = vec2.sub(v2, v1);
// Compute normal constraint impulse + adding bounce as a velocity bias
// lambda_n = -EMn * J * V
var lambda_n = -con.emn * (Phaser.Vec2Utils.dot(n, rv) + con.bounce);
// Accumulate and clamp
var lambda_n_old = con.lambdaNormal;
con.lambdaNormal = Math.max(lambda_n_old + lambda_n, 0);
lambda_n = con.lambdaNormal - lambda_n_old;
// Compute frictional constraint impulse
// lambda_t = -EMt * J * V
var lambda_t = -con.emt * Phaser.Vec2Utils.dot(t, rv);
// Max friction constraint impulse (Coulomb's Law)
var lambda_t_max = con.lambdaNormal * this.friction;
// Accumulate and clamp
var lambda_t_old = con.lambdaTangential;
con.lambdaTangential = this.clamp(lambda_t_old + lambda_t, -lambda_t_max, lambda_t_max);
lambda_t = con.lambdaTangential - lambda_t_old;
// Apply the final impulses
//var impulse = vec2.rotate_vec(new vec2(lambda_n, lambda_t), n);
var impulse = new Phaser.Vec2(lambda_n * n.x - lambda_t * n.y, lambda_t * n.x + lambda_n * n.y);
body1.velocity.multiplyAddByScalar(impulse, -m1_inv);
//body1.v.mad(impulse, -m1_inv);
body1.angularVelocity -= Phaser.Vec2Utils.cross(r1, impulse) * i1_inv;
//body1.w -= vec2.cross(r1, impulse) * i1_inv;
body2.velocity.multiplyAddByScalar(impulse, m2_inv);
//body2.v.mad(impulse, m2_inv);
body1.angularVelocity += Phaser.Vec2Utils.cross(r2, impulse) * i2_inv;
//body2.w += vec2.cross(r2, impulse) * i2_inv;
}
}
public solvePositionConstraints() {
var body1: Body = this.shape1.body;
var body2: Body = this.shape2.body;
var m1_inv = body1.massInverted;
var i1_inv = body1.inertiaInverted;
var m2_inv = body2.massInverted;
var i2_inv = body2.inertiaInverted;
var sum_m_inv = m1_inv + m2_inv;
var max_penetration = 0;
for (var i = 0; i < this.contacts.length; i++)
{
var con = this.contacts[i];
var n = con.normal;
var r1 = new Phaser.Vec2;
var r2 = new Phaser.Vec2;
// Transformed r1, r2
Phaser.Vec2Utils.rotate(con.r1_local, body1.angle, r1);
//var r1 = vec2.rotate(con.r1_local, body1.a);
Phaser.Vec2Utils.rotate(con.r2_local, body2.angle, r2);
//var r2 = vec2.rotate(con.r2_local, body2.a);
// Contact points (corrected)
var p1 = new Phaser.Vec2;
var p2 = new Phaser.Vec2;
Phaser.Vec2Utils.add(body1.position, r1, p1);
//var p1 = vec2.add(body1.p, r1);
Phaser.Vec2Utils.add(body2.position, r2, p2);
//var p2 = vec2.add(body2.p, r2);
// Corrected delta vector
var dp = new Phaser.Vec2;
Phaser.Vec2Utils.subtract(p2, p1);
//var dp = vec2.sub(p2, p1);
// Position constraint
var c = Phaser.Vec2Utils.dot(dp, n) + con.depth;
var correction = this.clamp(Manager.CONTACT_SOLVER_BAUMGARTE * (c + Manager.CONTACT_SOLVER_COLLISION_SLOP), -Manager.CONTACT_SOLVER_MAX_LINEAR_CORRECTION, 0);
if (correction == 0)
{
continue;
}
// We don't need max_penetration less than or equal slop
max_penetration = Math.max(max_penetration, -c);
// Compute lambda for position constraint
// Solve (J * invM * JT) * lambda = -C / dt
var sn1 = Phaser.Vec2Utils.cross(r1, n);
var sn2 = Phaser.Vec2Utils.cross(r2, n);
var em_inv = sum_m_inv + body1.inertiaInverted * sn1 * sn1 + body2.inertiaInverted * sn2 * sn2;
var lambda_dt = em_inv == 0 ? 0 : -correction / em_inv;
// Apply correction impulses
var impulse_dt = new Phaser.Vec2;
Phaser.Vec2Utils.scale(n, lambda_dt, impulse_dt);
//var impulse_dt = vec2.scale(n, lambda_dt);
body1.position.multiplyAddByScalar(impulse_dt, -m1_inv);
//body1.p.mad(impulse_dt, -m1_inv);
body1.angle -= sn1 * lambda_dt * i1_inv;
body2.position.multiplyAddByScalar(impulse_dt, m2_inv);
//body2.p.mad(impulse_dt, m2_inv);
body2.angle += sn2 * lambda_dt * i2_inv;
}
return max_penetration <= Manager.CONTACT_SOLVER_COLLISION_SLOP * 3;
}
public clamp(v, min, max) {
return v < min ? min : (v > max ? max : v);
}
}
}

View file

@ -0,0 +1,328 @@
/// <reference path="../../Game.ts" />
/// <reference path="Body.ts" />
/// <reference path="joints/Joint.ts" />
/**
* Phaser - Advanced Physics Manager
*
* Your game only has one PhysicsManager instance and it's responsible for looking after, creating and colliding
* all of the physics objects in the world.
*/
module Phaser.Physics.Advanced {
export class Manager {
constructor(game: Game) {
this.game = game;
this.space = new Space();
Manager.collision = new Collision();
}
/**
* Local reference to Game.
*/
public game: Game;
public static collision: Collision;
public static SHAPE_TYPE_CIRCLE: number = 0;
public static SHAPE_TYPE_SEGMENT: number = 1;
public static SHAPE_TYPE_POLY: number = 2;
public static SHAPE_NUM_TYPES: number = 3;
public static JOINT_TYPE_ANGLE: number = 0;
public static JOINT_TYPE_REVOLUTE: number = 1;
public static JOINT_TYPE_WELD: number = 2;
public static JOINT_TYPE_WHEEL: number = 3;
public static JOINT_TYPE_PRISMATIC: number = 4;
public static JOINT_TYPE_DISTANCE: number = 5;
public static JOINT_TYPE_ROPE: number = 6;
public static JOINT_TYPE_MOUSE: number = 7;
public static JOINT_LINEAR_SLOP: number = 0.0008;
public static JOINT_ANGULAR_SLOP: number = 2 * Phaser.GameMath.DEG_TO_RAD;
public static JOINT_MAX_LINEAR_CORRECTION: number = 0.5;
public static JOINT_MAX_ANGULAR_CORRECTION: number = 8 * Phaser.GameMath.DEG_TO_RAD;
public static JOINT_LIMIT_STATE_INACTIVE: number = 0;
public static JOINT_LIMIT_STATE_AT_LOWER: number = 1;
public static JOINT_LIMIT_STATE_AT_UPPER: number = 2;
public static JOINT_LIMIT_STATE_EQUAL_LIMITS: number = 3;
public static CONTACT_SOLVER_COLLISION_SLOP: number = 0.0008;
public static CONTACT_SOLVER_BAUMGARTE: number = 0.28;
public static CONTACT_SOLVER_MAX_LINEAR_CORRECTION: number = 1;//Infinity;
public static bodyCounter: number = 0;
public static jointCounter: number = 0;
public static shapeCounter: number = 0;
public space: Space;
public lastTime: number = Date.now();
public frameRateHz: number = 60;
public timeDelta: number = 0;
public paused: bool = false;
public step: bool = false; // step through the simulation (i.e. per click)
public velocityIterations: number = 8;
public positionIterations: number = 4;
public allowSleep: bool = true;
public warmStarting: bool = true;
public update() {
var time = Date.now();
var frameTime = (time - this.lastTime) / 1000;
this.lastTime = time;
// if rAf - why?
frameTime = Math.floor(frameTime * 60 + 0.5) / 60;
//if (!mouseDown)
//{
// var p = canvasToWorld(mousePosition);
// var body = space.findBodyByPoint(p);
// //domCanvas.style.cursor = body ? "pointer" : "default";
//}
if (!this.paused || this.step)
{
var h = 1 / this.frameRateHz;
this.timeDelta += frameTime;
if (this.step)
{
this.step = false;
this.timeDelta = h;
}
for (var maxSteps = 4; maxSteps > 0 && this.timeDelta >= h; maxSteps--)
{
this.space.step(h, this.velocityIterations, this.positionIterations, this.warmStarting, this.allowSleep);
this.timeDelta -= h;
}
if (this.timeDelta > h)
{
this.timeDelta = 0;
}
//if (sceneIndex < demoArr.length)
//{
// demo = demoArr[sceneIndex];
// demo.runFrame();
//}
}
//frameCount++;
}
public pixelsToMeters(value: number): number {
return value * 0.02;
}
public metersToPixels(value: number): number {
return value * 50;
}
public static pixelsToMeters(value: number): number {
return value * 0.02;
}
public static metersToPixels(value: number): number {
return value * 50;
}
public static p2m(value: number): number {
return value * 0.02;
}
public static m2p(value: number): number {
return value * 50;
}
public static areaForCircle(radius_outer, radius_inner): number {
return Math.PI * (radius_outer * radius_outer - radius_inner * radius_inner);
}
public static inertiaForCircle(mass, center, radius_outer, radius_inner): number {
return mass * ((radius_outer * radius_outer + radius_inner * radius_inner) * 0.5 + center.lengthSq());
}
public static areaForSegment(a, b, radius): number {
return radius * (Math.PI * radius + 2 * Phaser.Vec2Utils.distance(a, b));
}
public static centroidForSegment(a, b): Phaser.Vec2 {
return Phaser.Vec2Utils.scale(Phaser.Vec2Utils.add(a, b), 0.5);
}
public static inertiaForSegment(mass, a, b): number {
var distsq = Phaser.Vec2Utils.distanceSq(b, a);
var offset: Phaser.Vec2 = Phaser.Vec2Utils.scale(Phaser.Vec2Utils.add(a, b), 0.5);
return mass * (distsq / 12 + offset.lengthSq());
}
public static areaForPoly(verts): number {
var area = 0;
for (var i = 0; i < verts.length; i++)
{
area += Phaser.Vec2Utils.cross(verts[i], verts[(i + 1) % verts.length]);
}
return area / 2;
}
public static centroidForPoly(verts): Phaser.Vec2 {
var area = 0;
var vsum = new Phaser.Vec2;
for (var i = 0; i < verts.length; i++)
{
var v1 = verts[i];
var v2 = verts[(i + 1) % verts.length];
var cross = Phaser.Vec2Utils.cross(v1, v2);
area += cross;
// SO many vecs created here - unroll these bad boys
vsum.add(Phaser.Vec2Utils.scale(Phaser.Vec2Utils.add(v1, v2), cross));
}
return Phaser.Vec2Utils.scale(vsum, 1 / (3 * area));
}
public static inertiaForPoly(mass, verts, offset): number {
var sum1 = 0;
var sum2 = 0;
for (var i = 0; i < verts.length; i++)
{
var v1 = Phaser.Vec2Utils.add(verts[i], offset);
var v2 = Phaser.Vec2Utils.add(verts[(i + 1) % verts.length], offset);
var a = Phaser.Vec2Utils.cross(v2, v1);
var b = Phaser.Vec2Utils.dot(v1, v1) + Phaser.Vec2Utils.dot(v1, v2) + Phaser.Vec2Utils.dot(v2, v2);
sum1 += a * b;
sum2 += a;
}
return (mass * sum1) / (6 * sum2);
}
public static inertiaForBox(mass, w, h) {
return mass * (w * w + h * h) / 12;
}
// Create the convex hull using the Gift wrapping algorithm (http://en.wikipedia.org/wiki/Gift_wrapping_algorithm)
public static createConvexHull(points) {
// Find the right most point on the hull
var i0 = 0;
var x0 = points[0].x;
for (var i = 1; i < points.length; i++)
{
var x = points[i].x;
if (x > x0 || (x == x0 && points[i].y < points[i0].y))
{
i0 = i;
x0 = x;
}
}
var n = points.length;
var hull = [];
var m = 0;
var ih = i0;
while (1)
{
hull[m] = ih;
var ie = 0;
for (var j = 1; j < n; j++)
{
if (ie == ih)
{
ie = j;
continue;
}
var r = Phaser.Vec2Utils.subtract(points[ie], points[hull[m]]);
var v = Phaser.Vec2Utils.subtract(points[j], points[hull[m]]);
var c = Phaser.Vec2Utils.cross(r, v);
if (c < 0)
{
ie = j;
}
// Collinearity check
if (c == 0 && v.lengthSq() > r.lengthSq())
{
ie = j;
}
}
m++;
ih = ie;
if (ie == i0)
{
break;
}
}
// Copy vertices
var newPoints = [];
for (var i = 0; i < m; ++i)
{
newPoints.push(points[hull[i]]);
}
return newPoints;
}
}
}

View file

@ -0,0 +1,850 @@
/// <reference path="../../math/Vec2.ts" />
/// <reference path="../../math/Vec2Utils.ts" />
/// <reference path="Manager.ts" />
/// <reference path="Body.ts" />
/// <reference path="shapes/Shape.ts" />
/// <reference path="ContactSolver.ts" />
/// <reference path="Contact.ts" />
/// <reference path="Collision.ts" />
/// <reference path="joints/IJoint.ts" />
/**
* Phaser - Advanced Physics - Space
*
* Based on the work Ju Hyung Lee started in JS PhyRus.
*/
module Phaser.Physics.Advanced {
export class Space {
constructor() {
this.bodyArr = [];
this.bodyHash = {};
this.jointArr = [];
this.jointHash = {};
this.numContacts = 0;
this.contactSolvers = [];
//this.postSolve(arb) { };
this.gravity = new Phaser.Vec2(0, 10);
this.damping = 0;
}
public static TIME_TO_SLEEP = 0.5;
public static SLEEP_LINEAR_TOLERANCE = 0.5;
public static SLEEP_ANGULAR_TOLERANCE = 2 * Phaser.GameMath.DEG_TO_RAD;
public bodyArr: Body[];
public bodyHash;
public jointArr: IJoint[];
public jointHash;
public numContacts: number;
public contactSolvers: ContactSolver[];
public postSolve;
public gravity: Phaser.Vec2;
public damping: number;
public stepCount: number = 0;
public clear() {
Manager.shapeCounter = 0;
Manager.bodyCounter = 0;
Manager.jointCounter = 0;
for (var i = 0; i < this.bodyArr.length; i++)
{
if (this.bodyArr[i])
{
this.removeBody(this.bodyArr[i]);
}
}
this.bodyArr = [];
this.bodyHash = {};
this.jointArr = [];
this.jointHash = {};
this.contactSolvers = [];
this.stepCount = 0;
}
public addBody(body: Body) {
if (this.bodyHash[body.id] != undefined)
{
return;
}
//console.log('Body added to space', body.name);
var index = this.bodyArr.push(body) - 1;
this.bodyHash[body.id] = index;
body.awake(true);
body.space = this;
body.cacheData();
}
public removeBody(body: Body) {
if (this.bodyHash[body.id] == undefined)
{
return;
}
// Remove linked joint
for (var i = 0; i < body.joints.length; i++)
{
if (body.joints[i])
{
this.removeJoint(body.joints[i]);
}
}
body.space = null;
var index = this.bodyHash[body.id];
delete this.bodyHash[body.id];
delete this.bodyArr[index];
}
public addJoint(joint: IJoint) {
if (this.jointHash[joint.id] != undefined)
{
return;
}
joint.body1.awake(true);
joint.body2.awake(true);
var index = this.jointArr.push(joint) - 1;
this.jointHash[joint.id] = index;
var index = joint.body1.joints.push(joint) - 1;
joint.body1.jointHash[joint.id] = index;
var index = joint.body2.joints.push(joint) - 1;
joint.body2.jointHash[joint.id] = index;
}
public removeJoint(joint: IJoint) {
if (this.jointHash[joint.id] == undefined)
{
return;
}
joint.body1.awake(true);
joint.body2.awake(true);
var index = joint.body1.jointHash[joint.id];
delete joint.body1.jointHash[joint.id];
delete joint.body1.joints[index];
var index = joint.body2.jointHash[joint.id];
delete joint.body2.jointHash[joint.id];
delete joint.body2.joints[index];
var index = this.jointHash[joint.id];
delete this.jointHash[joint.id];
delete this.jointArr[index];
}
public findShapeByPoint(p, refShape) {
var firstShape;
for (var i = 0; i < this.bodyArr.length; i++)
{
var body = this.bodyArr[i];
if (!body)
{
continue;
}
for (var j = 0; j < body.shapes.length; j++)
{
var shape = body.shapes[j];
if (shape.pointQuery(p))
{
if (!refShape)
{
return shape;
}
if (!firstShape)
{
firstShape = shape;
}
if (shape == refShape)
{
refShape = null;
}
}
}
}
return firstShape;
}
public findBodyByPoint(p, refBody: Body) {
var firstBody;
for (var i = 0; i < this.bodyArr.length; i++)
{
var body = this.bodyArr[i];
if (!body)
{
continue;
}
for (var j = 0; j < body.shapes.length; j++)
{
var shape = body.shapes[j];
if (shape.pointQuery(p))
{
if (!refBody)
{
return shape.body;
}
if (!firstBody)
{
firstBody = shape.body;
}
if (shape.body == refBody)
{
refBody = null;
}
break;
}
}
}
return firstBody;
}
// TODO: Replace this function to shape hashing
public shapeById(id) {
var shape;
for (var i = 0; i < this.bodyArr.length; i++)
{
var body = this.bodyArr[i];
if (!body)
{
continue;
}
for (var j = 0; j < body.shapes.length; j++)
{
if (body.shapes[j].id == id)
{
return body.shapes[j];
}
}
}
return null;
}
public jointById(id) {
var index = this.jointHash[id];
if (index != undefined)
{
return this.jointArr[index];
}
return null;
}
public findVertexByPoint(p, minDist, refVertexId) {
var firstVertexId = -1;
refVertexId = refVertexId || -1;
for (var i = 0; i < this.bodyArr.length; i++)
{
var body = this.bodyArr[i];
if (!body)
{
continue;
}
for (var j = 0; j < body.shapes.length; j++)
{
var shape = body.shapes[j];
var index = shape.findVertexByPoint(p, minDist);
if (index != -1)
{
var vertex = (shape.id << 16) | index;
if (refVertexId == -1)
{
return vertex;
}
if (firstVertexId == -1)
{
firstVertexId = vertex;
}
if (vertex == refVertexId)
{
refVertexId = -1;
}
}
}
}
return firstVertexId;
}
public findEdgeByPoint(p, minDist, refEdgeId) {
var firstEdgeId = -1;
refEdgeId = refEdgeId || -1;
for (var i = 0; i < this.bodyArr.length; i++)
{
var body = this.bodyArr[i];
if (!body)
{
continue;
}
for (var j = 0; j < body.shapes.length; j++)
{
var shape = body.shapes[j];
if (shape.type != Manager.SHAPE_TYPE_POLY)
{
continue;
}
var index = shape.findEdgeByPoint(p, minDist);
if (index != -1)
{
var edge = (shape.id << 16) | index;
if (refEdgeId == -1)
{
return edge;
}
if (firstEdgeId == -1)
{
firstEdgeId = edge;
}
if (edge == refEdgeId)
{
refEdgeId = -1;
}
}
}
}
return firstEdgeId;
}
public findJointByPoint(p, minDist, refJointId) {
var firstJointId = -1;
var dsq = minDist * minDist;
refJointId = refJointId || -1;
for (var i = 0; i < this.jointArr.length; i++)
{
var joint = this.jointArr[i];
if (!joint)
{
continue;
}
var jointId = -1;
if (Phaser.Vec2Utils.distanceSq(p, joint.getWorldAnchor1()) < dsq)
{
jointId = (joint.id << 16 | 0);
}
else if (Phaser.Vec2Utils.distanceSq(p, joint.getWorldAnchor2()) < dsq)
{
jointId = (joint.id << 16 | 1);
}
if (jointId != -1)
{
if (refJointId == -1)
{
return jointId;
}
if (firstJointId == -1)
{
firstJointId = jointId;
}
if (jointId == refJointId)
{
refJointId = -1;
}
}
}
return firstJointId;
}
public findContactSolver(shape1, shape2) {
for (var i = 0; i < this.contactSolvers.length; i++)
{
var contactSolver = this.contactSolvers[i];
if (shape1 == contactSolver.shape1 && shape2 == contactSolver.shape2)
{
return contactSolver;
}
}
return null;
}
public genTemporalContactSolvers() {
//console.log('genTemporalContactSolvers');
//var t0 = Date.now();
var newContactSolverArr = [];
this.numContacts = 0;
for (var body1_index = 0; body1_index < this.bodyArr.length; body1_index++)
{
var body1: Body = this.bodyArr[body1_index];
//console.log('body1', body1_index, body1.type);
if (!body1)
{
continue;
}
body1.stepCount = this.stepCount;
for (var body2_index = 0; body2_index < this.bodyArr.length; body2_index++)
{
var body2: Body = this.bodyArr[body2_index];
//console.log('body2', body2_index, body2.type);
if (!body2)
{
continue;
}
if (body1.stepCount == body2.stepCount)
{
continue;
}
//console.log('step');
var active1 = body1.isAwake && !body1.isStatic;
var active2 = body2.isAwake && !body2.isStatic;
if (!active1 && !active2)
{
continue;
}
//console.log('active');
if (!body1.isCollidable(body2))
{
continue;
}
//console.log('collideable');
if (!body1.bounds.intersectsBounds(body2.bounds))
{
continue;
}
//console.log('>>>>>>>>>> intersects');
for (var i = 0; i < body1.shapes.length; i++)
{
for (var j = 0; j < body2.shapes.length; j++)
{
var shape1 = body1.shapes[i];
var shape2 = body2.shapes[j];
var contactArr = [];
if (!Manager.collision.collide(shape1, shape2, contactArr))
{
continue;
}
if (shape1.type > shape2.type)
{
var temp = shape1;
shape1 = shape2;
shape2 = temp;
}
this.numContacts += contactArr.length;
var contactSolver = this.findContactSolver(shape1, shape2);
if (contactSolver)
{
contactSolver.update(contactArr);
newContactSolverArr.push(contactSolver);
}
else
{
body1.awake(true);
body2.awake(true);
var newContactSolver = new ContactSolver(shape1, shape2);
newContactSolver.contacts = contactArr;
newContactSolver.elasticity = Math.max(shape1.elasticity, shape2.elasticity);
newContactSolver.friction = Math.sqrt(shape1.friction * shape2.friction);
newContactSolverArr.push(newContactSolver);
}
}
}
}
}
//stats.timeCollision = Date.now() - t0;
return newContactSolverArr;
}
public initSolver(dt, dt_inv, warmStarting) {
//var t0 = Date.now();
// Initialize contact solvers
for (var i = 0; i < this.contactSolvers.length; i++)
{
this.contactSolvers[i].initSolver(dt_inv);
}
// Initialize joint solver
for (var i = 0; i < this.jointArr.length; i++)
{
if (this.jointArr[i])
{
this.jointArr[i].initSolver(dt, warmStarting);
}
}
// Warm starting (apply cached impulse)
if (warmStarting)
{
for (var i = 0; i < this.contactSolvers.length; i++)
{
this.contactSolvers[i].warmStart();
}
}
//stats.timeInitSolver = Date.now() - t0;
}
public velocitySolver(iteration) {
//var t0 = Date.now();
for (var i = 0; i < iteration; i++)
{
for (var j = 0; j < this.jointArr.length; j++)
{
if (this.jointArr[j])
{
this.jointArr[j].solveVelocityConstraints();
}
}
for (var j = 0; j < this.contactSolvers.length; j++)
{
this.contactSolvers[j].solveVelocityConstraints();
}
}
//stats.timeVelocitySolver = Date.now() - t0;
}
public positionSolver(iteration) {
//var t0 = Date.now();
var positionSolved = false;
//stats.positionIterations = 0;
for (var i = 0; i < iteration; i++)
{
var contactsOk = true;
var jointsOk = true;
for (var j = 0; j < this.contactSolvers.length; j++)
{
var contactOk = this.contactSolvers[j].solvePositionConstraints();
contactsOk = contactOk && contactsOk;
}
for (var j = 0; j < this.jointArr.length; j++)
{
if (this.jointArr[j])
{
var jointOk = this.jointArr[j].solvePositionConstraints();
jointsOk = jointOk && jointsOk;
}
}
if (contactsOk && jointsOk)
{
// exit early if the position errors are small
positionSolved = true;
break;
}
//stats.positionIterations++;
}
//stats.timePositionSolver = Date.now() - t0;
return positionSolved;
}
public step(dt, vel_iteration, pos_iteration, warmStarting, allowSleep) {
var dt_inv = 1 / dt;
this.stepCount++;
// Generate contact & contactSolver
this.contactSolvers = this.genTemporalContactSolvers();
// Initialize contacts & joints solver
this.initSolver(dt, dt_inv, warmStarting);
// Intergrate velocity
for (var i = 0; i < this.bodyArr.length; i++)
{
var body = this.bodyArr[i];
if (!body)
{
continue;
}
if (body.isDynamic && body.isAwake)
{
body.updateVelocity(this.gravity, dt, this.damping);
}
}
for (var i = 0; i < this.jointArr.length; i++)
{
var joint = this.jointArr[i];
if (!joint)
{
continue;
}
var body1 = joint.body1;
var body2 = joint.body2;
var awake1 = body1.isAwake && !body1.isStatic;
var awake2 = body2.isAwake && !body2.isStatic;
if (awake1 ^ awake2)
{
if (!awake1)
{
body1.awake(true);
}
if (!awake2)
{
body2.awake(true);
}
}
}
// Iterative velocity constraints solver
this.velocitySolver(vel_iteration);
// Intergrate position
for (var i = 0; i < this.bodyArr.length; i++)
{
var body = this.bodyArr[i];
if (!body)
{
continue
}
if (body.isDynamic && body.isAwake)
{
body.updatePosition(dt);
}
}
// Process breakable joint
for (var i = 0; i < this.jointArr.length; i++)
{
var joint = this.jointArr[i];
if (!joint)
{
continue;
}
if (joint.breakable)
{
if (joint.getReactionForce(dt_inv).lengthsq() >= joint.maxForce * joint.maxForce)
{
this.removeJoint(joint);
}
}
}
// Iterative position constraints solver
var positionSolved = this.positionSolver(pos_iteration);
for (var i = 0; i < this.bodyArr.length; i++)
{
var body = this.bodyArr[i];
if (!body)
{
continue;
}
body.syncTransform();
}
// Post solve collision callback
for (var i = 0; i < this.contactSolvers.length; i++)
{
var arb = this.contactSolvers[i];
// Re-enable this
//this.postSolve(arb);
}
for (var i = 0; i < this.bodyArr.length; i++)
{
var body = this.bodyArr[i];
if (!body)
{
continue;
}
if (body.isDynamic && body.isAwake)
{
body.cacheData();
}
}
// Process sleeping
if (allowSleep)
{
var minSleepTime = 999999;
var linTolSqr = Space.SLEEP_LINEAR_TOLERANCE * Space.SLEEP_LINEAR_TOLERANCE;
var angTolSqr = Space.SLEEP_ANGULAR_TOLERANCE * Space.SLEEP_ANGULAR_TOLERANCE;
for (var i = 0; i < this.bodyArr.length; i++)
{
var body = this.bodyArr[i];
if (!body)
{
continue;
}
if (!body.isDynamic)
{
continue;
}
if (body.angularVelocity * body.angularVelocity > angTolSqr || body.velocity.dot(body.velocity) > linTolSqr)
{
body.sleepTime = 0;
minSleepTime = 0;
}
else
{
body.sleepTime += dt;
minSleepTime = Math.min(minSleepTime, body.sleepTime);
}
}
if (positionSolved && minSleepTime >= Space.TIME_TO_SLEEP)
{
for (var i = 0; i < this.bodyArr.length; i++)
{
var body = this.bodyArr[i];
if (!body)
{
continue;
}
body.awake(false);
}
}
}
}
}
}

View file

@ -0,0 +1,43 @@
/// <reference path="../../../math/Vec2.ts" />
/// <reference path="../../../geom/Point.ts" />
/// <reference path="../../../math/Vec2Utils.ts" />
/// <reference path="../Manager.ts" />
/// <reference path="../Body.ts" />
/**
* Phaser - Advanced Physics - Joint
*
* Based on the work Ju Hyung Lee started in JS PhyRus.
*/
module Phaser.Physics.Advanced {
export interface IJoint {
id: number;
type: number;
body1: Phaser.Physics.Advanced.Body;
body2: Phaser.Physics.Advanced.Body;
collideConnected; // bool?
maxForce: number;
breakable: bool;
anchor1: Phaser.Vec2;
anchor2: Phaser.Vec2;
getWorldAnchor1();
getWorldAnchor2();
setWorldAnchor1(anchor1);
setWorldAnchor2(anchor2);
initSolver(dt, warmStarting);
solveVelocityConstraints();
solvePositionConstraints();
getReactionForce(dt_inv);
}
}

View file

@ -0,0 +1,64 @@
/// <reference path="../../../math/Vec2.ts" />
/// <reference path="../../../geom/Point.ts" />
/// <reference path="../../../math/Vec2Utils.ts" />
/// <reference path="../Manager.ts" />
/// <reference path="../Body.ts" />
/**
* Phaser - Advanced Physics - Joint
*
* Based on the work Ju Hyung Lee started in JS PhyRus.
*/
module Phaser.Physics.Advanced {
export class Joint {
constructor(type: number, body1:Phaser.Physics.Advanced.Body, body2:Phaser.Physics.Advanced.Body, collideConnected) {
this.id = Phaser.Physics.Advanced.Manager.jointCounter++;
this.type = type;
this.body1 = body1;
this.body2 = body2;
this.collideConnected = collideConnected;
this.maxForce = 9999999999;
this.breakable = false;
}
public id: number;
public type: number;
public body1: Phaser.Physics.Advanced.Body;
public body2: Phaser.Physics.Advanced.Body;
public collideConnected; // bool?
public maxForce: number;
public breakable: bool;
public anchor1: Phaser.Vec2;
public anchor2: Phaser.Vec2;
public getWorldAnchor1() {
return this.body1.getWorldPoint(this.anchor1);
}
public getWorldAnchor2() {
return this.body2.getWorldPoint(this.anchor2);
}
public setWorldAnchor1(anchor1) {
this.anchor1 = this.body1.getLocalPoint(anchor1);
}
public setWorldAnchor2(anchor2) {
this.anchor2 = this.body2.getLocalPoint(anchor2);
}
}
}

View file

@ -0,0 +1,39 @@
/// <reference path="../../../math/Vec2.ts" />
/// <reference path="../Manager.ts" />
/// <reference path="../Body.ts" />
/// <reference path="Shape.ts" />
/// <reference path="Poly.ts" />
/**
* Phaser - Advanced Physics - Shapes - Box
*
* Based on the work Ju Hyung Lee started in JS PhyRus.
*/
module Phaser.Physics.Advanced.Shapes {
export class Box extends Phaser.Physics.Advanced.Shapes.Poly {
// Give in pixels
constructor(x, y, width, height) {
x = Manager.pixelsToMeters(x);
y = Manager.pixelsToMeters(y);
width = Manager.pixelsToMeters(width);
height = Manager.pixelsToMeters(height);
var hw = width * 0.5;
var hh = height * 0.5;
super([
new Phaser.Vec2(-hw + x, +hh + y),
new Phaser.Vec2(-hw + x, -hh + y),
new Phaser.Vec2(+hw + x, -hh + y),
new Phaser.Vec2(+hw + x, +hh + y)
]);
}
}
}

View file

@ -0,0 +1,101 @@
/// <reference path="../../../math/Vec2.ts" />
/// <reference path="../../../math/Vec2Utils.ts" />
/// <reference path="../Manager.ts" />
/// <reference path="../Body.ts" />
/// <reference path="Shape.ts" />
/**
* Phaser - Advanced Physics - Shape - Circle
*
* Based on the work Ju Hyung Lee started in JS PhyRus.
*/
module Phaser.Physics.Advanced.Shapes {
export class Circle extends Phaser.Physics.Advanced.Shape implements IShape {
constructor(radius: number, x?: number = 0, y?: number = 0) {
super(Manager.SHAPE_TYPE_CIRCLE);
this.center = new Phaser.Vec2(x, y);
this.radius = radius;
this.tc = new Phaser.Vec2;
this.finishVerts();
}
public radius: number;
public center: Phaser.Vec2;
public tc: Phaser.Vec2;
public finishVerts() {
this.radius = Math.abs(this.radius);
}
public duplicate(): Circle {
return new Circle(this.center.x, this.center.y, this.radius);
}
public recenter(c:Phaser.Vec2) {
this.center.subtract(c);
}
public transform(xf: Transform) {
Phaser.TransformUtils.transform(xf, this.center, this.center);
//this.center = xf.transform(this.center);
}
public untransform(xf: Transform) {
Phaser.TransformUtils.untransform(xf, this.center, this.center);
//this.center = xf.untransform(this.center);
}
public area(): number {
return Manager.areaForCircle(this.radius, 0);
}
public centroid(): Phaser.Vec2 {
return Phaser.Vec2Utils.clone(this.center);
}
public inertia(mass: number): number {
return Manager.inertiaForCircle(mass, this.center, this.radius, 0);
}
public cacheData(xf: Transform) {
Phaser.TransformUtils.transform(xf, this.center, this.tc);
//this.tc = xf.transform(this.center);
this.bounds.mins.setTo(this.tc.x - this.radius, this.tc.y - this.radius);
this.bounds.maxs.setTo(this.tc.x + this.radius, this.tc.y + this.radius);
}
public pointQuery(p:Phaser.Vec2): bool {
//return vec2.distsq(this.tc, p) < (this.r * this.r);
return Phaser.Vec2Utils.distanceSq(this.tc, p) < (this.radius * this.radius);
}
public findVertexByPoint(p:Phaser.Vec2, minDist: number): number {
var dsq = minDist * minDist;
if (Phaser.Vec2Utils.distanceSq(this.tc, p) < dsq)
{
return 0;
}
return -1;
}
public distanceOnPlane(n, d) {
Phaser.Vec2Utils.dot(n, this.tc) - this.radius - d;
}
}
}

View file

@ -0,0 +1,39 @@
/// <reference path="../../../math/Vec2.ts" />
/// <reference path="../../../geom/Point.ts" />
/// <reference path="../../../math/Vec2Utils.ts" />
/// <reference path="../Manager.ts" />
/// <reference path="../Body.ts" />
/// <reference path="Shape.ts" />
/**
* Phaser - Advanced Physics - IShape
*
* Based on the work Ju Hyung Lee started in JS PhyRus.
*/
module Phaser.Physics.Advanced {
export interface IShape {
id: number;
type: number;
elasticity: number;
friction: number;
density: number;
body: Body;
bounds: Bounds;
area(): number;
centroid(): Phaser.Vec2;
inertia(mass: number): number;
cacheData(xf:Transform);
pointQuery(p: Phaser.Vec2): bool;
findEdgeByPoint(p: Phaser.Vec2, minDist: number): number;
findVertexByPoint(p: Phaser.Vec2, minDist: number): number;
}
}

View file

@ -0,0 +1,295 @@
/// <reference path="../../../math/Vec2.ts" />
/// <reference path="../../../math/Vec2Utils.ts" />
/// <reference path="../Manager.ts" />
/// <reference path="../Body.ts" />
/// <reference path="Shape.ts" />
/**
* Phaser - Advanced Physics - Shapes - Convex Polygon
*
* Based on the work Ju Hyung Lee started in JS PhyRus.
*/
module Phaser.Physics.Advanced.Shapes {
export class Poly extends Phaser.Physics.Advanced.Shape implements IShape {
constructor(verts?:Phaser.Vec2[]) {
super(Manager.SHAPE_TYPE_POLY);
this.verts = [];
this.planes = [];
this.tverts = [];
this.tplanes = [];
if (verts)
{
for (var i = 0; i < verts.length; i++)
{
this.verts[i] = Phaser.Vec2Utils.clone(verts[i]);
this.tverts[i] = this.verts[i];
this.tplanes[i] = {};
this.tplanes[i].n = new Phaser.Vec2;
this.tplanes[i].d = 0;
}
}
this.finishVerts();
}
public verts: Phaser.Vec2[];
public planes;
public tverts;
public tplanes;
public convexity: bool;
public finishVerts() {
if (this.verts.length < 2)
{
this.convexity = false;
this.planes = [];
return;
}
this.convexity = true;
this.tverts = [];
this.tplanes = [];
// Must be counter-clockwise verts
for (var i = 0; i < this.verts.length; i++)
{
var a = this.verts[i];
var b = this.verts[(i + 1) % this.verts.length];
var n = Phaser.Vec2Utils.normalize(Phaser.Vec2Utils.perp(Phaser.Vec2Utils.subtract(a, b)));
this.planes[i] = {};
this.planes[i].n = n;
this.planes[i].d = Phaser.Vec2Utils.dot(n, a);
this.tverts[i] = this.verts[i];
this.tplanes[i] = {};
this.tplanes[i].n = new Phaser.Vec2;
this.tplanes[i].d = 0;
}
for (var i = 0; i < this.verts.length; i++)
{
var b = this.verts[(i + 2) % this.verts.length];
var n = this.planes[i].n;
var d = this.planes[i].d;
if (Phaser.Vec2Utils.dot(n, b) - d > 0)
{
this.convexity = false;
}
}
}
public duplicate() {
return new Phaser.Physics.Advanced.Shapes.Poly(this.verts);
}
public recenter(c) {
for (var i = 0; i < this.verts.length; i++)
{
this.verts[i].subtract(c);
}
}
public transform(xf) {
for (var i = 0; i < this.verts.length; i++)
{
this.verts[i] = xf.transform(this.verts[i]);
}
}
public untransform(xf) {
for (var i = 0; i < this.verts.length; i++)
{
this.verts[i] = xf.untransform(this.verts[i]);
}
}
public area(): number {
return Manager.areaForPoly(this.verts);
}
public centroid(): Phaser.Vec2 {
return Manager.centroidForPoly(this.verts);
}
public inertia(mass: number): number {
return Manager.inertiaForPoly(mass, this.verts, new Phaser.Vec2);
}
public cacheData(xf:Transform) {
this.bounds.clear();
var numVerts = this.verts.length;
//console.log('shapePoly cacheData', numVerts);
if (numVerts == 0)
{
return;
}
for (var i = 0; i < numVerts; i++)
{
Phaser.TransformUtils.transform(xf, this.tverts[i], this.tverts[i]);
//this.tverts[i] = xf.transform(this.verts[i]);
}
if (numVerts < 2)
{
this.bounds.addPoint(this.tverts[0]);
return;
}
for (var i = 0; i < numVerts; i++)
{
var a = this.tverts[i];
var b = this.tverts[(i + 1) % numVerts];
var n = Phaser.Vec2Utils.normalize(Phaser.Vec2Utils.perp(Phaser.Vec2Utils.subtract(a, b)));
this.tplanes[i].n = n;
this.tplanes[i].d = Phaser.Vec2Utils.dot(n, a);
this.bounds.addPoint(a);
}
}
public pointQuery(p: Phaser.Vec2): bool {
if (!this.bounds.containPoint(p))
{
return false;
}
return this.containPoint(p);
}
public findVertexByPoint(p:Phaser.Vec2, minDist: number): number {
var dsq = minDist * minDist;
for (var i = 0; i < this.tverts.length; i++)
{
if (Phaser.Vec2Utils.distanceSq(this.tverts[i], p) < dsq)
{
return i;
}
}
return -1;
}
public findEdgeByPoint(p: Phaser.Vec2, minDist: number): number {
var dsq = minDist * minDist;
var numVerts = this.tverts.length;
for (var i = 0; i < this.tverts.length; i++)
{
var v1 = this.tverts[i];
var v2 = this.tverts[(i + 1) % numVerts];
var n = this.tplanes[i].n;
var dtv1 = Phaser.Vec2Utils.cross(v1, n);
var dtv2 = Phaser.Vec2Utils.cross(v2, n);
var dt = Phaser.Vec2Utils.cross(p, n);
if (dt > dtv1)
{
if (Phaser.Vec2Utils.distanceSq(v1, p) < dsq)
{
return i;
}
}
else if (dt < dtv2)
{
if (Phaser.Vec2Utils.distanceSq(v2, p) < dsq)
{
return i;
}
}
else
{
var dist = Phaser.Vec2Utils.dot(n, p) - Phaser.Vec2Utils.dot(n, v1);
if (dist * dist < dsq)
{
return i;
}
}
}
return -1;
}
public distanceOnPlane(n, d) {
var min = 999999;
for (var i = 0; i < this.verts.length; i++)
{
min = Math.min(min, Phaser.Vec2Utils.dot(n, this.tverts[i]));
}
return min - d;
}
public containPoint(p) {
for (var i = 0; i < this.verts.length; i++)
{
var plane = this.tplanes[i];
if (Phaser.Vec2Utils.dot(plane.n, p) - plane.d > 0)
{
return false;
}
}
return true;
}
public containPointPartial(p, n) {
for (var i = 0; i < this.verts.length; i++)
{
var plane = this.tplanes[i];
if (Phaser.Vec2Utils.dot(plane.n, n) < 0.0001)
{
continue;
}
if (Phaser.Vec2Utils.dot(plane.n, p) - plane.d > 0)
{
return false;
}
}
return true;
}
}
}

View file

@ -0,0 +1,204 @@
/// <reference path="../../../math/Vec2.ts" />
/// <reference path="../../../math/Vec2Utils.ts" />
/// <reference path="../Manager.ts" />
/// <reference path="../Body.ts" />
/// <reference path="Shape.ts" />
/**
* Phaser - Advanced Physics - Shapes - Segment
*
* Based on the work Ju Hyung Lee started in JS PhyRus.
*/
module Phaser.Physics.Advanced.Shapes {
export class Segment extends Phaser.Physics.Advanced.Shape implements IShape {
constructor(a, b, radius: number) {
super(Manager.SHAPE_TYPE_SEGMENT);
this.a = a.duplicate();
this.b = b.duplicate();
this.radius = radius;
this.normal = Phaser.Vec2Utils.perp(Phaser.Vec2Utils.subtract(b, a));
this.normal.normalize();
this.ta = new Phaser.Vec2;
this.tb = new Phaser.Vec2;
this.tn = new Phaser.Vec2;
this.finishVerts();
}
public a: Phaser.Vec2;
public b: Phaser.Vec2;
public radius: number;
public normal: Phaser.Vec2;
public ta: Phaser.Vec2;
public tb: Phaser.Vec2;
public tn: Phaser.Vec2;
public finishVerts() {
this.normal = Phaser.Vec2Utils.perp(Phaser.Vec2Utils.subtract(this.b, this.a));
this.normal.normalize();
this.radius = Math.abs(this.radius);
}
public duplicate() {
return new Phaser.Physics.Advanced.Shapes.Segment(this.a, this.b, this.radius);
}
public recenter(c) {
this.a.subtract(c);
this.b.subtract(c);
}
public transform(xf:Transform) {
Phaser.TransformUtils.transform(xf, this.a, this.a);
Phaser.TransformUtils.transform(xf, this.b, this.b);
//this.a = xf.transform(this.a);
//this.b = xf.transform(this.b);
}
public untransform(xf:Transform) {
Phaser.TransformUtils.untransform(xf, this.a, this.a);
Phaser.TransformUtils.untransform(xf, this.b, this.b);
//this.a = xf.untransform(this.a);
//this.b = xf.untransform(this.b);
}
public area(): number {
return Manager.areaForSegment(this.a, this.b, this.radius);
}
public centroid(): Phaser.Vec2 {
return Manager.centroidForSegment(this.a, this.b);
}
public inertia(mass: number): number {
return Manager.inertiaForSegment(mass, this.a, this.b);
}
public cacheData(xf:Transform) {
Phaser.TransformUtils.transform(xf, this.a, this.ta);
Phaser.TransformUtils.transform(xf, this.b, this.tb);
//this.ta = xf.transform(this.a);
//this.tb = xf.transform(this.b);
this.tn = Phaser.Vec2Utils.perp(Phaser.Vec2Utils.subtract(this.tb, this.ta)).normalize();
var l;
var r;
var t;
var b;
if (this.ta.x < this.tb.x)
{
l = this.ta.x;
r = this.tb.x;
}
else
{
l = this.tb.x;
r = this.ta.x;
}
if (this.ta.y < this.tb.y)
{
b = this.ta.y;
t = this.tb.y;
} else
{
b = this.tb.y;
t = this.ta.y;
}
this.bounds.mins.setTo(l - this.radius, b - this.radius);
this.bounds.maxs.setTo(r + this.radius, t + this.radius);
}
public pointQuery(p: Phaser.Vec2): bool {
if (!this.bounds.containPoint(p))
{
return false;
}
var dn = Phaser.Vec2Utils.dot(this.tn, p) - Phaser.Vec2Utils.dot(this.ta, this.tn);
var dist = Math.abs(dn);
if (dist > this.radius)
{
return false;
}
var dt = Phaser.Vec2Utils.cross(p, this.tn);
var dta = Phaser.Vec2Utils.cross(this.ta, this.tn);
var dtb = Phaser.Vec2Utils.cross(this.tb, this.tn);
if (dt <= dta)
{
if (dt < dta - this.radius)
{
return false;
}
return Phaser.Vec2Utils.distanceSq(this.ta, p) < (this.radius * this.radius);
}
else if (dt > dtb)
{
if (dt > dtb + this.radius)
{
return false;
}
return Phaser.Vec2Utils.distanceSq(this.tb, p) < (this.radius * this.radius);
}
return true;
}
public findVertexByPoint(p:Phaser.Vec2, minDist: number): number {
var dsq = minDist * minDist;
if (Phaser.Vec2Utils.distanceSq(this.ta, p) < dsq)
{
return 0;
}
if (Phaser.Vec2Utils.distanceSq(this.tb, p) < dsq)
{
return 1;
}
return -1;
}
public distanceOnPlane(n, d) {
var a = Phaser.Vec2Utils.dot(n, this.ta) - this.radius;
var b = Phaser.Vec2Utils.dot(n, this.tb) - this.radius;
return Math.min(a, b) - d;
}
}
}

View file

@ -0,0 +1,54 @@
/// <reference path="../../../math/Vec2.ts" />
/// <reference path="../../../math/Vec2Utils.ts" />
/// <reference path="../Manager.ts" />
/// <reference path="../Body.ts" />
/// <reference path="../Bounds.ts" />
/// <reference path="IShape.ts" />
/**
* Phaser - Advanced Physics - Shape
*
* Based on the work Ju Hyung Lee started in JS PhyRus.
*/
module Phaser.Physics.Advanced {
export class Shape {
constructor(type: number) {
this.id = Phaser.Physics.Advanced.Manager.shapeCounter++;
this.type = type;
this.elasticity = 0.0;
this.friction = 1.0;
this.density = 1;
this.bounds = new Bounds;
}
public id: number;
public type: number;
public body: Body;
// Coefficient of restitution (elasticity)
public elasticity: number;
// Frictional coefficient
public friction: number;
// Mass density
public density: number;
// Axis-aligned bounding box
public bounds: Bounds;
// Over-ridden by ShapePoly
public findEdgeByPoint(p: Phaser.Vec2, minDist: number): number {
return -1;
}
}
}

View file

@ -0,0 +1,25 @@
/// <reference path="../../../math/Vec2.ts" />
/// <reference path="../Manager.ts" />
/// <reference path="../Body.ts" />
/// <reference path="Shape.ts" />
/// <reference path="Poly.ts" />
/**
* Phaser - Advanced Physics - Shapes - Triangle
*
* Based on the work Ju Hyung Lee started in JS PhyRus.
*/
module Phaser.Physics.Advanced.Shapes {
export class Triangle extends Phaser.Physics.Advanced.Shapes.Poly {
constructor(p1, p2, p3) {
super( [ new Phaser.Vec2(p1.x, p1.y), new Phaser.Vec2(p2.x, p2.y), new Phaser.Vec2(p3.x, p3.y) ] );
}
}
}

View file

@ -45,6 +45,10 @@ TODO:
* Sprite collision events
* See which functions in the input component can move elsewhere (utils)
* Move all of the renderDebugInfo methods to the DebugUtils class
* Check bounds/edge points when sprite is only 1x1 sized :)
* See what I can move out of Body and into a BodyUtils class.
* See about optimising Advanced Physics a lot more, so it doesn't create lots of Vec2s everywhere.
V1.0.0
@ -112,7 +116,7 @@ V1.0.0
* Added SpriteUtils.overlapsXY and overlapsPoint to check if a point is within a sprite, taking scale and rotation into account.
* Added Cache.getImageKeys (and similar) to return an array of all the keys for all currently cached objects.
* Added Group.bringToTop feature. Will sort the Group, move the given sprites z-index to the top and shift the rest down by one.
* Brand new Advanced Physics system added and working! Woohoo :)

View file

@ -186,6 +186,14 @@
<Content Include="physics\aabb vs aabb 1.js">
<DependentUpon>aabb vs aabb 1.ts</DependentUpon>
</Content>
<TypeScriptCompile Include="physics\obb vs obb.ts" />
<TypeScriptCompile Include="physics\body1.ts" />
<Content Include="physics\body1.js">
<DependentUpon>body1.ts</DependentUpon>
</Content>
<Content Include="physics\obb vs obb.js">
<DependentUpon>obb vs obb.ts</DependentUpon>
</Content>
<Content Include="scrollzones\ballscroller.js">
<DependentUpon>ballscroller.ts</DependentUpon>
</Content>

File diff suppressed because it is too large Load diff

104
Tests/physics/body1.js Normal file
View file

@ -0,0 +1,104 @@
/// <reference path="../../Phaser/Game.ts" />
/// <reference path="../../Phaser/physics/advanced/Manager.ts" />
/// <reference path="../../Phaser/physics/advanced/shapes/Box.ts" />
/// <reference path="../../Phaser/physics/advanced/shapes/Circle.ts" />
(function () {
var game = new Phaser.Game(this, 'game', 800, 600, init, create, update, render);
function init() {
game.load.image('xatari', 'assets/sprites/atari800xl.png');
game.load.image('card', 'assets/sprites/mana_card.png');
game.load.image('atari', 'assets/sprites/shinyball.png');
game.load.start();
}
var atari;
var card;
var physics;
var circle;
var walls;
var ground;
function create() {
atari = game.add.sprite(200, 100, 'atari');
atari.transform.origin.setTo(0.5, 0.5);
//card = game.add.sprite(500, 300, 'card');
physics = new Phaser.Physics.Advanced.Manager(game);
walls = new Phaser.Physics.Advanced.Body(null, Phaser.Types.BODY_STATIC);
walls.game = game;
// position is in relation to the containing body! don't forget this
ground = walls.addShape(new Phaser.Physics.Advanced.Shapes.Box(400, 500, 500, 20));
//walls.addShape(new Phaser.Physics.Advanced.ShapeBox(0, 0.2, 20.48, 0.4));
//walls.addShape(new Phaser.Physics.Advanced.ShapeBox(0, 15.16, 20.48, 0.4));
//walls.addShape(new Phaser.Physics.Advanced.ShapeBox(-10.04, 7.68, 0.4, 14.56));
//walls.addShape(new Phaser.Physics.Advanced.ShapeBox(10.04, 7.68, 0.4, 14.56));
walls.resetMassData();
physics.space.addBody(walls);
// Add a circle
circle = new Phaser.Physics.Advanced.Body(null, Phaser.Types.BODY_DYNAMIC, physics.pixelsToMeters(300), physics.pixelsToMeters(200));
circle.game = game;
var shape = new Phaser.Physics.Advanced.Shapes.Circle(0.4, 0, 0);
shape.elasticity = 0.8;
shape.friction = 1;
shape.density = 1;
circle.addShape(shape);
circle.resetMassData();
physics.space.addBody(circle);
}
function update() {
physics.update();
atari.x = physics.metersToPixels(circle.position.x);
atari.y = physics.metersToPixels(circle.position.y);
atari.rotation = physics.metersToPixels(circle.angle);
// force moves without rotating
if(game.input.keyboard.isDown(Phaser.Keyboard.LEFT)) {
circle.applyAngularImpulse(-0.02);
} else if(game.input.keyboard.isDown(Phaser.Keyboard.RIGHT)) {
circle.applyAngularImpulse(0.02);
}
/*
if (game.input.keyboard.isDown(Phaser.Keyboard.LEFT))
{
circle.applyForceToCenter(new Phaser.Vec2(-8, 0));
}
else if (game.input.keyboard.isDown(Phaser.Keyboard.RIGHT))
{
circle.applyForceToCenter(new Phaser.Vec2(8, 0));
}
*/
if(game.input.keyboard.isDown(Phaser.Keyboard.UP)) {
circle.applyForceToCenter(new Phaser.Vec2(0, -10));
} else if(game.input.keyboard.isDown(Phaser.Keyboard.DOWN)) {
circle.applyForceToCenter(new Phaser.Vec2(0, 5));
}
//console.log(circle.velocity.x, circle.velocity.y);
//console.log('p', circle.position.x, circle.position.y);
}
function renderCircle(shape) {
game.stage.context.beginPath();
game.stage.context.arc(shape.tc.x * 50, shape.tc.y * 50, shape.radius * 50, 0, Math.PI * 2, false);
if(shape.body.isAwake) {
game.stage.context.fillStyle = 'rgba(0,255,0, 0.3)';
} else {
game.stage.context.fillStyle = 'rgba(100,100,100, 0.1)';
}
game.stage.context.fill();
game.stage.context.closePath();
}
function drawPolygon(ctx, shape, lineWidth, fillStyle) {
var verts = shape.verts;
ctx.beginPath();
ctx.moveTo(verts[0].x * 50, verts[0].y * 50);
for(var i = 0; i < verts.length; i++) {
ctx.lineTo(verts[i].x * 50, verts[i].y * 50);
}
ctx.lineTo(verts[verts.length - 1].x * 50, verts[verts.length - 1].y * 50);
ctx.closePath();
ctx.fillStyle = fillStyle;
ctx.fill();
}
function render() {
game.stage.context.fillStyle = 'rgb(255,255,0)';
game.stage.context.fillText('x: ' + circle.position.x + ' y: ' + circle.position.y, 32, 32);
game.stage.context.fillText('vx: ' + circle.velocity.x + ' vy: ' + circle.velocity.y, 32, 64);
renderCircle(circle.shapes[0]);
drawPolygon(game.stage.context, walls.shapes[0], 1, 'rgb(0,255,255)');
}
})();

160
Tests/physics/body1.ts Normal file
View file

@ -0,0 +1,160 @@
/// <reference path="../../Phaser/Game.ts" />
/// <reference path="../../Phaser/physics/advanced/Manager.ts" />
/// <reference path="../../Phaser/physics/advanced/shapes/Box.ts" />
/// <reference path="../../Phaser/physics/advanced/shapes/Circle.ts" />
(function () {
var game = new Phaser.Game(this, 'game', 800, 600, init, create, update, render);
function init() {
game.load.image('xatari', 'assets/sprites/atari800xl.png');
game.load.image('card', 'assets/sprites/mana_card.png');
game.load.image('atari', 'assets/sprites/shinyball.png');
game.load.start();
}
var atari: Phaser.Sprite;
var card: Phaser.Sprite;
var physics: Phaser.Physics.Advanced.Manager;
var circle: Phaser.Physics.Advanced.Body;
var walls: Phaser.Physics.Advanced.Body;
var ground: Phaser.Physics.Advanced.Shapes.Box;
function create() {
atari = game.add.sprite(200, 100, 'atari');
atari.transform.origin.setTo(0.5, 0.5);
//card = game.add.sprite(500, 300, 'card');
physics = new Phaser.Physics.Advanced.Manager(game);
walls = new Phaser.Physics.Advanced.Body(null, Phaser.Types.BODY_STATIC);
walls.game = game;
// position is in relation to the containing body! don't forget this
ground = walls.addShape(new Phaser.Physics.Advanced.Shapes.Box(400, 500, 500, 20));
//walls.addShape(new Phaser.Physics.Advanced.ShapeBox(0, 0.2, 20.48, 0.4));
//walls.addShape(new Phaser.Physics.Advanced.ShapeBox(0, 15.16, 20.48, 0.4));
//walls.addShape(new Phaser.Physics.Advanced.ShapeBox(-10.04, 7.68, 0.4, 14.56));
//walls.addShape(new Phaser.Physics.Advanced.ShapeBox(10.04, 7.68, 0.4, 14.56));
walls.resetMassData();
physics.space.addBody(walls);
// Add a circle
circle = new Phaser.Physics.Advanced.Body(null, Phaser.Types.BODY_DYNAMIC, physics.pixelsToMeters(300), physics.pixelsToMeters(200));
circle.game = game;
var shape = new Phaser.Physics.Advanced.Shapes.Circle(0.4, 0, 0);
shape.elasticity = 0.8;
shape.friction = 1;
shape.density = 1;
circle.addShape(shape);
circle.resetMassData();
physics.space.addBody(circle);
}
function update() {
physics.update();
atari.x = physics.metersToPixels(circle.position.x);
atari.y = physics.metersToPixels(circle.position.y);
atari.rotation = physics.metersToPixels(circle.angle);
// force moves without rotating
if (game.input.keyboard.isDown(Phaser.Keyboard.LEFT))
{
circle.applyAngularImpulse(-0.02);
}
else if (game.input.keyboard.isDown(Phaser.Keyboard.RIGHT))
{
circle.applyAngularImpulse(0.02);
}
/*
if (game.input.keyboard.isDown(Phaser.Keyboard.LEFT))
{
circle.applyForceToCenter(new Phaser.Vec2(-8, 0));
}
else if (game.input.keyboard.isDown(Phaser.Keyboard.RIGHT))
{
circle.applyForceToCenter(new Phaser.Vec2(8, 0));
}
*/
if (game.input.keyboard.isDown(Phaser.Keyboard.UP))
{
circle.applyForceToCenter(new Phaser.Vec2(0, -10));
}
else if (game.input.keyboard.isDown(Phaser.Keyboard.DOWN))
{
circle.applyForceToCenter(new Phaser.Vec2(0, 5));
}
//console.log(circle.velocity.x, circle.velocity.y);
//console.log('p', circle.position.x, circle.position.y);
}
function renderCircle(shape) {
game.stage.context.beginPath();
game.stage.context.arc(shape.tc.x * 50, shape.tc.y * 50, shape.radius * 50, 0, Math.PI * 2, false);
if (shape.body.isAwake)
{
game.stage.context.fillStyle = 'rgba(0,255,0, 0.3)';
}
else
{
game.stage.context.fillStyle = 'rgba(100,100,100, 0.1)';
}
game.stage.context.fill();
game.stage.context.closePath();
}
function drawPolygon(ctx, shape, lineWidth, fillStyle) {
var verts = shape.verts;
ctx.beginPath();
ctx.moveTo(verts[0].x * 50, verts[0].y * 50);
for (var i = 0; i < verts.length; i++) {
ctx.lineTo(verts[i].x * 50, verts[i].y * 50);
}
ctx.lineTo(verts[verts.length - 1].x * 50, verts[verts.length - 1].y * 50);
ctx.closePath();
ctx.fillStyle = fillStyle;
ctx.fill();
}
function render() {
game.stage.context.fillStyle = 'rgb(255,255,0)';
game.stage.context.fillText('x: ' + circle.position.x + ' y: ' + circle.position.y, 32, 32);
game.stage.context.fillText('vx: ' + circle.velocity.x + ' vy: ' + circle.velocity.y, 32, 64);
renderCircle(circle.shapes[0]);
drawPolygon(game.stage.context, walls.shapes[0], 1, 'rgb(0,255,255)');
}
})();

View file

@ -0,0 +1,33 @@
/// <reference path="../../Phaser/Game.ts" />
(function () {
var game = new Phaser.Game(this, 'game', 800, 600, init, create, update, render);
function init() {
// Using Phasers asset loader we load up a PNG from the assets folder
game.load.image('atari', 'assets/sprites/atari800xl.png');
game.load.image('card', 'assets/sprites/mana_card.png');
game.load.start();
}
var atari;
var card;
function create() {
atari = game.add.sprite(200, 310, 'atari');
card = game.add.sprite(500, 300, 'card');
atari.input.start(0);
atari.input.enableDrag();
card.input.start(0);
card.events.onInputDown.add(rotateIt, this);
}
function rotateIt() {
card.rotation += 10;
}
function update() {
}
function render() {
game.stage.context.save();
game.stage.context.strokeStyle = 'rgb(255,255,0)';
game.stage.context.strokeRect(atari.cameraView.x, atari.cameraView.y, atari.cameraView.width, atari.cameraView.height);
game.stage.context.strokeStyle = 'rgb(255,0,255)';
game.stage.context.strokeRect(card.cameraView.x, card.cameraView.y, card.cameraView.width, card.cameraView.height);
game.stage.context.restore();
}
})();

View file

@ -0,0 +1,54 @@
/// <reference path="../../Phaser/Game.ts" />
(function () {
var game = new Phaser.Game(this, 'game', 800, 600, init, create, update, render);
function init() {
// Using Phasers asset loader we load up a PNG from the assets folder
game.load.image('atari', 'assets/sprites/atari800xl.png');
game.load.image('card', 'assets/sprites/mana_card.png');
game.load.start();
}
var atari: Phaser.Sprite;
var card: Phaser.Sprite;
function create() {
atari = game.add.sprite(200, 310, 'atari');
card = game.add.sprite(500, 300, 'card');
atari.input.start(0);
atari.input.enableDrag();
card.input.start(0);
card.events.onInputDown.add(rotateIt, this);
}
function rotateIt() {
card.rotation += 10;
}
function update() {
}
function render() {
game.stage.context.save();
game.stage.context.strokeStyle = 'rgb(255,255,0)';
game.stage.context.strokeRect(atari.cameraView.x, atari.cameraView.y, atari.cameraView.width, atari.cameraView.height);
game.stage.context.strokeStyle = 'rgb(255,0,255)';
game.stage.context.strokeRect(card.cameraView.x, card.cameraView.y, card.cameraView.width, card.cameraView.height);
game.stage.context.restore();
}
})();

712
build/phaser.d.ts vendored
View file

@ -572,6 +572,12 @@ module Phaser {
*/
public lengthSq(): number;
/**
* Normalize this vector.
*
* @return {Vec2} This for chaining.
*/
public normalize(): Vec2;
/**
* The dot product of two 2D vectors.
*
* @param {Vec2} a Reference to a source Vec2 object.
@ -615,6 +621,14 @@ module Phaser {
*/
public multiplyByScalar(scalar: number): Vec2;
/**
* Adds the given vector to this vector then multiplies by the given scalar.
*
* @param {Vec2} a Reference to a source Vec2 object.
* @param {number} scalar
* @return {Vec2} This for chaining.
*/
public multiplyAddByScalar(a: Vec2, scalar: number): Vec2;
/**
* Divide this vector by the given scalar.
*
* @param {number} scalar
@ -822,9 +836,9 @@ module Phaser {
static GEOM_LINE: number;
static GEOM_POLYGON: number;
static BODY_DISABLED: number;
static BODY_DYNAMIC: number;
static BODY_STATIC: number;
static BODY_KINEMATIC: number;
static BODY_KINETIC: number;
static BODY_DYNAMIC: number;
/**
* Flag used to allow GameObjects to collide on their left side
* @type {number}
@ -2378,7 +2392,25 @@ module Phaser {
*/
static scale(a: Vec2, s: number, out?: Vec2): Vec2;
/**
* Rotate a 2D vector by 90 degrees.
* Adds two 2D vectors together and multiplies the result by the given scalar.
*
* @param {Vec2} a Reference to a source Vec2 object.
* @param {Vec2} b Reference to a source Vec2 object.
* @param {number} s Scaling value.
* @param {Vec2} out The output Vec2 that is the result of the operation.
* @return {Vec2} A Vec2 that is the sum of the two vectors added and multiplied.
*/
static multiplyAdd(a: Vec2, b: Vec2, s: number, out?: Vec2): Vec2;
/**
* Return a negative vector.
*
* @param {Vec2} a Reference to a source Vec2 object.
* @param {Vec2} out The output Vec2 that is the result of the operation.
* @return {Vec2} A Vec2 that is the negative vector.
*/
static negative(a: Vec2, out?: Vec2): Vec2;
/**
* Return a perpendicular vector (90 degrees rotation)
*
* @param {Vec2} a Reference to a source Vec2 object.
* @param {Vec2} out The output Vec2 that is the result of the operation.
@ -2386,6 +2418,14 @@ module Phaser {
*/
static perp(a: Vec2, out?: Vec2): Vec2;
/**
* Return a perpendicular vector (-90 degrees rotation)
*
* @param {Vec2} a Reference to a source Vec2 object.
* @param {Vec2} out The output Vec2 that is the result of the operation.
* @return {Vec2} A Vec2 that is the scaled vector.
*/
static rperp(a: Vec2, out?: Vec2): Vec2;
/**
* Checks if two 2D vectors are equal.
*
* @param {Vec2} a Reference to a source Vec2 object.
@ -2493,7 +2533,17 @@ module Phaser {
* @param {Vec2} out The output Vec2 that is the result of the operation.
* @return {Vec2} A Vec2.
*/
static rotate(a: Vec2, b: Vec2, theta: number, out?: Vec2): Vec2;
static rotateAroundOrigin(a: Vec2, b: Vec2, theta: number, out?: Vec2): Vec2;
/**
* Rotate a 2D vector to the given angle (theta).
*
* @param {Vec2} a Reference to a source Vec2 object.
* @param {Vec2} b Reference to a source Vec2 object.
* @param {Number} theta The angle of rotation in radians.
* @param {Vec2} out The output Vec2 that is the result of the operation.
* @return {Vec2} A Vec2.
*/
static rotate(a: Vec2, theta: number, out?: Vec2): Vec2;
/**
* Clone a 2D vector.
*
@ -3832,8 +3882,22 @@ module Phaser {
* @return {object} The text data you want.
*/
public getText(key: string);
/**
* Returns an array containing all of the keys of Images in the Cache.
* @return {Array} The string based keys in the Cache.
*/
public getImageKeys(): any[];
/**
* Returns an array containing all of the keys of Sounds in the Cache.
* @return {Array} The string based keys in the Cache.
*/
public getSoundKeys(): any[];
/**
* Returns an array containing all of the keys of Text Files in the Cache.
* @return {Array} The string based keys in the Cache.
*/
public getTextKeys(): any[];
/**
* Clean up cache memory.
*/
public destroy(): void;
@ -7215,7 +7279,7 @@ module Phaser {
private _groupCounter;
public getNextGroupID(): number;
/**
* Called one by Game during the boot process.
* Called once by Game during the boot process.
*/
public boot(): void;
/**
@ -9349,6 +9413,644 @@ module Phaser {
}
}
/**
* Phaser - 2D Transform
*
* A 2D Transform
*/
module Phaser {
class Transform {
/**
* Creates a new 2D Transform object.
* @class Transform
* @constructor
* @return {Transform} This object
**/
constructor(pos: Vec2, angle: number);
public t: Vec2;
public c: number;
public s: number;
public setTo(pos: Vec2, angle: number): Transform;
public setRotation(angle: number): Transform;
public setPosition(p: Vec2): Transform;
public identity(): Transform;
}
}
/**
* Phaser - TransformUtils
*
* A collection of methods useful for manipulating and performing operations on 2D Transforms.
*
*/
module Phaser {
class TransformUtils {
static rotate(t: Transform, v: Vec2, out?: Vec2): Vec2;
static unrotate(t: Transform, v: Vec2, out?: Vec2): Vec2;
static transform(t: Transform, v: Vec2, out?: Vec2): Vec2;
static untransform(t: Transform, v: Vec2, out?: Vec2): Vec2;
}
}
/**
* Phaser - PhysicsManager
*
* Your game only has one PhysicsManager instance and it's responsible for looking after, creating and colliding
* all of the physics objects in the world.
*/
module Phaser.Physics {
class ArcadePhysics {
constructor(game: Game, width: number, height: number);
/**
* Local private reference to Game.
*/
public game: Game;
/**
* Physics object pool
*/
public members: Group;
private _drag;
private _delta;
private _velocityDelta;
private _length;
private _distance;
private _tangent;
private _separatedX;
private _separatedY;
private _overlap;
private _maxOverlap;
private _obj1Velocity;
private _obj2Velocity;
private _obj1NewVelocity;
private _obj2NewVelocity;
private _average;
private _quadTree;
private _quadTreeResult;
public bounds: Rectangle;
public gravity: Vec2;
public drag: Vec2;
public bounce: Vec2;
public angularDrag: number;
/**
* The overlap bias is used when calculating hull overlap before separation - change it if you have especially small or large GameObjects
* @type {number}
*/
static OVERLAP_BIAS: number;
/**
* The overlap bias is used when calculating hull overlap before separation - change it if you have especially small or large GameObjects
* @type {number}
*/
static TILE_OVERLAP: bool;
/**
* @type {number}
*/
public worldDivisions: number;
public updateMotion(body: Body): void;
/**
* A tween-like function that takes a starting velocity and some other factors and returns an altered velocity.
*
* @param {number} Velocity Any component of velocity (e.g. 20).
* @param {number} Acceleration Rate at which the velocity is changing.
* @param {number} Drag Really kind of a deceleration, this is how much the velocity changes if Acceleration is not set.
* @param {number} Max An absolute value cap for the velocity.
*
* @return {number} The altered Velocity value.
*/
public computeVelocity(velocity: number, gravity?: number, acceleration?: number, drag?: number, max?: number): number;
/**
* The core Collision separation method.
* @param body1 The first Physics.Body to separate
* @param body2 The second Physics.Body to separate
* @returns {boolean} Returns true if the bodies were separated, otherwise false.
*/
public separate(body1: Body, body2: Body): bool;
public checkHullIntersection(body1: Body, body2: Body): bool;
/**
* Separates the two objects on their x axis
* @param object1 The first GameObject to separate
* @param object2 The second GameObject to separate
* @returns {boolean} Whether the objects in fact touched and were separated along the X axis.
*/
public separateBodyX(body1: Body, body2: Body): bool;
/**
* Separates the two objects on their y axis
* @param object1 The first GameObject to separate
* @param object2 The second GameObject to separate
* @returns {boolean} Whether the objects in fact touched and were separated along the Y axis.
*/
public separateBodyY(body1: Body, body2: Body): bool;
/**
* Checks for overlaps between two objects using the world QuadTree. Can be Sprite vs. Sprite, Sprite vs. Group or Group vs. Group.
* Note: Does not take the objects scrollFactor into account. All overlaps are check in world space.
* @param object1 The first Sprite or Group to check. If null the world.group is used.
* @param object2 The second Sprite or Group to check.
* @param notifyCallback A callback function that is called if the objects overlap. The two objects will be passed to this function in the same order in which you passed them to Collision.overlap.
* @param processCallback A callback function that lets you perform additional checks against the two objects if they overlap. If this is set then notifyCallback will only be called if processCallback returns true.
* @param context The context in which the callbacks will be called
* @returns {boolean} true if the objects overlap, otherwise false.
*/
public overlap(object1?, object2?, notifyCallback?, processCallback?, context?): bool;
/**
* Collision resolution specifically for GameObjects vs. Tiles.
* @param object The GameObject to separate
* @param tile The Tile to separate
* @returns {boolean} Whether the objects in fact touched and were separated
*/
public separateTile(object: Sprite, x: number, y: number, width: number, height: number, mass: number, collideLeft: bool, collideRight: bool, collideUp: bool, collideDown: bool, separateX: bool, separateY: bool): bool;
}
}
/**
* Phaser - Advanced Physics - Joint
*
* Based on the work Ju Hyung Lee started in JS PhyRus.
*/
module Phaser.Physics.Advanced {
class Joint {
constructor(type: number, body1: Body, body2: Body, collideConnected);
public id: number;
public type: number;
public body1: Body;
public body2: Body;
public collideConnected;
public maxForce: number;
public breakable: bool;
public anchor1: Vec2;
public anchor2: Vec2;
public getWorldAnchor1(): Vec2;
public getWorldAnchor2(): Vec2;
public setWorldAnchor1(anchor1): void;
public setWorldAnchor2(anchor2): void;
}
}
/**
* Phaser - Advanced Physics Manager
*
* Your game only has one PhysicsManager instance and it's responsible for looking after, creating and colliding
* all of the physics objects in the world.
*/
module Phaser.Physics.Advanced {
class Manager {
constructor(game: Game);
/**
* Local reference to Game.
*/
public game: Game;
static collision: Collision;
static SHAPE_TYPE_CIRCLE: number;
static SHAPE_TYPE_SEGMENT: number;
static SHAPE_TYPE_POLY: number;
static SHAPE_NUM_TYPES: number;
static JOINT_TYPE_ANGLE: number;
static JOINT_TYPE_REVOLUTE: number;
static JOINT_TYPE_WELD: number;
static JOINT_TYPE_WHEEL: number;
static JOINT_TYPE_PRISMATIC: number;
static JOINT_TYPE_DISTANCE: number;
static JOINT_TYPE_ROPE: number;
static JOINT_TYPE_MOUSE: number;
static JOINT_LINEAR_SLOP: number;
static JOINT_ANGULAR_SLOP: number;
static JOINT_MAX_LINEAR_CORRECTION: number;
static JOINT_MAX_ANGULAR_CORRECTION: number;
static JOINT_LIMIT_STATE_INACTIVE: number;
static JOINT_LIMIT_STATE_AT_LOWER: number;
static JOINT_LIMIT_STATE_AT_UPPER: number;
static JOINT_LIMIT_STATE_EQUAL_LIMITS: number;
static CONTACT_SOLVER_COLLISION_SLOP: number;
static CONTACT_SOLVER_BAUMGARTE: number;
static CONTACT_SOLVER_MAX_LINEAR_CORRECTION: number;
static bodyCounter: number;
static jointCounter: number;
static shapeCounter: number;
public space: Space;
public lastTime: number;
public frameRateHz: number;
public timeDelta: number;
public paused: bool;
public step: bool;
public velocityIterations: number;
public positionIterations: number;
public allowSleep: bool;
public warmStarting: bool;
public update(): void;
public pixelsToMeters(value: number): number;
public metersToPixels(value: number): number;
static pixelsToMeters(value: number): number;
static metersToPixels(value: number): number;
static p2m(value: number): number;
static m2p(value: number): number;
static areaForCircle(radius_outer, radius_inner): number;
static inertiaForCircle(mass, center, radius_outer, radius_inner): number;
static areaForSegment(a, b, radius): number;
static centroidForSegment(a, b): Vec2;
static inertiaForSegment(mass, a, b): number;
static areaForPoly(verts): number;
static centroidForPoly(verts): Vec2;
static inertiaForPoly(mass, verts, offset): number;
static inertiaForBox(mass, w, h): number;
static createConvexHull(points): any[];
}
}
/**
* Phaser - 2D AABB
*
* A 2D AABB object
*/
module Phaser.Physics.Advanced {
class Bounds {
/**
* Creates a new 2D AABB object.
* @class Bounds
* @constructor
* @return {Bounds} This object
**/
constructor(mins?: Vec2, maxs?: Vec2);
public mins: Vec2;
public maxs: Vec2;
public toString(): string;
public setTo(mins: Vec2, maxs: Vec2): void;
public copy(b: Bounds): Bounds;
public clear(): Bounds;
public isEmpty(): bool;
public getPerimeter(): number;
public addPoint(p: Vec2): Bounds;
public addBounds(b: Bounds): Bounds;
public addBounds2(mins, maxs): Bounds;
public addExtents(center: Vec2, extent_x: number, extent_y: number): Bounds;
public expand(ax: number, ay: number): Bounds;
public containPoint(p: Vec2): bool;
public intersectsBounds(b: Bounds): bool;
static expand(b: Bounds, ax, ay);
}
}
/**
* Phaser - Advanced Physics - IShape
*
* Based on the work Ju Hyung Lee started in JS PhyRus.
*/
module Phaser.Physics.Advanced {
interface IShape {
id: number;
type: number;
elasticity: number;
friction: number;
density: number;
body: Body;
bounds: Bounds;
area(): number;
centroid(): Vec2;
inertia(mass: number): number;
cacheData(xf: Transform);
pointQuery(p: Vec2): bool;
findEdgeByPoint(p: Vec2, minDist: number): number;
findVertexByPoint(p: Vec2, minDist: number): number;
}
}
/**
* Phaser - Advanced Physics - Shape
*
* Based on the work Ju Hyung Lee started in JS PhyRus.
*/
module Phaser.Physics.Advanced {
class Shape {
constructor(type: number);
public id: number;
public type: number;
public body: Body;
public elasticity: number;
public friction: number;
public density: number;
public bounds: Bounds;
public findEdgeByPoint(p: Vec2, minDist: number): number;
}
}
/**
* Phaser - Advanced Physics - Contact
*
* Based on the work Ju Hyung Lee started in JS PhyRus.
*/
module Phaser.Physics.Advanced {
class Contact {
constructor(p, n, d, hash);
public hash;
public r1: Vec2;
public r2: Vec2;
public r1_local: Vec2;
public r2_local: Vec2;
public bounce: number;
public emn: number;
public emt: number;
public point;
public normal: Vec2;
public depth;
public lambdaNormal;
public lambdaTangential;
}
}
module Phaser.Physics.Advanced {
class ContactSolver {
constructor(shape1, shape2);
public shape1;
public shape2;
public contacts: Contact[];
public elasticity: number;
public friction: number;
public update(newContactArr: Contact[]): void;
public initSolver(dt_inv): void;
public warmStart(): void;
public solveVelocityConstraints(): void;
public solvePositionConstraints(): bool;
public clamp(v, min, max);
}
}
/**
* Phaser - Advanced Physics - Shape - Circle
*
* Based on the work Ju Hyung Lee started in JS PhyRus.
*/
module Phaser.Physics.Advanced.Shapes {
class Circle extends Shape implements IShape {
constructor(radius: number, x?: number, y?: number);
public radius: number;
public center: Vec2;
public tc: Vec2;
public finishVerts(): void;
public duplicate(): Circle;
public recenter(c: Vec2): void;
public transform(xf: Transform): void;
public untransform(xf: Transform): void;
public area(): number;
public centroid(): Vec2;
public inertia(mass: number): number;
public cacheData(xf: Transform): void;
public pointQuery(p: Vec2): bool;
public findVertexByPoint(p: Vec2, minDist: number): number;
public distanceOnPlane(n, d): void;
}
}
/**
* Phaser - Advanced Physics - Shapes - Convex Polygon
*
* Based on the work Ju Hyung Lee started in JS PhyRus.
*/
module Phaser.Physics.Advanced.Shapes {
class Poly extends Shape implements IShape {
constructor(verts?: Vec2[]);
public verts: Vec2[];
public planes;
public tverts;
public tplanes;
public convexity: bool;
public finishVerts(): void;
public duplicate(): Poly;
public recenter(c): void;
public transform(xf): void;
public untransform(xf): void;
public area(): number;
public centroid(): Vec2;
public inertia(mass: number): number;
public cacheData(xf: Transform): void;
public pointQuery(p: Vec2): bool;
public findVertexByPoint(p: Vec2, minDist: number): number;
public findEdgeByPoint(p: Vec2, minDist: number): number;
public distanceOnPlane(n, d): number;
public containPoint(p): bool;
public containPointPartial(p, n): bool;
}
}
/**
* Phaser - Advanced Physics - Shapes - Segment
*
* Based on the work Ju Hyung Lee started in JS PhyRus.
*/
module Phaser.Physics.Advanced.Shapes {
class Segment extends Shape implements IShape {
constructor(a, b, radius: number);
public a: Vec2;
public b: Vec2;
public radius: number;
public normal: Vec2;
public ta: Vec2;
public tb: Vec2;
public tn: Vec2;
public finishVerts(): void;
public duplicate(): Segment;
public recenter(c): void;
public transform(xf: Transform): void;
public untransform(xf: Transform): void;
public area(): number;
public centroid(): Vec2;
public inertia(mass: number): number;
public cacheData(xf: Transform): void;
public pointQuery(p: Vec2): bool;
public findVertexByPoint(p: Vec2, minDist: number): number;
public distanceOnPlane(n, d): number;
}
}
/**
* Phaser - Advanced Physics - Collision Handlers
*
* Based on the work Ju Hyung Lee started in JS PhyRus.
*/
module Phaser.Physics.Advanced {
class Collision {
constructor();
public collide(a, b, contacts: Contact[]): number;
private _circle2Circle(c1, r1, c2, r2, contactArr);
public circle2Circle(circ1: Shapes.Circle, circ2: Shapes.Circle, contactArr: Contact[]): number;
public circle2Segment(circ: Shapes.Circle, seg: Shapes.Segment, contactArr: Contact[]): number;
public circle2Poly(circ: Shapes.Circle, poly: Shapes.Poly, contactArr: Contact[]): number;
public segmentPointDistanceSq(seg: Shapes.Segment, p): number;
public segment2Segment(seg1: Shapes.Segment, seg2: Shapes.Segment, contactArr: Contact[]): number;
public findPointsBehindSeg(contactArr: Contact[], seg: Shapes.Segment, poly: Shapes.Poly, dist: number, coef: number): void;
public segment2Poly(seg: Shapes.Segment, poly: Shapes.Poly, contactArr: Contact[]): number;
public findMSA(poly: Shapes.Poly, planes, num: number): {
dist: number;
index: number;
};
public findVertsFallback(contactArr: Contact[], poly1: Shapes.Poly, poly2: Shapes.Poly, n, dist: number): number;
public findVerts(contactArr: Contact[], poly1: Shapes.Poly, poly2: Shapes.Poly, n, dist: number): number;
public poly2Poly(poly1: Shapes.Poly, poly2: Shapes.Poly, contactArr: Contact[]): number;
}
}
/**
* Phaser - Advanced Physics - Joint
*
* Based on the work Ju Hyung Lee started in JS PhyRus.
*/
module Phaser.Physics.Advanced {
interface IJoint {
id: number;
type: number;
body1: Body;
body2: Body;
collideConnected;
maxForce: number;
breakable: bool;
anchor1: Vec2;
anchor2: Vec2;
getWorldAnchor1();
getWorldAnchor2();
setWorldAnchor1(anchor1);
setWorldAnchor2(anchor2);
initSolver(dt, warmStarting);
solveVelocityConstraints();
solvePositionConstraints();
getReactionForce(dt_inv);
}
}
/**
* Phaser - Advanced Physics - Space
*
* Based on the work Ju Hyung Lee started in JS PhyRus.
*/
module Phaser.Physics.Advanced {
class Space {
constructor();
static TIME_TO_SLEEP: number;
static SLEEP_LINEAR_TOLERANCE: number;
static SLEEP_ANGULAR_TOLERANCE: number;
public bodyArr: Body[];
public bodyHash;
public jointArr: IJoint[];
public jointHash;
public numContacts: number;
public contactSolvers: ContactSolver[];
public postSolve;
public gravity: Vec2;
public damping: number;
public stepCount: number;
public clear(): void;
public addBody(body: Body): void;
public removeBody(body: Body): void;
public addJoint(joint: IJoint): void;
public removeJoint(joint: IJoint): void;
public findShapeByPoint(p, refShape);
public findBodyByPoint(p, refBody: Body);
public shapeById(id): IShape;
public jointById(id): IJoint;
public findVertexByPoint(p, minDist, refVertexId): number;
public findEdgeByPoint(p, minDist, refEdgeId): number;
public findJointByPoint(p, minDist, refJointId): number;
public findContactSolver(shape1, shape2): ContactSolver;
public genTemporalContactSolvers(): any[];
public initSolver(dt, dt_inv, warmStarting): void;
public velocitySolver(iteration): void;
public positionSolver(iteration): bool;
public step(dt, vel_iteration, pos_iteration, warmStarting, allowSleep): void;
}
}
/**
* Phaser - Advanced Physics - Body
*
* Based on the work Ju Hyung Lee started in JS PhyRus.
*/
module Phaser.Physics.Advanced {
class Body {
constructor(sprite: Sprite, type: number, x?: number, y?: number);
/**
* Reference to Phaser.Game
*/
public game: Game;
/**
* Reference to the parent Sprite
*/
public sprite: Sprite;
/**
* The Body ID
*/
public id: number;
/**
* The Body name
*/
public name: string;
/**
* The type of Body (disabled, dynamic, static or kinematic)
* Disabled = skips all physics operations / tests (default)
* Dynamic = gives and receives impacts
* Static = gives but doesn't receive impacts, cannot be moved by physics
* Kinematic = gives impacts, but never receives, can be moved by physics
* @type {number}
*/
public type: number;
public angle: number;
public transform: Transform;
public centroid: Vec2;
public position: Vec2;
public velocity: Vec2;
public force: Vec2;
public angularVelocity: number;
public torque: number;
public linearDamping: number;
public angularDamping: number;
public sleepTime: number;
public awaked: bool;
public shapes: IShape[];
public joints: IJoint[];
public jointHash: {};
public bounds: Bounds;
public fixedRotation: bool;
public categoryBits: number;
public maskBits: number;
public stepCount: number;
public space: Space;
public duplicate(): void;
public isDisabled : bool;
public isStatic : bool;
public isKinetic : bool;
public isDynamic : bool;
public setType(type: number): void;
public addShape(shape);
public removeShape(shape): void;
public mass: number;
public massInverted: number;
public inertia: number;
public inertiaInverted: number;
private setMass(mass);
private setInertia(inertia);
public setTransform(pos, angle): void;
public syncTransform(): void;
public getWorldPoint(p: Vec2): Vec2;
public getWorldVector(v): Vec2;
public getLocalPoint(p): Vec2;
public getLocalVector(v): Vec2;
public setFixedRotation(flag): void;
public resetMassData(): void;
public resetJointAnchors(): void;
public cacheData(): void;
private _tempVec2;
public updateVelocity(gravity, dt, damping): void;
public updatePosition(dt): void;
public resetForce(): void;
public applyForce(force, p): void;
public applyForceToCenter(force): void;
public applyTorque(torque): void;
public applyLinearImpulse(impulse, p): void;
public applyAngularImpulse(impulse: number): void;
public kineticEnergy(): number;
public isAwake : bool;
public awake(flag): void;
public isCollidable(other): bool;
}
}
/**
* Phaser - Advanced Physics - Shapes - Box
*
* Based on the work Ju Hyung Lee started in JS PhyRus.
*/
module Phaser.Physics.Advanced.Shapes {
class Box extends Poly {
constructor(x, y, width, height);
}
}
/**
* Phaser - Advanced Physics - Shapes - Triangle
*
* Based on the work Ju Hyung Lee started in JS PhyRus.
*/
module Phaser.Physics.Advanced.Shapes {
class Triangle extends Poly {
constructor(p1, p2, p3);
}
}
/**
* Phaser - PixelUtils
*
* A collection of methods useful for manipulating pixels.

File diff suppressed because it is too large Load diff