Refactoring ready for 1.0 release.

This commit is contained in:
Richard Davey
2013-05-25 04:21:24 +01:00
parent 4ef0750c07
commit 204ec46b2b
90 changed files with 15043 additions and 15223 deletions
+84
View File
@@ -0,0 +1,84 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<ProjectGuid>{1106D1E1-DCE3-4CAF-8096-6C85F765D519}</ProjectGuid>
<ProjectTypeGuids>{349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>
<OutputType>Library</OutputType>
<OutputPath>bin</OutputPath>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<DebugType>full</DebugType>
<DebugSymbols>true</DebugSymbols>
<UseIISExpress>true</UseIISExpress>
<IISExpressSSLPort />
<IISExpressAnonymousAuthentication />
<IISExpressWindowsAuthentication />
<IISExpressUseClassicPipelineMode />
</PropertyGroup>
<ItemGroup>
<Content Include="verlet\AngleConstraint.js">
<DependentUpon>AngleConstraint.ts</DependentUpon>
</Content>
<Content Include="verlet\Composite.js">
<DependentUpon>Composite.ts</DependentUpon>
</Content>
<Content Include="verlet\DistanceConstraint.js">
<DependentUpon>DistanceConstraint.ts</DependentUpon>
</Content>
<Content Include="verlet\Particle.js">
<DependentUpon>Particle.ts</DependentUpon>
</Content>
<Content Include="verlet\PinConstraint.js">
<DependentUpon>PinConstraint.ts</DependentUpon>
</Content>
<Content Include="verlet\VerletManager.js">
<DependentUpon>VerletManager.ts</DependentUpon>
</Content>
<XamlAppDef Include="verlet\VerletManager.ts" />
<XamlAppDef Include="verlet\PinConstraint.ts" />
<XamlAppDef Include="verlet\Particle.ts" />
<XamlAppDef Include="verlet\DistanceConstraint.ts" />
<XamlAppDef Include="verlet\Composite.ts" />
<XamlAppDef Include="verlet\AngleConstraint.ts" />
</ItemGroup>
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<PropertyGroup>
<RootNamespace>Plugins</RootNamespace>
</PropertyGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<Import Project="$(VSToolsPath)\WebApplications\Microsoft.WebApplication.targets" Condition="'$(VSToolsPath)' != ''" />
<ProjectExtensions>
<VisualStudio>
<FlavorProperties GUID="{349c5851-65df-11da-9384-00065b846f21}">
<WebProjectProperties>
<UseIIS>True</UseIIS>
<AutoAssignPort>True</AutoAssignPort>
<DevelopmentServerPort>0</DevelopmentServerPort>
<DevelopmentServerVPath>/</DevelopmentServerVPath>
<IISUrl>http://localhost:61985/</IISUrl>
<NTLMAuthentication>False</NTLMAuthentication>
<UseCustomServer>False</UseCustomServer>
<CustomServerUrl>
</CustomServerUrl>
<SaveServerSettingsInUserFile>False</SaveServerSettingsInUserFile>
</WebProjectProperties>
</FlavorProperties>
</VisualStudio>
</ProjectExtensions>
<PropertyGroup Condition="'$(Configuration)' == 'Debug'">
<TypeScriptTarget>ES3</TypeScriptTarget>
<TypeScriptIncludeComments>true</TypeScriptIncludeComments>
<TypeScriptSourceMap>true</TypeScriptSourceMap>
<TypeScriptModuleKind>AMD</TypeScriptModuleKind>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
<TypeScriptTarget>ES3</TypeScriptTarget>
<TypeScriptIncludeComments>false</TypeScriptIncludeComments>
<TypeScriptSourceMap>false</TypeScriptSourceMap>
<TypeScriptModuleKind>AMD</TypeScriptModuleKind>
</PropertyGroup>
<Import Project="$(VSToolsPath)\TypeScript\Microsoft.TypeScript.targets" />
</Project>
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"app.js","sources":["app.ts"],"names":["Greeter","Greeter.constructor","Greeter.start","","Greeter.stop","onload"],"mappings":"AAAA;IAKIA,SALEA,OAAOA,CAKGA,OAAoBA;QAC5BC,IAAIA,CAACA,OAAOA,GAAGA,OAAOA;QACtBA,IAAIA,CAACA,OAAOA,CAACA,SAASA,IAAIA,eAAeA;QACzCA,IAAIA,CAACA,IAAIA,GAAGA,QAAQA,CAACA,aAAaA,CAACA,MAAMA,CAACA;QAC1CA,IAAIA,CAACA,OAAOA,CAACA,WAAWA,CAACA,IAAIA,CAACA,IAAIA,CAACA;QACnCA,IAAIA,CAACA,IAAIA,CAACA,SAASA,GAAGA,IAAIA,IAAIA,EAAEA,CAACA,WAAWA,EAAEA;IAClDA,CAACA;IAEDD,0BAAAA;QAAAE,iBAECA;QADGA,IAAIA,CAACA,UAAUA,GAAGA,WAAWA,CAACA;YAAMC,OAAAA,KAAIA,CAACA,IAAIA,CAACA,SAASA,GAAGA,IAAIA,IAAIA,EAAEA,CAACA,WAAWA,EAAEA,CAAAA;QAA9CA,CAA8CA,EAAED,GAAGA,CAACA;IAC5FA,CAACA;IAEDF,yBAAAA;QACII,YAAYA,CAACA,IAAIA,CAACA,UAAUA,CAACA;IACjCA,CAACA;IAELJ;AAACA,CAAAA,IAAA;AAED,MAAM,CAAC,MAAM,GAAG;IACZK,IAAIA,EAAEA,GAAGA,QAAQA,CAACA,cAAcA,CAACA,SAASA,CAACA,CAACA;IAC5CA,IAAIA,OAAOA,GAAGA,IAAIA,OAAOA,CAACA,EAAEA,CAACA,CAACA;IAC9BA,OAAOA,CAACA,KAAKA,EAAEA;AACnBA,CAACA"}
+59
View File
@@ -0,0 +1,59 @@
var Phaser;
(function (Phaser) {
/// <reference path="../Game.ts" />
/// <reference path="Particle.ts" />
/// <reference path="../geom/Vector2.ts" />
/**
* Phaser - AngleConstraint
*
* constrains 3 particles to an angle
*/
(function (Verlet) {
var AngleConstraint = (function () {
/**
* Creates a new AngleConstraint object.
* @class AngleConstraint
* @constructor
* @param {Number} x The x coordinate of vector2
* @param {Number} y The y coordinate of vector2
* @return {AngleConstraint} This object
**/
function AngleConstraint(a, b, c, stiffness) {
this.a = a;
this.b = b;
this.c = c;
this.angle = this.b.pos.angle2(this.a.pos, this.c.pos);
this.stiffness = stiffness;
}
AngleConstraint.prototype.relax = function (stepCoef) {
var angle = this.b.pos.angle2(this.a.pos, this.c.pos);
var diff = angle - this.angle;
if(diff <= -Math.PI) {
diff += 2 * Math.PI;
} else if(diff >= Math.PI) {
diff -= 2 * Math.PI;
}
diff *= stepCoef * this.stiffness;
this.a.pos = this.a.pos.rotate(this.b.pos, diff);
this.c.pos = this.c.pos.rotate(this.b.pos, -diff);
this.b.pos = this.b.pos.rotate(this.a.pos, diff);
this.b.pos = this.b.pos.rotate(this.c.pos, -diff);
};
AngleConstraint.prototype.render = function (ctx) {
ctx.beginPath();
ctx.moveTo(this.a.pos.x, this.a.pos.y);
ctx.lineTo(this.b.pos.x, this.b.pos.y);
ctx.lineTo(this.c.pos.x, this.c.pos.y);
var tmp = ctx.lineWidth;
ctx.lineWidth = 5;
ctx.strokeStyle = "rgba(255,255,0,0.2)";
ctx.stroke();
ctx.lineWidth = tmp;
};
return AngleConstraint;
})();
Verlet.AngleConstraint = AngleConstraint;
})(Phaser.Verlet || (Phaser.Verlet = {}));
var Verlet = Phaser.Verlet;
})(Phaser || (Phaser = {}));
//@ sourceMappingURL=AngleConstraint.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"AngleConstraint.js","sources":["AngleConstraint.ts"],"names":["Phaser","Phaser.Verlet","Phaser.Verlet.AngleConstraint","Phaser.Verlet.AngleConstraint.constructor","Phaser.Verlet.AngleConstraint.relax","Phaser.Verlet.AngleConstraint.render"],"mappings":"AAUA,IAAO,MAAM;AA+DZ,CA/DD,UAAO,MAAM;IAVbA,mCAAmCA;IACnCA,oCAAoCA;IACpCA,2CAA2CA;IAE3CA;;;;MAIEA;KAEKA,UAAOA,MAAMA;QAEhBC;YAUIC;;;;;;;eADGA;YACHA,SAVSA,eAAeA,CAUZA,CAAyBA,EAAEA,CAAyBA,EAAEA,CAAyBA,EAAEA,SAAiBA;gBAE1GC,IAAIA,CAACA,CAACA,GAAGA,CAACA;gBACVA,IAAIA,CAACA,CAACA,GAAGA,CAACA;gBACVA,IAAIA,CAACA,CAACA,GAAGA,CAACA;gBACVA,IAAIA,CAACA,KAAKA,GAAGA,IAAIA,CAACA,CAACA,CAACA,GAAGA,CAACA,MAAMA,CAACA,IAAIA,CAACA,CAACA,CAACA,GAAGA,EAAEA,IAAIA,CAACA,CAACA,CAACA,GAAGA,CAACA;gBACtDA,IAAIA,CAACA,SAASA,GAAGA,SAASA;YAE9BA,CAACA;YAQDD,kCAAAA,UAAaA,QAAgBA;gBAEzBE,IAAIA,KAAKA,GAAGA,IAAIA,CAACA,CAACA,CAACA,GAAGA,CAACA,MAAMA,CAACA,IAAIA,CAACA,CAACA,CAACA,GAAGA,EAAEA,IAAIA,CAACA,CAACA,CAACA,GAAGA,CAACA,CAACA;gBACtDA,IAAIA,IAAIA,GAAGA,KAAKA,GAAGA,IAAIA,CAACA,KAAKA,CAACA;gBAE9BA,GAAIA,IAAIA,IAAIA,CAACA,IAAIA,CAACA,EAAEA,CAACA;oBACjBA,IAAIA,IAAIA,CAACA,GAAGA,IAAIA,CAACA,EAAEA;iBAACA,MACnBA,GAAIA,IAAIA,IAAIA,IAAIA,CAACA,EAAEA,CAACA;oBACrBA,IAAIA,IAAIA,CAACA,GAAGA,IAAIA,CAACA,EAAEA;iBAACA;gBAExBA,IAAIA,IAAIA,QAAQA,GAAGA,IAAIA,CAACA,SAASA;gBAEjCA,IAAIA,CAACA,CAACA,CAACA,GAAGA,GAAGA,IAAIA,CAACA,CAACA,CAACA,GAAGA,CAACA,MAAMA,CAACA,IAAIA,CAACA,CAACA,CAACA,GAAGA,EAAEA,IAAIA,CAACA;gBAChDA,IAAIA,CAACA,CAACA,CAACA,GAAGA,GAAGA,IAAIA,CAACA,CAACA,CAACA,GAAGA,CAACA,MAAMA,CAACA,IAAIA,CAACA,CAACA,CAACA,GAAGA,EAAEA,CAACA,IAAIA,CAACA;gBACjDA,IAAIA,CAACA,CAACA,CAACA,GAAGA,GAAGA,IAAIA,CAACA,CAACA,CAACA,GAAGA,CAACA,MAAMA,CAACA,IAAIA,CAACA,CAACA,CAACA,GAAGA,EAAEA,IAAIA,CAACA;gBAChDA,IAAIA,CAACA,CAACA,CAACA,GAAGA,GAAGA,IAAIA,CAACA,CAACA,CAACA,GAAGA,CAACA,MAAMA,CAACA,IAAIA,CAACA,CAACA,CAACA,GAAGA,EAAEA,CAACA,IAAIA,CAACA;YAErDA,CAACA;YAEDF,mCAAAA,UAAcA,GAAGA;gBAEbG,GAAGA,CAACA,SAASA,EAAEA;gBACfA,GAAGA,CAACA,MAAMA,CAACA,IAAIA,CAACA,CAACA,CAACA,GAAGA,CAACA,CAACA,EAAEA,IAAIA,CAACA,CAACA,CAACA,GAAGA,CAACA,CAACA,CAACA;gBACtCA,GAAGA,CAACA,MAAMA,CAACA,IAAIA,CAACA,CAACA,CAACA,GAAGA,CAACA,CAACA,EAAEA,IAAIA,CAACA,CAACA,CAACA,GAAGA,CAACA,CAACA,CAACA;gBACtCA,GAAGA,CAACA,MAAMA,CAACA,IAAIA,CAACA,CAACA,CAACA,GAAGA,CAACA,CAACA,EAAEA,IAAIA,CAACA,CAACA,CAACA,GAAGA,CAACA,CAACA,CAACA;gBACtCA,IAAIA,GAAGA,GAAGA,GAAGA,CAACA,SAASA,CAACA;gBACxBA,GAAGA,CAACA,SAASA,GAAGA,CAACA;gBACjBA,GAAGA,CAACA,WAAWA,GAAGA,qBAAqBA;gBACvCA,GAAGA,CAACA,MAAMA,EAAEA;gBACZA,GAAGA,CAACA,SAASA,GAAGA,GAAGA;YAEvBA,CAACA;YAELH;AAACA,QAADA,CAACA,IAAAD;QA3DDA,yCA2DCA,QAAAA;IAELA,CAACA,yCAAAD;IA/DMA;AA+DNA,CAAAA,2BAAA"}
+74
View File
@@ -0,0 +1,74 @@
/// <reference path="../Game.ts" />
/// <reference path="Particle.ts" />
/// <reference path="../geom/Vector2.ts" />
/**
* Phaser - AngleConstraint
*
* constrains 3 particles to an angle
*/
module Phaser.Verlet {
export class AngleConstraint {
/**
* Creates a new AngleConstraint object.
* @class AngleConstraint
* @constructor
* @param {Number} x The x coordinate of vector2
* @param {Number} y The y coordinate of vector2
* @return {AngleConstraint} This object
**/
constructor(a: Phaser.Verlet.Particle, b: Phaser.Verlet.Particle, c: Phaser.Verlet.Particle, stiffness: number) {
this.a = a;
this.b = b;
this.c = c;
this.angle = this.b.pos.angle2(this.a.pos, this.c.pos);
this.stiffness = stiffness;
}
public a: Phaser.Verlet.Particle;
public b: Phaser.Verlet.Particle;
public c: Phaser.Verlet.Particle;
public angle: number;
public stiffness: number;
public relax(stepCoef: number) {
var angle = this.b.pos.angle2(this.a.pos, this.c.pos);
var diff = angle - this.angle;
if (diff <= -Math.PI)
diff += 2 * Math.PI;
else if (diff >= Math.PI)
diff -= 2 * Math.PI;
diff *= stepCoef * this.stiffness;
this.a.pos = this.a.pos.rotate(this.b.pos, diff);
this.c.pos = this.c.pos.rotate(this.b.pos, -diff);
this.b.pos = this.b.pos.rotate(this.a.pos, diff);
this.b.pos = this.b.pos.rotate(this.c.pos, -diff);
}
public render(ctx) {
ctx.beginPath();
ctx.moveTo(this.a.pos.x, this.a.pos.y);
ctx.lineTo(this.b.pos.x, this.b.pos.y);
ctx.lineTo(this.c.pos.x, this.c.pos.y);
var tmp = ctx.lineWidth;
ctx.lineWidth = 5;
ctx.strokeStyle = "rgba(255,255,0,0.2)";
ctx.stroke();
ctx.lineWidth = tmp;
}
}
}
+144
View File
@@ -0,0 +1,144 @@
var Phaser;
(function (Phaser) {
/// <reference path="../Game.ts" />
/// <reference path="../geom/Vector2.ts" />
/// <reference path="Particle.ts" />
/// <reference path="PinConstraint.ts" />
/**
* Phaser - Verlet - Composite
*
*
*/
(function (Verlet) {
var Composite = (function () {
/**
* Creates a new Composite object.
* @class Composite
* @constructor
* @param {Number} x The x coordinate of vector2
* @param {Number} y The y coordinate of vector2
* @return {Composite} This object
**/
function Composite(game) {
/**
* Texture of the particles to be rendered.
*/
this._texture = null;
// local rendering related temp vars to help avoid gc spikes
this._sx = 0;
this._sy = 0;
this._sw = 0;
this._sh = 0;
this._dx = 0;
this._dy = 0;
this._dw = 0;
this._dh = 0;
this._hw = 0;
this._hh = 0;
this.drawParticles = null;
this.drawConstraints = null;
this.hideConstraints = true;
this.constraintLineColor = 'rgba(200,200,200,1)';
this._game = game;
this.sprites = [];
this.particles = [];
this.constraints = [];
this.frameBounds = new Phaser.Quad();
}
Composite.prototype.createDistanceConstraint = // Create Constraints
function (a, b, stiffness, distance) {
if (typeof distance === "undefined") { distance = null; }
this.constraints.push(new Phaser.Verlet.DistanceConstraint(a, b, stiffness, distance));
return this.constraints[this.constraints.length - 1];
};
Composite.prototype.createAngleConstraint = function (a, b, c, stiffness) {
this.constraints.push(new Phaser.Verlet.AngleConstraint(a, b, c, stiffness));
return this.constraints[this.constraints.length - 1];
};
Composite.prototype.createPinConstraint = function (a, pos) {
this.constraints.push(new Phaser.Verlet.PinConstraint(a, pos));
return this.constraints[this.constraints.length - 1];
};
Composite.prototype.loadGraphic = /**
* Load a graphic for this Composite. The graphic cannot be a SpriteSheet yet.
* @param key {string} Key of the graphic you want to load for this sprite.
* @return {Composite} This object
*/
function (key) {
if(this._game.cache.getImage(key) !== null) {
if(this._game.cache.isSpriteSheet(key) == false) {
this._texture = this._game.cache.getImage(key);
this.frameBounds.width = this._texture.width;
this.frameBounds.height = this._texture.height;
this._hw = Math.floor(this.frameBounds.width / 2);
this._hh = Math.floor(this.frameBounds.width / 2);
this.drawParticles = this.render;
this.drawConstraints = this.renderConstraints;
}
}
return this;
};
Composite.prototype.renderConstraints = function (context) {
if(this.hideConstraints == true || this.constraints.length == 0) {
return;
}
var i;
context.beginPath();
for(i in this.constraints) {
if(this.constraints[i].b) {
context.moveTo(this.constraints[i].a.pos.x, this.constraints[i].a.pos.y);
context.lineTo(this.constraints[i].b.pos.x, this.constraints[i].b.pos.y);
}
}
context.strokeStyle = this.constraintLineColor;
context.stroke();
context.closePath();
};
Composite.prototype.render = function (context) {
this._sx = 0;
this._sy = 0;
this._sw = this.frameBounds.width;
this._sh = this.frameBounds.height;
this._dw = this.frameBounds.width;
this._dh = this.frameBounds.height;
this._sx = Math.round(this._sx);
this._sy = Math.round(this._sy);
this._sw = Math.round(this._sw);
this._sh = Math.round(this._sh);
this._dw = Math.round(this._dw);
this._dh = Math.round(this._dh);
var i;
for(i in this.particles) {
//this._dx = cameraOffsetX + (this.frameBounds.topLeft.x - camera.worldView.x);
//this._dy = cameraOffsetY + (this.frameBounds.topLeft.y - camera.worldView.y);
this._dx = this.particles[i].pos.x - this._hw;
this._dy = this.particles[i].pos.y - this._hh;
this._dx = Math.round(this._dx);
this._dy = Math.round(this._dy);
context.drawImage(this._texture, // Source Image
this._sx, // Source X (location within the source image)
this._sy, // Source Y
this._sw, // Source Width
this._sh, // Source Height
this._dx, // Destination X (where on the canvas it'll be drawn)
this._dy, // Destination Y
this._dw, // Destination Width (always same as Source Width unless scaled)
this._dh);
// Destination Height (always same as Source Height unless scaled)
}
};
Composite.prototype.pin = function (index, pos) {
if (typeof pos === "undefined") { pos = null; }
if(pos == null) {
pos = this.particles[index].pos;
}
var pc = new Phaser.Verlet.PinConstraint(this.particles[index], pos);
this.constraints.push(pc);
return pc;
};
return Composite;
})();
Verlet.Composite = Composite;
})(Phaser.Verlet || (Phaser.Verlet = {}));
var Verlet = Phaser.Verlet;
})(Phaser || (Phaser = {}));
+203
View File
@@ -0,0 +1,203 @@
/// <reference path="../Game.ts" />
/// <reference path="../geom/Vector2.ts" />
/// <reference path="Particle.ts" />
/// <reference path="PinConstraint.ts" />
/**
* Phaser - Verlet - Composite
*
*
*/
module Phaser.Verlet {
export class Composite {
/**
* Creates a new Composite object.
* @class Composite
* @constructor
* @param {Number} x The x coordinate of vector2
* @param {Number} y The y coordinate of vector2
* @return {Composite} This object
**/
constructor(game: Game) {
this._game = game;
this.sprites = [];
this.particles = [];
this.constraints = [];
this.frameBounds = new Phaser.Quad();
}
private _game: Game;
/**
* Texture of the particles to be rendered.
*/
private _texture = null;
/**
* Rendering bounds for the texture
* @type {Quad}
*/
private frameBounds: Quad;
// local rendering related temp vars to help avoid gc spikes
private _sx: number = 0;
private _sy: number = 0;
private _sw: number = 0;
private _sh: number = 0;
private _dx: number = 0;
private _dy: number = 0;
private _dw: number = 0;
private _dh: number = 0;
private _hw: number = 0;
private _hh: number = 0;
public sprites: Phaser.Sprite[];
public particles: Phaser.Verlet.Particle[];
public constraints;
public drawParticles = null;
public drawConstraints = null;
// Create Constraints
public createDistanceConstraint(a: Phaser.Verlet.Particle, b: Phaser.Verlet.Particle, stiffness: number, distance?: number = null): Phaser.Verlet.DistanceConstraint {
this.constraints.push(new Phaser.Verlet.DistanceConstraint(a, b, stiffness, distance));
return this.constraints[this.constraints.length - 1];
}
public createAngleConstraint(a: Phaser.Verlet.Particle, b: Phaser.Verlet.Particle, c: Phaser.Verlet.Particle, stiffness: number): Phaser.Verlet.AngleConstraint {
this.constraints.push(new Phaser.Verlet.AngleConstraint(a, b, c, stiffness));
return this.constraints[this.constraints.length - 1];
}
public createPinConstraint(a: Phaser.Verlet.Particle, pos: Vector2): Phaser.Verlet.PinConstraint {
this.constraints.push(new Phaser.Verlet.PinConstraint(a, pos));
return this.constraints[this.constraints.length - 1];
}
/**
* Load a graphic for this Composite. The graphic cannot be a SpriteSheet yet.
* @param key {string} Key of the graphic you want to load for this sprite.
* @return {Composite} This object
*/
public loadGraphic(key: string): Composite {
if (this._game.cache.getImage(key) !== null)
{
if (this._game.cache.isSpriteSheet(key) == false)
{
this._texture = this._game.cache.getImage(key);
this.frameBounds.width = this._texture.width;
this.frameBounds.height = this._texture.height;
this._hw = Math.floor(this.frameBounds.width / 2);
this._hh = Math.floor(this.frameBounds.width / 2);
this.drawParticles = this.render;
this.drawConstraints = this.renderConstraints;
}
}
return this;
}
public hideConstraints: bool = true;
public constraintLineColor: string = 'rgba(200,200,200,1)';
private renderConstraints(context) {
if (this.hideConstraints == true || this.constraints.length == 0)
{
return;
}
var i;
context.beginPath();
for (i in this.constraints)
{
if (this.constraints[i].b)
{
context.moveTo(this.constraints[i].a.pos.x, this.constraints[i].a.pos.y);
context.lineTo(this.constraints[i].b.pos.x, this.constraints[i].b.pos.y);
}
}
context.strokeStyle = this.constraintLineColor;
context.stroke();
context.closePath();
}
private render(context) {
this._sx = 0;
this._sy = 0;
this._sw = this.frameBounds.width;
this._sh = this.frameBounds.height;
this._dw = this.frameBounds.width;
this._dh = this.frameBounds.height;
this._sx = Math.round(this._sx);
this._sy = Math.round(this._sy);
this._sw = Math.round(this._sw);
this._sh = Math.round(this._sh);
this._dw = Math.round(this._dw);
this._dh = Math.round(this._dh);
var i;
for (i in this.particles)
{
//this._dx = cameraOffsetX + (this.frameBounds.topLeft.x - camera.worldView.x);
//this._dy = cameraOffsetY + (this.frameBounds.topLeft.y - camera.worldView.y);
this._dx = this.particles[i].pos.x - this._hw;
this._dy = this.particles[i].pos.y - this._hh;
this._dx = Math.round(this._dx);
this._dy = Math.round(this._dy);
context.drawImage(
this._texture, // Source Image
this._sx, // Source X (location within the source image)
this._sy, // Source Y
this._sw, // Source Width
this._sh, // Source Height
this._dx, // Destination X (where on the canvas it'll be drawn)
this._dy, // Destination Y
this._dw, // Destination Width (always same as Source Width unless scaled)
this._dh // Destination Height (always same as Source Height unless scaled)
);
}
}
public pin(index, pos?=null) {
if (pos == null)
{
pos = this.particles[index].pos;
}
var pc = new Phaser.Verlet.PinConstraint(this.particles[index], pos);
this.constraints.push(pc);
return pc;
}
}
}
+52
View File
@@ -0,0 +1,52 @@
var Phaser;
(function (Phaser) {
/// <reference path="../Game.ts" />
/// <reference path="Particle.ts" />
/// <reference path="../geom/Vector2.ts" />
/**
* Phaser - DistanceConstraint
*
* Constrains to initial distance
*/
(function (Verlet) {
var DistanceConstraint = (function () {
/**
* Creates a new DistanceConstraint object.
* @class DistanceConstraint
* @constructor
* @param {Number} x The x coordinate of vector2
* @param {Number} y The y coordinate of vector2
* @return {DistanceConstraint} This object
**/
function DistanceConstraint(a, b, stiffness, distance) {
if (typeof distance === "undefined") { distance = null; }
this.a = a;
this.b = b;
if(distance === null) {
this.distance = a.pos.sub(b.pos).length();
} else {
this.distance = distance;
}
this.stiffness = stiffness;
}
DistanceConstraint.prototype.relax = function (stepCoef) {
var normal = this.a.pos.sub(this.b.pos);
var m = normal.length2();
normal.mutableScale(((this.distance * this.distance - m) / m) * this.stiffness * stepCoef);
this.a.pos.mutableAdd(normal);
this.b.pos.mutableSub(normal);
};
DistanceConstraint.prototype.render = function (ctx) {
ctx.beginPath();
ctx.moveTo(this.a.pos.x, this.a.pos.y);
ctx.lineTo(this.b.pos.x, this.b.pos.y);
ctx.strokeStyle = "#d8dde2";
ctx.stroke();
ctx.closePath();
};
return DistanceConstraint;
})();
Verlet.DistanceConstraint = DistanceConstraint;
})(Phaser.Verlet || (Phaser.Verlet = {}));
var Verlet = Phaser.Verlet;
})(Phaser || (Phaser = {}));
+70
View File
@@ -0,0 +1,70 @@
/// <reference path="../Game.ts" />
/// <reference path="Particle.ts" />
/// <reference path="../geom/Vector2.ts" />
/**
* Phaser - DistanceConstraint
*
* Constrains to initial distance
*/
module Phaser.Verlet {
export class DistanceConstraint {
/**
* Creates a new DistanceConstraint object.
* @class DistanceConstraint
* @constructor
* @param {Number} x The x coordinate of vector2
* @param {Number} y The y coordinate of vector2
* @return {DistanceConstraint} This object
**/
constructor(a: Phaser.Verlet.Particle, b: Phaser.Verlet.Particle, stiffness: number, distance?:number = null) {
this.a = a;
this.b = b;
if (distance === null)
{
this.distance = a.pos.sub(b.pos).length();
}
else
{
this.distance = distance;
}
this.stiffness = stiffness;
}
public a: Phaser.Verlet.Particle;
public b: Phaser.Verlet.Particle;
public distance: number;
public stiffness: number;
public relax(stepCoef: number) {
var normal = this.a.pos.sub(this.b.pos);
var m = normal.length2();
normal.mutableScale(((this.distance * this.distance - m) / m) * this.stiffness * stepCoef);
this.a.pos.mutableAdd(normal);
this.b.pos.mutableSub(normal);
}
public render(ctx) {
ctx.beginPath();
ctx.moveTo(this.a.pos.x, this.a.pos.y);
ctx.lineTo(this.b.pos.x, this.b.pos.y);
ctx.strokeStyle = "#d8dde2";
ctx.stroke();
ctx.closePath();
}
}
}
+36
View File
@@ -0,0 +1,36 @@
var Phaser;
(function (Phaser) {
/// <reference path="../Game.ts" />
/// <reference path="../geom/Vector2.ts" />
/**
* Phaser - Verlet - Particle
*
*
*/
(function (Verlet) {
var Particle = (function () {
/**
* Creates a new Particle object.
* @class Particle
* @constructor
* @param {Number} x The x coordinate of vector2
* @param {Number} y The y coordinate of vector2
* @return {Particle} This object
**/
function Particle(pos) {
this.pos = (new Vector2()).mutableSet(pos);
this.lastPos = (new Vector2()).mutableSet(pos);
}
Particle.prototype.render = function (ctx) {
ctx.beginPath();
ctx.arc(this.pos.x, this.pos.y, 2, 0, 2 * Math.PI);
ctx.fillStyle = "#2dad8f";
ctx.fill();
};
return Particle;
})();
Verlet.Particle = Particle;
})(Phaser.Verlet || (Phaser.Verlet = {}));
var Verlet = Phaser.Verlet;
})(Phaser || (Phaser = {}));
//@ sourceMappingURL=Particle.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"Particle.js","sources":["Particle.ts"],"names":["Phaser","Phaser.Verlet","Phaser.Verlet.Particle","Phaser.Verlet.Particle.constructor","Phaser.Verlet.Particle.render"],"mappings":"AASA,IAAO,MAAM;AAkCZ,CAlCD,UAAO,MAAM;IATbA,mCAAmCA;IACnCA,2CAA2CA;IAE3CA;;;;MAIEA;KAEKA,UAAOA,MAAMA;QAEhBC;YAUIC;;;;;;;eADGA;YACHA,SAVSA,QAAQA,CAULA,GAAYA;gBAEpBC,IAAIA,CAACA,GAAGA,GAAGA,CAACA,IAAIA,OAAOA,EAAEA,EAAEA,UAAUA,CAACA,GAAGA,CAACA;gBAC1CA,IAAIA,CAACA,OAAOA,GAAGA,CAACA,IAAIA,OAAOA,EAAEA,EAAEA,UAAUA,CAACA,GAAGA,CAACA;YAGlDA,CAACA;YAKDD,4BAAAA,UAAcA,GAAGA;gBAEhBE,GAAGA,CAACA,SAASA,EAAEA;gBACfA,GAAGA,CAACA,GAAGA,CAACA,IAAIA,CAACA,GAAGA,CAACA,CAACA,EAAEA,IAAIA,CAACA,GAAGA,CAACA,CAACA,EAAEA,CAACA,EAAEA,CAACA,EAAEA,CAACA,GAACA,IAAIA,CAACA,EAAEA,CAACA;gBAChDA,GAAGA,CAACA,SAASA,GAAGA,SAASA;gBACzBA,GAAGA,CAACA,IAAIA,EAAEA;YAEXA,CAACA;YAELF;AAACA,QAADA,CAACA,IAAAD;QA9BDA,2BA8BCA,QAAAA;IAELA,CAACA,yCAAAD;IAlCMA;AAkCNA,CAAAA,2BAAA"}
+44
View File
@@ -0,0 +1,44 @@
/// <reference path="../Game.ts" />
/// <reference path="../geom/Vector2.ts" />
/**
* Phaser - Verlet - Particle
*
*
*/
module Phaser.Verlet {
export class Particle {
/**
* Creates a new Particle object.
* @class Particle
* @constructor
* @param {Number} x The x coordinate of vector2
* @param {Number} y The y coordinate of vector2
* @return {Particle} This object
**/
constructor(pos: Vector2) {
this.pos = (new Vector2()).mutableSet(pos);
this.lastPos = (new Vector2()).mutableSet(pos);
}
public pos: Vector2;
public lastPos: Vector2;
public render(ctx) {
ctx.beginPath();
ctx.arc(this.pos.x, this.pos.y, 2, 0, 2*Math.PI);
ctx.fillStyle = "#2dad8f";
ctx.fill();
}
}
}
+39
View File
@@ -0,0 +1,39 @@
var Phaser;
(function (Phaser) {
/// <reference path="../Game.ts" />
/// <reference path="Particle.ts" />
/// <reference path="../geom/Vector2.ts" />
/**
* Phaser - PinConstraint
*
* Constrains to static / fixed point
*/
(function (Verlet) {
var PinConstraint = (function () {
/**
* Creates a new PinConstraint object.
* @class PinConstraint
* @constructor
* @param {Number} x The x coordinate of vector2
* @param {Number} y The y coordinate of vector2
* @return {PinConstraint} This object
**/
function PinConstraint(a, pos) {
this.a = a;
this.pos = (new Phaser.Vector2()).mutableSet(pos);
}
PinConstraint.prototype.relax = function () {
this.a.pos.mutableSet(this.pos);
};
PinConstraint.prototype.render = function (ctx) {
ctx.beginPath();
ctx.arc(this.pos.x, this.pos.y, 6, 0, 2 * Math.PI);
ctx.fillStyle = "rgba(0,153,255,0.1)";
ctx.fill();
};
return PinConstraint;
})();
Verlet.PinConstraint = PinConstraint;
})(Phaser.Verlet || (Phaser.Verlet = {}));
var Verlet = Phaser.Verlet;
})(Phaser || (Phaser = {}));
+48
View File
@@ -0,0 +1,48 @@
/// <reference path="../Game.ts" />
/// <reference path="Particle.ts" />
/// <reference path="../geom/Vector2.ts" />
/**
* Phaser - PinConstraint
*
* Constrains to static / fixed point
*/
module Phaser.Verlet {
export class PinConstraint {
/**
* Creates a new PinConstraint object.
* @class PinConstraint
* @constructor
* @param {Number} x The x coordinate of vector2
* @param {Number} y The y coordinate of vector2
* @return {PinConstraint} This object
**/
constructor(a: Phaser.Verlet.Particle, pos: Vector2) {
this.a = a;
this.pos = (new Vector2()).mutableSet(pos);
}
public a: Phaser.Verlet.Particle;
public pos: Vector2;
public relax() {
this.a.pos.mutableSet(this.pos);
}
public render(ctx) {
ctx.beginPath();
ctx.arc(this.pos.x, this.pos.y, 6, 0, 2*Math.PI);
ctx.fillStyle = "rgba(0,153,255,0.1)";
ctx.fill();
}
}
}
+271
View File
@@ -0,0 +1,271 @@
var Phaser;
(function (Phaser) {
/// <reference path="Game.ts" />
/// <reference path="geom/Vector2.ts" />
/// <reference path="verlet/Composite.ts" />
/// <reference path="verlet/Particle.ts" />
/// <reference path="verlet/DistanceConstraint.ts" />
/// <reference path="verlet/PinConstraint.ts" />
/// <reference path="verlet/AngleConstraint.ts" />
/**
* Phaser - Verlet
*
* Based on verlet-js by Sub Protocol released under MIT
*/
(function (Verlet) {
var VerletManager = (function () {
/**
* Creates a new Vector2 object.
* @class Vector2
* @constructor
* @param {Number} x The x coordinate of vector2
* @param {Number} y The y coordinate of vector2
* @return {Vector2} This object
**/
function VerletManager(game, width, height) {
this._v = new Phaser.Vector2();
this.composites = [];
this.step = 16;
this.selectionRadius = 20;
this.draggedEntity = null;
this.highlightColor = '#4f545c';
this.hideNearestEntityCircle = false;
this._game = game;
this.width = width;
this.height = height;
this.gravity = new Phaser.Vector2(0, 0.2);
this.friction = 0.99;
this.groundFriction = 0.8;
this.canvas = game.stage.canvas;
this.context = game.stage.context;
this._game.input.onDown.add(this.mouseDownHandler, this);
this._game.input.onUp.add(this.mouseUpHandler, this);
}
VerletManager.prototype.intersectionTime = /**
* Computes time of intersection of a particle with a wall
*
* @param {Vec2} line walls root position
* @param {Vec2} p particle position
* @param {Vec2} dir walls direction
* @param {Vec2} v particles velocity
*/
function (wall, p, dir, v) {
if(dir.x != 0) {
var denominator = v.y - dir.y * v.x / dir.x;
if(denominator == 0) {
return undefined;
}// Movement is parallel to wall
var numerator = wall.y + dir.y * (p.x - wall.x) / dir.x - p.y;
return numerator / denominator;
} else {
if(v.x == 0) {
return undefined;
}// parallel again
var denominator = v.x;
var numerator = wall.x - p.x;
return numerator / denominator;
}
};
VerletManager.prototype.intersectionPoint = function (wall, p, dir, v) {
var t = this.intersectionTime(wall, p, dir, v);
return new Phaser.Vector2(p.x + v.x * t, p.y + v.y * t);
};
VerletManager.prototype.bounds = function (particle) {
this._v.mutableSet(particle.pos);
this._v.mutableSub(particle.lastPos);
if(particle.pos.y > this.height - 1) {
particle.pos.mutableSet(this.intersectionPoint(new Phaser.Vector2(0, this.height - 1), particle.lastPos, new Phaser.Vector2(1, 0), this._v));
}
if(particle.pos.x < 0) {
particle.pos.mutableSet(this.intersectionPoint(new Phaser.Vector2(0, 0), particle.pos, new Phaser.Vector2(0, 1), this._v));
}
if(particle.pos.x > this.width - 1) {
particle.pos.mutableSet(this.intersectionPoint(new Phaser.Vector2(this.width - 1, 0), particle.pos, new Phaser.Vector2(0, 1), this._v));
}
};
VerletManager.prototype.createPoint = function (pos) {
var composite = new Phaser.Verlet.Composite(this._game);
composite.particles.push(new Phaser.Verlet.Particle(pos));
this.composites.push(composite);
return composite;
};
VerletManager.prototype.createLineSegments = function (vertices, stiffness) {
var composite = new Phaser.Verlet.Composite(this._game);
var i;
for(i in vertices) {
composite.particles.push(new Phaser.Verlet.Particle(vertices[i]));
if(i > 0) {
composite.constraints.push(new Phaser.Verlet.DistanceConstraint(composite.particles[i], composite.particles[i - 1], stiffness));
}
}
this.composites.push(composite);
return composite;
};
VerletManager.prototype.createCloth = function (origin, width, height, segments, pinMod, stiffness) {
var composite = new Phaser.Verlet.Composite(this._game);
var xStride = width / segments;
var yStride = height / segments;
var x;
var y;
for(y = 0; y < segments; ++y) {
for(x = 0; x < segments; ++x) {
var px = origin.x + x * xStride - width / 2 + xStride / 2;
var py = origin.y + y * yStride - height / 2 + yStride / 2;
composite.particles.push(new Phaser.Verlet.Particle(new Phaser.Vector2(px, py)));
if(x > 0) {
composite.constraints.push(new Phaser.Verlet.DistanceConstraint(composite.particles[y * segments + x], composite.particles[y * segments + x - 1], stiffness));
}
if(y > 0) {
composite.constraints.push(new Phaser.Verlet.DistanceConstraint(composite.particles[y * segments + x], composite.particles[(y - 1) * segments + x], stiffness));
}
}
}
for(x = 0; x < segments; ++x) {
if(x % pinMod == 0) {
composite.pin(x);
}
}
this.composites.push(composite);
return composite;
};
VerletManager.prototype.createTire = function (origin, radius, segments, spokeStiffness, treadStiffness) {
var stride = (2 * Math.PI) / segments;
var i;
var composite = new Phaser.Verlet.Composite(this._game);
// particles
for(i = 0; i < segments; ++i) {
var theta = i * stride;
composite.particles.push(new Verlet.Particle(new Phaser.Vector2(origin.x + Math.cos(theta) * radius, origin.y + Math.sin(theta) * radius)));
}
var center = new Verlet.Particle(origin);
composite.particles.push(center);
// constraints
for(i = 0; i < segments; ++i) {
composite.constraints.push(new Verlet.DistanceConstraint(composite.particles[i], composite.particles[(i + 1) % segments], treadStiffness));
composite.constraints.push(new Verlet.DistanceConstraint(composite.particles[i], center, spokeStiffness));
composite.constraints.push(new Verlet.DistanceConstraint(composite.particles[i], composite.particles[(i + 5) % segments], treadStiffness));
}
this.composites.push(composite);
return composite;
};
VerletManager.prototype.update = function () {
if(this.composites.length == 0) {
return;
}
var i, j, c;
for(c in this.composites) {
for(i in this.composites[c].particles) {
var particles = this.composites[c].particles;
// calculate velocity
var velocity = particles[i].pos.sub(particles[i].lastPos).scale(this.friction);
// ground friction
if(particles[i].pos.y >= this.height - 1 && velocity.length2() > 0.000001) {
var m = velocity.length();
velocity.x /= m;
velocity.y /= m;
velocity.mutableScale(m * this.groundFriction);
}
// save last good state
particles[i].lastPos.mutableSet(particles[i].pos);
// gravity
particles[i].pos.mutableAdd(this.gravity);
// inertia
particles[i].pos.mutableAdd(velocity);
}
}
// handle dragging of entities
if(this.draggedEntity) {
this.draggedEntity.pos.mutableSet(this._game.input.position);
}
// relax
var stepCoef = 1 / this.step;
for(c in this.composites) {
var constraints = this.composites[c].constraints;
for(i = 0; i < this.step; ++i) {
for(j in constraints) {
constraints[j].relax(stepCoef);
}
}
}
// bounds checking
for(c in this.composites) {
var particles = this.composites[c].particles;
for(i in particles) {
this.bounds(particles[i]);
}
}
};
VerletManager.prototype.mouseDownHandler = function () {
var nearest = this.nearestEntity();
if(nearest) {
this.draggedEntity = nearest;
}
};
VerletManager.prototype.mouseUpHandler = function () {
this.draggedEntity = null;
};
VerletManager.prototype.nearestEntity = function () {
var c, i;
var d2Nearest = 0;
var entity = null;
var constraintsNearest = null;
// find nearest point
for(c in this.composites) {
var particles = this.composites[c].particles;
for(i in particles) {
var d2 = particles[i].pos.distance2(this._game.input.position);
if(d2 <= this.selectionRadius * this.selectionRadius && (entity == null || d2 < d2Nearest)) {
entity = particles[i];
constraintsNearest = this.composites[c].constraints;
d2Nearest = d2;
}
}
}
// search for pinned constraints for this entity
for(i in constraintsNearest) {
if(constraintsNearest[i] instanceof Verlet.PinConstraint && constraintsNearest[i].a == entity) {
entity = constraintsNearest[i];
}
}
return entity;
};
VerletManager.prototype.render = function () {
var i, c;
for(c in this.composites) {
// draw constraints
if(this.composites[c].drawConstraints) {
this.composites[c].drawConstraints(this.context, this.composites[c]);
} else {
var constraints = this.composites[c].constraints;
for(i in constraints) {
constraints[i].render(this.context);
}
}
// draw particles
if(this.composites[c].drawParticles) {
this.composites[c].drawParticles(this.context, this.composites[c]);
} else {
var particles = this.composites[c].particles;
for(i in particles) {
particles[i].render(this.context);
}
}
}
// highlight nearest / dragged entity
var nearest = this.draggedEntity || this.nearestEntity();
if(nearest && this.hideNearestEntityCircle == false) {
this.context.beginPath();
this.context.arc(nearest.pos.x, nearest.pos.y, 8, 0, 2 * Math.PI);
this.context.strokeStyle = this.highlightColor;
this.context.stroke();
this.context.closePath();
}
};
return VerletManager;
})();
Verlet.VerletManager = VerletManager;
})(Phaser.Verlet || (Phaser.Verlet = {}));
var Verlet = Phaser.Verlet;
})(Phaser || (Phaser = {}));
+411
View File
@@ -0,0 +1,411 @@
/// <reference path="Game.ts" />
/// <reference path="geom/Vector2.ts" />
/// <reference path="verlet/Composite.ts" />
/// <reference path="verlet/Particle.ts" />
/// <reference path="verlet/DistanceConstraint.ts" />
/// <reference path="verlet/PinConstraint.ts" />
/// <reference path="verlet/AngleConstraint.ts" />
/**
* Phaser - Verlet
*
* Based on verlet-js by Sub Protocol released under MIT
*/
module Phaser.Verlet {
export class VerletManager {
/**
* Creates a new Vector2 object.
* @class Vector2
* @constructor
* @param {Number} x The x coordinate of vector2
* @param {Number} y The y coordinate of vector2
* @return {Vector2} This object
**/
constructor(game: Game, width: number, height: number) {
this._game = game;
this.width = width;
this.height = height;
this.gravity = new Vector2(0, 0.2);
this.friction = 0.99;
this.groundFriction = 0.8;
this.canvas = game.stage.canvas;
this.context = game.stage.context;
this._game.input.onDown.add(this.mouseDownHandler, this);
this._game.input.onUp.add(this.mouseUpHandler, this);
}
private _game: Game;
private _v = new Phaser.Vector2;
public composites = [];
public width: number;
public height: number;
public step: number = 16;
public gravity: Vector2;
public friction: number;
public groundFriction: number;
public selectionRadius: number = 20;
public draggedEntity = null;
public highlightColor = '#4f545c';
/**
* A reference to the canvas this renders to
* @type {HTMLCanvasElement}
*/
public canvas: HTMLCanvasElement;
/**
* A reference to the context this renders to
* @type {CanvasRenderingContext2D}
*/
public context: CanvasRenderingContext2D;
/**
* Computes time of intersection of a particle with a wall
*
* @param {Vec2} line walls root position
* @param {Vec2} p particle position
* @param {Vec2} dir walls direction
* @param {Vec2} v particles velocity
*/
public intersectionTime(wall, p, dir, v) {
if (dir.x != 0)
{
var denominator = v.y - dir.y * v.x / dir.x;
if (denominator == 0) return undefined; // Movement is parallel to wall
var numerator = wall.y + dir.y * (p.x - wall.x) / dir.x - p.y;
return numerator / denominator;
}
else
{
if (v.x == 0) return undefined; // parallel again
var denominator = v.x;
var numerator = wall.x - p.x;
return numerator / denominator;
}
}
public intersectionPoint(wall, p, dir, v) {
var t = this.intersectionTime(wall, p, dir, v);
return new Phaser.Vector2(p.x + v.x * t, p.y + v.y * t);
}
public bounds(particle: Phaser.Verlet.Particle) {
this._v.mutableSet(particle.pos);
this._v.mutableSub(particle.lastPos);
if (particle.pos.y > this.height - 1)
{
particle.pos.mutableSet(this.intersectionPoint(new Phaser.Vector2(0, this.height - 1), particle.lastPos, new Phaser.Vector2(1, 0), this._v));
}
if (particle.pos.x < 0)
{
particle.pos.mutableSet(this.intersectionPoint(new Phaser.Vector2(0, 0), particle.pos, new Phaser.Vector2(0, 1), this._v));
}
if (particle.pos.x > this.width - 1)
{
particle.pos.mutableSet(this.intersectionPoint(new Phaser.Vector2(this.width - 1, 0), particle.pos, new Phaser.Vector2(0, 1), this._v));
}
}
public createPoint(pos: Vector2) {
var composite = new Phaser.Verlet.Composite(this._game);
composite.particles.push(new Phaser.Verlet.Particle(pos));
this.composites.push(composite);
return composite;
}
public createLineSegments(vertices, stiffness) {
var composite = new Phaser.Verlet.Composite(this._game);
var i;
for (i in vertices)
{
composite.particles.push(new Phaser.Verlet.Particle(vertices[i]));
if (i > 0)
{
composite.constraints.push(new Phaser.Verlet.DistanceConstraint(composite.particles[i], composite.particles[i - 1], stiffness));
}
}
this.composites.push(composite);
return composite;
}
public createCloth(origin, width, height, segments, pinMod, stiffness) {
var composite = new Phaser.Verlet.Composite(this._game);
var xStride = width / segments;
var yStride = height / segments;
var x;
var y;
for (y = 0; y < segments; ++y)
{
for (x = 0; x < segments; ++x)
{
var px = origin.x + x * xStride - width / 2 + xStride / 2;
var py = origin.y + y * yStride - height / 2 + yStride / 2;
composite.particles.push(new Phaser.Verlet.Particle(new Vector2(px, py)));
if (x > 0)
{
composite.constraints.push(new Phaser.Verlet.DistanceConstraint(composite.particles[y * segments + x], composite.particles[y * segments + x - 1], stiffness));
}
if (y > 0)
{
composite.constraints.push(new Phaser.Verlet.DistanceConstraint(composite.particles[y * segments + x], composite.particles[(y - 1) * segments + x], stiffness));
}
}
}
for (x = 0; x < segments; ++x)
{
if (x % pinMod == 0)
{
composite.pin(x);
}
}
this.composites.push(composite);
return composite;
}
public createTire(origin, radius, segments, spokeStiffness, treadStiffness) {
var stride = (2 * Math.PI) / segments;
var i;
var composite = new Phaser.Verlet.Composite(this._game);
// particles
for (i = 0; i < segments; ++i)
{
var theta = i * stride;
composite.particles.push(new Particle(new Vector2(origin.x + Math.cos(theta) * radius, origin.y + Math.sin(theta) * radius)));
}
var center = new Particle(origin);
composite.particles.push(center);
// constraints
for (i = 0; i < segments; ++i)
{
composite.constraints.push(new DistanceConstraint(composite.particles[i], composite.particles[(i + 1) % segments], treadStiffness));
composite.constraints.push(new DistanceConstraint(composite.particles[i], center, spokeStiffness))
composite.constraints.push(new DistanceConstraint(composite.particles[i], composite.particles[(i + 5) % segments], treadStiffness));
}
this.composites.push(composite);
return composite;
}
public update() {
if (this.composites.length == 0)
{
return;
}
var i, j, c;
for (c in this.composites)
{
for (i in this.composites[c].particles)
{
var particles = this.composites[c].particles;
// calculate velocity
var velocity = particles[i].pos.sub(particles[i].lastPos).scale(this.friction);
// ground friction
if (particles[i].pos.y >= this.height - 1 && velocity.length2() > 0.000001)
{
var m = velocity.length();
velocity.x /= m;
velocity.y /= m;
velocity.mutableScale(m * this.groundFriction);
}
// save last good state
particles[i].lastPos.mutableSet(particles[i].pos);
// gravity
particles[i].pos.mutableAdd(this.gravity);
// inertia
particles[i].pos.mutableAdd(velocity);
}
}
// handle dragging of entities
if (this.draggedEntity)
{
this.draggedEntity.pos.mutableSet(this._game.input.position);
}
// relax
var stepCoef = 1 / this.step;
for (c in this.composites)
{
var constraints = this.composites[c].constraints;
for (i = 0; i < this.step; ++i)
{
for (j in constraints)
{
constraints[j].relax(stepCoef);
}
}
}
// bounds checking
for (c in this.composites)
{
var particles = this.composites[c].particles;
for (i in particles)
{
this.bounds(particles[i]);
}
}
}
private mouseDownHandler() {
var nearest = this.nearestEntity();
if (nearest)
{
this.draggedEntity = nearest;
}
}
private mouseUpHandler() {
this.draggedEntity = null;
}
public nearestEntity() {
var c, i;
var d2Nearest = 0;
var entity = null;
var constraintsNearest = null;
// find nearest point
for (c in this.composites)
{
var particles = this.composites[c].particles;
for (i in particles)
{
var d2 = particles[i].pos.distance2(this._game.input.position);
if (d2 <= this.selectionRadius * this.selectionRadius && (entity == null || d2 < d2Nearest))
{
entity = particles[i];
constraintsNearest = this.composites[c].constraints;
d2Nearest = d2;
}
}
}
// search for pinned constraints for this entity
for (i in constraintsNearest)
{
if (constraintsNearest[i] instanceof PinConstraint && constraintsNearest[i].a == entity)
{
entity = constraintsNearest[i];
}
}
return entity;
}
public hideNearestEntityCircle: bool = false;
public render() {
var i, c;
for (c in this.composites)
{
// draw constraints
if (this.composites[c].drawConstraints)
{
this.composites[c].drawConstraints(this.context, this.composites[c]);
}
else
{
var constraints = this.composites[c].constraints;
for (i in constraints)
{
constraints[i].render(this.context);
}
}
// draw particles
if (this.composites[c].drawParticles)
{
this.composites[c].drawParticles(this.context, this.composites[c]);
}
else
{
var particles = this.composites[c].particles;
for (i in particles)
{
particles[i].render(this.context);
}
}
}
// highlight nearest / dragged entity
var nearest = this.draggedEntity || this.nearestEntity();
if (nearest && this.hideNearestEntityCircle == false)
{
this.context.beginPath();
this.context.arc(nearest.pos.x, nearest.pos.y, 8, 0, 2 * Math.PI);
this.context.strokeStyle = this.highlightColor;
this.context.stroke();
this.context.closePath();
}
}
}
}