This commit is contained in:
Richard Davey 2022-02-03 21:50:54 +00:00
commit 3546140b51
72 changed files with 93052 additions and 90179 deletions

View file

@ -70,6 +70,9 @@ Development of this feature was kindly sponsored by Club Penguin Rewritten (http
* `Math.LinearXY` is a new function that will interpolate between 2 given Vector2s and return a new Vector2 as a result (thanks @GregDevProjects)
* `Curves.Path.getCurveAt` is a new method that will return the curve that forms the path at the given location (thanks @natureofcode)
* You can now use any `Shape` Game Object as a Geometry Mask. Fix #5900 (thanks @rexrainbow)
* `Mesh.setTint` is a new method that will set the tint color across all vertices of a Mesh (thanks @rexrainbow)
* `Mesh.tint` is a new setter that will set the tint color across all vertices of a Mesh (thanks @rexrainbow)
* `Mesh.clearTint` is a new method that will clear the tint from all vertices of a Mesh (thanks @rexrainbow)
### Geom Updates
@ -117,6 +120,9 @@ The following are API-breaking, in that a new optional parameter has been insert
* `TileMap.createStaticLayer` has now been removed as it was deprecated in 3.50.
* `Animations.AnimationManager.createFromAseprite` has a new optional 3rd parameter `target`. This allows you to create the animations directly on a Sprite, instead of in the global Animation Manager (thanks Telemako)
* `Animations.AnimationState.createFromAseprite` is a new method that allows you to create animations from exported Aseprite data directly on a Sprite, rather than always in the global Animation Manager (thanks Telemako)
* The `path` package used by the TS Defs generator has been moved to `devDependencies` (thanks @antkhnvsk)
* The `GetValue` function has a new optional parameter `altSource` which allows you to provide an alternative object to source the value from.
* The `Renderer.Snapshot.WebGL` function has had its first parameter changed from an `HTMLCanvasElement` to a `WebGLRenderingContext`. This is now passed in from the `snapshot` methods inside the WebGL Renderer. The change was made to allow it to work with WebGL2 custom contexts (thanks @andymikulski)
### Bug Fixes
@ -165,9 +171,24 @@ The following are API-breaking, in that a new optional parameter has been insert
* `InputPlugin.disable` will now also reset the drag state of the Game Object as well as remove it from all of the internal temporary arrays. This fixes issues where if you disabled a Game Object for input during an input event it would still remain in the temporary internal arrays. This method now also returns the Input Plugin, to match `enable`. Fix #5828 (thank @natureofcode @thewaver)
* The `GetBounds` component has been removed from the Point Light Game Object. Fix #5934 (thanks @x-wk @samme)
* `SceneManager.moveAbove` and `moveBelow` now take into account the modified indexes after the move (thanks @EmilSV)
* When forcing a game to use `setTimeout` and then sending the game to sleep, it would accidentally restart by using Request Animation Frame instead (thanks @andymikulski)
* Including a `render` object within the Game Config will no longer erase any top-level config render settings. The `render` object will now take priority over the game config, but both will be used (thanks @vzhou842)
* Calling `Tween.stop(0)` would run for an additional delta before stopping, causing the Tween to not be truly 100% "reset". Fix #5986 (thanks @Mesonyx)
* The `Utils.Array.SafeRange` function would exclude valid certain ranges. Fix #5979 (thanks @ksritharan)
* The "Skip intersects check by argument" change in Arcade Physics has been reverted. Fix #5956 (thanks @samme)
* The `Container.pointToContainer` method would ignore the provided `output` parameter, but now uses it (thanks @vforsh)
* The `Polygon` Game Object would ignore its `closePath` property when rendering in Canvas. Fix #5983 (thanks @optimumsuave)
* IE9 Fix: Added 2 missing Typed Array polyfills (thanks @jcyuan)
* IE9 Fix: CanvasRenderer ignores frames with zero dimensions (thanks @jcyuan)
* `RenderTexture.batchTextureFrame` will now skip the `drawImage` call in canvas if the frame width or height are zero. Fix #5951 (thanks @Hoshinokoe)
* `BlitterCanvasRenderer` will now skip the `drawImage` call in canvas if the frame width or height are zero.
* `ParticleManagerCanvasRenderer` will now skip the `drawImage` call in canvas if the frame width or height are zero.
* `CanvasSnapshot` will now skip the `drawImage` call in canvas if the frame width or height are zero.
* `TextureManager.getBase64` will now skip the `drawImage` call in canvas if the frame width or height are zero.
* `TilemapLayerCanvasRenderer` will now skip the `drawImage` call in canvas if the frame width or height are zero.
### Examples, Documentation and TypeScript
My thanks to the following for helping with the Phaser 3 Examples, Docs, and TypeScript definitions, either by reporting errors, fixing them, or helping author the docs:
@necrokot Golen @Pythux @samme @danfoster @eltociear @sylvainpolletvillard @hanzooo @etherealmachine @DeweyHur @twoco @austinlyon @Arcanorum OmniOwl @EsteFilipe
@necrokot Golen @Pythux @samme @danfoster @eltociear @sylvainpolletvillard @hanzooo @etherealmachine @DeweyHur @twoco @austinlyon @Arcanorum OmniOwl @EsteFilipe @PhaserEditor2D @Fake

651
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -64,27 +64,28 @@
"web audio"
],
"devDependencies": {
"@types/offscreencanvas": "^2019.6.4",
"@types/source-map": "^0.5.7",
"clean-webpack-plugin": "^4.0.0",
"dts-dom": "^3.6.0",
"eslint": "^8.4.1",
"eslint": "^8.8.0",
"eslint-plugin-es5": "^1.5.0",
"exports-loader": "^3.1.0",
"fs-extra": "^10.0.0",
"imports-loader": "^3.1.1",
"jsdoc": "^3.6.7",
"jsdoc": "^3.6.10",
"node-sloc": "^0.2.1",
"path": "^0.12.7",
"remove-files-webpack-plugin": "^1.5.0",
"source-map": "^0.7.3",
"terser-webpack-plugin": "^5.2.5",
"typescript": "^4.5.4",
"terser-webpack-plugin": "^5.3.1",
"typescript": "^4.5.5",
"vivid-cli": "^1.1.2",
"webpack": "^5.65.0",
"webpack-cli": "^4.9.1",
"webpack": "^5.68.0",
"webpack-cli": "^4.9.2",
"webpack-shell-plugin": "^0.5.0"
},
"dependencies": {
"eventemitter3": "^4.0.7",
"path": "^0.12.7"
"eventemitter3": "^4.0.7"
}
}

View file

@ -2,10 +2,11 @@
1. Checkout the Esoteric Spine Runtimes repo to the `spine-runtimes` folder: https://github.com/EsotericSoftware/spine-runtimes/ and make sure this is in the `plugins/spine` folder, not the `plugins/spine/src` folder.
2. Run `npm i` inside the `spine-runtimes` folder.
3. Add the `source-map` module: `npm i --save-dev source-map`.
4. Run `npm run plugin.spine.runtimes` to build the new runtimes to the `plugins/spine/src/runtimes` folder.
3. Add the `offscreencanvas` module: `npm i --save-dev @types/offscreencanvas`.
4. Add the `source-map` module: `npm i --save-dev source-map`.
5. Run `npm run plugin.spine.runtimes` to build the new runtimes to the `plugins/spine/src/runtimes` folder.
You can now build a new version of the Spine Plugin:
5. `npm run plugin.spine.dist`.
6. `npm run plugin.spine.dist`.

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

View file

@ -1,3 +1,4 @@
/// <reference types="offscreencanvas" />
declare module spine {
class Animation {
name: string;
@ -1402,7 +1403,7 @@ declare module spine.webgl {
static DISABLE_UNPACK_PREMULTIPLIED_ALPHA_WEBGL: boolean;
constructor(context: ManagedWebGLRenderingContext | WebGLRenderingContext, image: HTMLImageElement | ImageBitmap, useMipMaps?: boolean);
setFilters(minFilter: TextureFilter, magFilter: TextureFilter): void;
static validateMagFilter(magFilter: TextureFilter): TextureFilter.Nearest | TextureFilter.Linear | TextureFilter.Linear;
static validateMagFilter(magFilter: TextureFilter): TextureFilter.Nearest | TextureFilter.Linear;
setWraps(uWrap: TextureWrap, vWrap: TextureWrap): void;
update(useMipMaps: boolean): void;
restore(): void;

View file

@ -6,6 +6,8 @@ var __extends = (this && this.__extends) || (function () {
return extendStatics(d, b);
};
return function (d, b) {
if (typeof b !== "function" && b !== null)
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
@ -2239,9 +2241,9 @@ var spine;
_this.toLoad--;
_this.loaded++;
}, function (state, responseText) {
_this.errors[path] = "Couldn't load binary " + path + ": status " + status + ", " + responseText;
_this.errors[path] = "Couldn't load binary ".concat(path, ": status ").concat(status, ", ").concat(responseText);
if (error)
error(path, "Couldn't load binary " + path + ": status " + status + ", " + responseText);
error(path, "Couldn't load binary ".concat(path, ": status ").concat(status, ", ").concat(responseText));
_this.toLoad--;
_this.loaded++;
});
@ -2259,9 +2261,9 @@ var spine;
_this.toLoad--;
_this.loaded++;
}, function (state, responseText) {
_this.errors[path] = "Couldn't load text " + path + ": status " + status + ", " + responseText;
_this.errors[path] = "Couldn't load text ".concat(path, ": status ").concat(status, ", ").concat(responseText);
if (error)
error(path, "Couldn't load text " + path + ": status " + status + ", " + responseText);
error(path, "Couldn't load text ".concat(path, ": status ").concat(status, ", ").concat(responseText));
_this.toLoad--;
_this.loaded++;
});
@ -2284,11 +2286,11 @@ var spine;
success(path, img);
};
img.onerror = function (ev) {
_this.errors[path] = "Couldn't load image " + path;
_this.errors[path] = "Couldn't load image ".concat(path);
_this.toLoad--;
_this.loaded++;
if (error)
error(path, "Couldn't load image " + path);
error(path, "Couldn't load image ".concat(path));
};
if (this.rawDataUris[path])
path = this.rawDataUris[path];
@ -2315,9 +2317,9 @@ var spine;
}
catch (e) {
var ex = e;
_this.errors[path] = "Couldn't load texture atlas " + path + ": " + ex.message;
_this.errors[path] = "Couldn't load texture atlas ".concat(path, ": ").concat(ex.message);
if (error)
error(path, "Couldn't load texture atlas " + path + ": " + ex.message);
error(path, "Couldn't load texture atlas ".concat(path, ": ").concat(ex.message));
_this.toLoad--;
_this.loaded++;
return;
@ -2340,17 +2342,17 @@ var spine;
}
catch (e) {
var ex = e;
_this.errors[path] = "Couldn't load texture atlas " + path + ": " + ex.message;
_this.errors[path] = "Couldn't load texture atlas ".concat(path, ": ").concat(ex.message);
if (error)
error(path, "Couldn't load texture atlas " + path + ": " + ex.message);
error(path, "Couldn't load texture atlas ".concat(path, ": ").concat(ex.message));
_this.toLoad--;
_this.loaded++;
}
}
else {
_this.errors[path] = "Couldn't load texture atlas page " + imagePath + "} of atlas " + path;
_this.errors[path] = "Couldn't load texture atlas page ".concat(imagePath, "} of atlas ").concat(path);
if (error)
error(path, "Couldn't load texture atlas page " + imagePath + " of atlas " + path);
error(path, "Couldn't load texture atlas page ".concat(imagePath, " of atlas ").concat(path));
_this.toLoad--;
_this.loaded++;
}
@ -2359,9 +2361,9 @@ var spine;
pageLoadError = true;
pagesLoaded.count++;
if (pagesLoaded.count == atlasPages.length) {
_this.errors[path] = "Couldn't load texture atlas page " + imagePath + "} of atlas " + path;
_this.errors[path] = "Couldn't load texture atlas page ".concat(imagePath, "} of atlas ").concat(path);
if (error)
error(path, "Couldn't load texture atlas page " + imagePath + " of atlas " + path);
error(path, "Couldn't load texture atlas page ".concat(imagePath, " of atlas ").concat(path));
_this.toLoad--;
_this.loaded++;
}
@ -2372,9 +2374,9 @@ var spine;
_loop_1(atlasPage);
}
}, function (state, responseText) {
_this.errors[path] = "Couldn't load texture atlas " + path + ": status " + status + ", " + responseText;
_this.errors[path] = "Couldn't load texture atlas ".concat(path, ": status ").concat(status, ", ").concat(responseText);
if (error)
error(path, "Couldn't load texture atlas " + path + ": status " + status + ", " + responseText);
error(path, "Couldn't load texture atlas ".concat(path, ": status ").concat(status, ", ").concat(responseText));
_this.toLoad--;
_this.loaded++;
});
@ -3540,7 +3542,7 @@ var spine;
_this.rawAssets[path] = request.responseText;
}
else {
_this.errors[path] = "Couldn't load text " + path + ": status " + request.status + ", " + request.responseText;
_this.errors[path] = "Couldn't load text ".concat(path, ": status ").concat(request.status, ", ").concat(request.responseText);
}
}
};
@ -3560,7 +3562,7 @@ var spine;
_this.rawAssets[path] = JSON.parse(request.responseText);
}
else {
_this.errors[path] = "Couldn't load text " + path + ": status " + request.status + ", " + request.responseText;
_this.errors[path] = "Couldn't load text ".concat(path, ": status ").concat(request.status, ", ").concat(request.responseText);
}
}
};
@ -3597,7 +3599,7 @@ var spine;
_this.rawAssets[path] = img_1;
};
img_1.onerror = function (ev) {
_this.errors[path] = "Couldn't load image " + path;
_this.errors[path] = "Couldn't load image ".concat(path);
};
img_1.src = path;
}
@ -6251,7 +6253,7 @@ var spine;
return spine.BlendMode.Multiply;
if (str == "screen")
return spine.BlendMode.Screen;
throw new Error("Unknown blend mode: " + str);
throw new Error("Unknown blend mode: ".concat(str));
};
SkeletonJson.positionModeFromString = function (str) {
str = str.toLowerCase();
@ -6259,7 +6261,7 @@ var spine;
return spine.PositionMode.Fixed;
if (str == "percent")
return spine.PositionMode.Percent;
throw new Error("Unknown position mode: " + str);
throw new Error("Unknown position mode: ".concat(str));
};
SkeletonJson.spacingModeFromString = function (str) {
str = str.toLowerCase();
@ -6269,7 +6271,7 @@ var spine;
return spine.SpacingMode.Fixed;
if (str == "percent")
return spine.SpacingMode.Percent;
throw new Error("Unknown position mode: " + str);
throw new Error("Unknown position mode: ".concat(str));
};
SkeletonJson.rotateModeFromString = function (str) {
str = str.toLowerCase();
@ -6279,7 +6281,7 @@ var spine;
return spine.RotateMode.Chain;
if (str == "chainscale")
return spine.RotateMode.ChainScale;
throw new Error("Unknown rotate mode: " + str);
throw new Error("Unknown rotate mode: ".concat(str));
};
SkeletonJson.transformModeFromString = function (str) {
str = str.toLowerCase();
@ -6293,7 +6295,7 @@ var spine;
return spine.TransformMode.NoScale;
if (str == "noscaleorreflection")
return spine.TransformMode.NoScaleOrReflection;
throw new Error("Unknown transform mode: " + str);
throw new Error("Unknown transform mode: ".concat(str));
};
return SkeletonJson;
}());
@ -6558,7 +6560,7 @@ var spine;
case "mipmaplinearnearest": return TextureFilter.MipMapLinearNearest;
case "mipmapnearestlinear": return TextureFilter.MipMapNearestLinear;
case "mipmaplinearlinear": return TextureFilter.MipMapLinearLinear;
default: throw new Error("Unknown texture filter " + text);
default: throw new Error("Unknown texture filter ".concat(text));
}
};
Texture.wrapFromString = function (text) {
@ -6566,7 +6568,7 @@ var spine;
case "mirroredtepeat": return TextureWrap.MirroredRepeat;
case "clamptoedge": return TextureWrap.ClampToEdge;
case "repeat": return TextureWrap.Repeat;
default: throw new Error("Unknown texture wrap " + text);
default: throw new Error("Unknown texture wrap ".concat(text));
}
};
return Texture;
@ -9796,14 +9798,14 @@ var spine;
var gl = this.context.gl;
var location = gl.getUniformLocation(this.program, uniform);
if (!location && !gl.isContextLost())
throw new Error("Couldn't find location for uniform " + uniform);
throw new Error("Couldn't find location for uniform ".concat(uniform));
return location;
};
Shader.prototype.getAttributeLocation = function (attribute) {
var gl = this.context.gl;
var location = gl.getAttribLocation(this.program, attribute);
if (location == -1 && !gl.isContextLost())
throw new Error("Couldn't find location for attribute " + attribute);
throw new Error("Couldn't find location for attribute ".concat(attribute));
return location;
};
Shader.prototype.dispose = function () {
@ -9823,17 +9825,17 @@ var spine;
}
};
Shader.newColoredTextured = function (context) {
var vs = "\n\t\t\t\tattribute vec4 " + Shader.POSITION + ";\n\t\t\t\tattribute vec4 " + Shader.COLOR + ";\n\t\t\t\tattribute vec2 " + Shader.TEXCOORDS + ";\n\t\t\t\tuniform mat4 " + Shader.MVP_MATRIX + ";\n\t\t\t\tvarying vec4 v_color;\n\t\t\t\tvarying vec2 v_texCoords;\n\n\t\t\t\tvoid main () {\n\t\t\t\t\tv_color = " + Shader.COLOR + ";\n\t\t\t\t\tv_texCoords = " + Shader.TEXCOORDS + ";\n\t\t\t\t\tgl_Position = " + Shader.MVP_MATRIX + " * " + Shader.POSITION + ";\n\t\t\t\t}\n\t\t\t";
var vs = "\n\t\t\t\tattribute vec4 ".concat(Shader.POSITION, ";\n\t\t\t\tattribute vec4 ").concat(Shader.COLOR, ";\n\t\t\t\tattribute vec2 ").concat(Shader.TEXCOORDS, ";\n\t\t\t\tuniform mat4 ").concat(Shader.MVP_MATRIX, ";\n\t\t\t\tvarying vec4 v_color;\n\t\t\t\tvarying vec2 v_texCoords;\n\n\t\t\t\tvoid main () {\n\t\t\t\t\tv_color = ").concat(Shader.COLOR, ";\n\t\t\t\t\tv_texCoords = ").concat(Shader.TEXCOORDS, ";\n\t\t\t\t\tgl_Position = ").concat(Shader.MVP_MATRIX, " * ").concat(Shader.POSITION, ";\n\t\t\t\t}\n\t\t\t");
var fs = "\n\t\t\t\t#ifdef GL_ES\n\t\t\t\t\t#define LOWP lowp\n\t\t\t\t\tprecision mediump float;\n\t\t\t\t#else\n\t\t\t\t\t#define LOWP\n\t\t\t\t#endif\n\t\t\t\tvarying LOWP vec4 v_color;\n\t\t\t\tvarying vec2 v_texCoords;\n\t\t\t\tuniform sampler2D u_texture;\n\n\t\t\t\tvoid main () {\n\t\t\t\t\tgl_FragColor = v_color * texture2D(u_texture, v_texCoords);\n\t\t\t\t}\n\t\t\t";
return new Shader(context, vs, fs);
};
Shader.newTwoColoredTextured = function (context) {
var vs = "\n\t\t\t\tattribute vec4 " + Shader.POSITION + ";\n\t\t\t\tattribute vec4 " + Shader.COLOR + ";\n\t\t\t\tattribute vec4 " + Shader.COLOR2 + ";\n\t\t\t\tattribute vec2 " + Shader.TEXCOORDS + ";\n\t\t\t\tuniform mat4 " + Shader.MVP_MATRIX + ";\n\t\t\t\tvarying vec4 v_light;\n\t\t\t\tvarying vec4 v_dark;\n\t\t\t\tvarying vec2 v_texCoords;\n\n\t\t\t\tvoid main () {\n\t\t\t\t\tv_light = " + Shader.COLOR + ";\n\t\t\t\t\tv_dark = " + Shader.COLOR2 + ";\n\t\t\t\t\tv_texCoords = " + Shader.TEXCOORDS + ";\n\t\t\t\t\tgl_Position = " + Shader.MVP_MATRIX + " * " + Shader.POSITION + ";\n\t\t\t\t}\n\t\t\t";
var vs = "\n\t\t\t\tattribute vec4 ".concat(Shader.POSITION, ";\n\t\t\t\tattribute vec4 ").concat(Shader.COLOR, ";\n\t\t\t\tattribute vec4 ").concat(Shader.COLOR2, ";\n\t\t\t\tattribute vec2 ").concat(Shader.TEXCOORDS, ";\n\t\t\t\tuniform mat4 ").concat(Shader.MVP_MATRIX, ";\n\t\t\t\tvarying vec4 v_light;\n\t\t\t\tvarying vec4 v_dark;\n\t\t\t\tvarying vec2 v_texCoords;\n\n\t\t\t\tvoid main () {\n\t\t\t\t\tv_light = ").concat(Shader.COLOR, ";\n\t\t\t\t\tv_dark = ").concat(Shader.COLOR2, ";\n\t\t\t\t\tv_texCoords = ").concat(Shader.TEXCOORDS, ";\n\t\t\t\t\tgl_Position = ").concat(Shader.MVP_MATRIX, " * ").concat(Shader.POSITION, ";\n\t\t\t\t}\n\t\t\t");
var fs = "\n\t\t\t\t#ifdef GL_ES\n\t\t\t\t\t#define LOWP lowp\n\t\t\t\t\tprecision mediump float;\n\t\t\t\t#else\n\t\t\t\t\t#define LOWP\n\t\t\t\t#endif\n\t\t\t\tvarying LOWP vec4 v_light;\n\t\t\t\tvarying LOWP vec4 v_dark;\n\t\t\t\tvarying vec2 v_texCoords;\n\t\t\t\tuniform sampler2D u_texture;\n\n\t\t\t\tvoid main () {\n\t\t\t\t\tvec4 texColor = texture2D(u_texture, v_texCoords);\n\t\t\t\t\tgl_FragColor.a = texColor.a * v_light.a;\n\t\t\t\t\tgl_FragColor.rgb = ((texColor.a - 1.0) * v_dark.a + 1.0 - texColor.rgb) * v_dark.rgb + texColor.rgb * v_light.rgb;\n\t\t\t\t}\n\t\t\t";
return new Shader(context, vs, fs);
};
Shader.newColored = function (context) {
var vs = "\n\t\t\t\tattribute vec4 " + Shader.POSITION + ";\n\t\t\t\tattribute vec4 " + Shader.COLOR + ";\n\t\t\t\tuniform mat4 " + Shader.MVP_MATRIX + ";\n\t\t\t\tvarying vec4 v_color;\n\n\t\t\t\tvoid main () {\n\t\t\t\t\tv_color = " + Shader.COLOR + ";\n\t\t\t\t\tgl_Position = " + Shader.MVP_MATRIX + " * " + Shader.POSITION + ";\n\t\t\t\t}\n\t\t\t";
var vs = "\n\t\t\t\tattribute vec4 ".concat(Shader.POSITION, ";\n\t\t\t\tattribute vec4 ").concat(Shader.COLOR, ";\n\t\t\t\tuniform mat4 ").concat(Shader.MVP_MATRIX, ";\n\t\t\t\tvarying vec4 v_color;\n\n\t\t\t\tvoid main () {\n\t\t\t\t\tv_color = ").concat(Shader.COLOR, ";\n\t\t\t\t\tgl_Position = ").concat(Shader.MVP_MATRIX, " * ").concat(Shader.POSITION, ";\n\t\t\t\t}\n\t\t\t");
var fs = "\n\t\t\t\t#ifdef GL_ES\n\t\t\t\t\t#define LOWP lowp\n\t\t\t\t\tprecision mediump float;\n\t\t\t\t#else\n\t\t\t\t\t#define LOWP\n\t\t\t\t#endif\n\t\t\t\tvarying LOWP vec4 v_color;\n\n\t\t\t\tvoid main () {\n\t\t\t\t\tgl_FragColor = v_color;\n\t\t\t\t}\n\t\t\t";
return new Shader(context, vs, fs);
};

File diff suppressed because one or more lines are too long

View file

@ -6,6 +6,8 @@ var __extends = (this && this.__extends) || (function () {
return extendStatics(d, b);
};
return function (d, b) {
if (typeof b !== "function" && b !== null)
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
@ -2239,9 +2241,9 @@ var spine;
_this.toLoad--;
_this.loaded++;
}, function (state, responseText) {
_this.errors[path] = "Couldn't load binary " + path + ": status " + status + ", " + responseText;
_this.errors[path] = "Couldn't load binary ".concat(path, ": status ").concat(status, ", ").concat(responseText);
if (error)
error(path, "Couldn't load binary " + path + ": status " + status + ", " + responseText);
error(path, "Couldn't load binary ".concat(path, ": status ").concat(status, ", ").concat(responseText));
_this.toLoad--;
_this.loaded++;
});
@ -2259,9 +2261,9 @@ var spine;
_this.toLoad--;
_this.loaded++;
}, function (state, responseText) {
_this.errors[path] = "Couldn't load text " + path + ": status " + status + ", " + responseText;
_this.errors[path] = "Couldn't load text ".concat(path, ": status ").concat(status, ", ").concat(responseText);
if (error)
error(path, "Couldn't load text " + path + ": status " + status + ", " + responseText);
error(path, "Couldn't load text ".concat(path, ": status ").concat(status, ", ").concat(responseText));
_this.toLoad--;
_this.loaded++;
});
@ -2284,11 +2286,11 @@ var spine;
success(path, img);
};
img.onerror = function (ev) {
_this.errors[path] = "Couldn't load image " + path;
_this.errors[path] = "Couldn't load image ".concat(path);
_this.toLoad--;
_this.loaded++;
if (error)
error(path, "Couldn't load image " + path);
error(path, "Couldn't load image ".concat(path));
};
if (this.rawDataUris[path])
path = this.rawDataUris[path];
@ -2315,9 +2317,9 @@ var spine;
}
catch (e) {
var ex = e;
_this.errors[path] = "Couldn't load texture atlas " + path + ": " + ex.message;
_this.errors[path] = "Couldn't load texture atlas ".concat(path, ": ").concat(ex.message);
if (error)
error(path, "Couldn't load texture atlas " + path + ": " + ex.message);
error(path, "Couldn't load texture atlas ".concat(path, ": ").concat(ex.message));
_this.toLoad--;
_this.loaded++;
return;
@ -2340,17 +2342,17 @@ var spine;
}
catch (e) {
var ex = e;
_this.errors[path] = "Couldn't load texture atlas " + path + ": " + ex.message;
_this.errors[path] = "Couldn't load texture atlas ".concat(path, ": ").concat(ex.message);
if (error)
error(path, "Couldn't load texture atlas " + path + ": " + ex.message);
error(path, "Couldn't load texture atlas ".concat(path, ": ").concat(ex.message));
_this.toLoad--;
_this.loaded++;
}
}
else {
_this.errors[path] = "Couldn't load texture atlas page " + imagePath + "} of atlas " + path;
_this.errors[path] = "Couldn't load texture atlas page ".concat(imagePath, "} of atlas ").concat(path);
if (error)
error(path, "Couldn't load texture atlas page " + imagePath + " of atlas " + path);
error(path, "Couldn't load texture atlas page ".concat(imagePath, " of atlas ").concat(path));
_this.toLoad--;
_this.loaded++;
}
@ -2359,9 +2361,9 @@ var spine;
pageLoadError = true;
pagesLoaded.count++;
if (pagesLoaded.count == atlasPages.length) {
_this.errors[path] = "Couldn't load texture atlas page " + imagePath + "} of atlas " + path;
_this.errors[path] = "Couldn't load texture atlas page ".concat(imagePath, "} of atlas ").concat(path);
if (error)
error(path, "Couldn't load texture atlas page " + imagePath + " of atlas " + path);
error(path, "Couldn't load texture atlas page ".concat(imagePath, " of atlas ").concat(path));
_this.toLoad--;
_this.loaded++;
}
@ -2372,9 +2374,9 @@ var spine;
_loop_1(atlasPage);
}
}, function (state, responseText) {
_this.errors[path] = "Couldn't load texture atlas " + path + ": status " + status + ", " + responseText;
_this.errors[path] = "Couldn't load texture atlas ".concat(path, ": status ").concat(status, ", ").concat(responseText);
if (error)
error(path, "Couldn't load texture atlas " + path + ": status " + status + ", " + responseText);
error(path, "Couldn't load texture atlas ".concat(path, ": status ").concat(status, ", ").concat(responseText));
_this.toLoad--;
_this.loaded++;
});
@ -3540,7 +3542,7 @@ var spine;
_this.rawAssets[path] = request.responseText;
}
else {
_this.errors[path] = "Couldn't load text " + path + ": status " + request.status + ", " + request.responseText;
_this.errors[path] = "Couldn't load text ".concat(path, ": status ").concat(request.status, ", ").concat(request.responseText);
}
}
};
@ -3560,7 +3562,7 @@ var spine;
_this.rawAssets[path] = JSON.parse(request.responseText);
}
else {
_this.errors[path] = "Couldn't load text " + path + ": status " + request.status + ", " + request.responseText;
_this.errors[path] = "Couldn't load text ".concat(path, ": status ").concat(request.status, ", ").concat(request.responseText);
}
}
};
@ -3597,7 +3599,7 @@ var spine;
_this.rawAssets[path] = img_1;
};
img_1.onerror = function (ev) {
_this.errors[path] = "Couldn't load image " + path;
_this.errors[path] = "Couldn't load image ".concat(path);
};
img_1.src = path;
}
@ -6251,7 +6253,7 @@ var spine;
return spine.BlendMode.Multiply;
if (str == "screen")
return spine.BlendMode.Screen;
throw new Error("Unknown blend mode: " + str);
throw new Error("Unknown blend mode: ".concat(str));
};
SkeletonJson.positionModeFromString = function (str) {
str = str.toLowerCase();
@ -6259,7 +6261,7 @@ var spine;
return spine.PositionMode.Fixed;
if (str == "percent")
return spine.PositionMode.Percent;
throw new Error("Unknown position mode: " + str);
throw new Error("Unknown position mode: ".concat(str));
};
SkeletonJson.spacingModeFromString = function (str) {
str = str.toLowerCase();
@ -6269,7 +6271,7 @@ var spine;
return spine.SpacingMode.Fixed;
if (str == "percent")
return spine.SpacingMode.Percent;
throw new Error("Unknown position mode: " + str);
throw new Error("Unknown position mode: ".concat(str));
};
SkeletonJson.rotateModeFromString = function (str) {
str = str.toLowerCase();
@ -6279,7 +6281,7 @@ var spine;
return spine.RotateMode.Chain;
if (str == "chainscale")
return spine.RotateMode.ChainScale;
throw new Error("Unknown rotate mode: " + str);
throw new Error("Unknown rotate mode: ".concat(str));
};
SkeletonJson.transformModeFromString = function (str) {
str = str.toLowerCase();
@ -6293,7 +6295,7 @@ var spine;
return spine.TransformMode.NoScale;
if (str == "noscaleorreflection")
return spine.TransformMode.NoScaleOrReflection;
throw new Error("Unknown transform mode: " + str);
throw new Error("Unknown transform mode: ".concat(str));
};
return SkeletonJson;
}());
@ -6558,7 +6560,7 @@ var spine;
case "mipmaplinearnearest": return TextureFilter.MipMapLinearNearest;
case "mipmapnearestlinear": return TextureFilter.MipMapNearestLinear;
case "mipmaplinearlinear": return TextureFilter.MipMapLinearLinear;
default: throw new Error("Unknown texture filter " + text);
default: throw new Error("Unknown texture filter ".concat(text));
}
};
Texture.wrapFromString = function (text) {
@ -6566,7 +6568,7 @@ var spine;
case "mirroredtepeat": return TextureWrap.MirroredRepeat;
case "clamptoedge": return TextureWrap.ClampToEdge;
case "repeat": return TextureWrap.Repeat;
default: throw new Error("Unknown texture wrap " + text);
default: throw new Error("Unknown texture wrap ".concat(text));
}
};
return Texture;

File diff suppressed because one or more lines are too long

View file

@ -1,3 +1,4 @@
/// <reference types="offscreencanvas" />
declare module spine {
class Animation {
name: string;
@ -1371,7 +1372,7 @@ declare module spine.webgl {
static DISABLE_UNPACK_PREMULTIPLIED_ALPHA_WEBGL: boolean;
constructor(context: ManagedWebGLRenderingContext | WebGLRenderingContext, image: HTMLImageElement | ImageBitmap, useMipMaps?: boolean);
setFilters(minFilter: TextureFilter, magFilter: TextureFilter): void;
static validateMagFilter(magFilter: TextureFilter): TextureFilter.Nearest | TextureFilter.Linear | TextureFilter.Linear;
static validateMagFilter(magFilter: TextureFilter): TextureFilter.Nearest | TextureFilter.Linear;
setWraps(uWrap: TextureWrap, vWrap: TextureWrap): void;
update(useMipMaps: boolean): void;
restore(): void;

View file

@ -6,6 +6,8 @@ var __extends = (this && this.__extends) || (function () {
return extendStatics(d, b);
};
return function (d, b) {
if (typeof b !== "function" && b !== null)
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
@ -2239,9 +2241,9 @@ var spine;
_this.toLoad--;
_this.loaded++;
}, function (state, responseText) {
_this.errors[path] = "Couldn't load binary " + path + ": status " + status + ", " + responseText;
_this.errors[path] = "Couldn't load binary ".concat(path, ": status ").concat(status, ", ").concat(responseText);
if (error)
error(path, "Couldn't load binary " + path + ": status " + status + ", " + responseText);
error(path, "Couldn't load binary ".concat(path, ": status ").concat(status, ", ").concat(responseText));
_this.toLoad--;
_this.loaded++;
});
@ -2259,9 +2261,9 @@ var spine;
_this.toLoad--;
_this.loaded++;
}, function (state, responseText) {
_this.errors[path] = "Couldn't load text " + path + ": status " + status + ", " + responseText;
_this.errors[path] = "Couldn't load text ".concat(path, ": status ").concat(status, ", ").concat(responseText);
if (error)
error(path, "Couldn't load text " + path + ": status " + status + ", " + responseText);
error(path, "Couldn't load text ".concat(path, ": status ").concat(status, ", ").concat(responseText));
_this.toLoad--;
_this.loaded++;
});
@ -2284,11 +2286,11 @@ var spine;
success(path, img);
};
img.onerror = function (ev) {
_this.errors[path] = "Couldn't load image " + path;
_this.errors[path] = "Couldn't load image ".concat(path);
_this.toLoad--;
_this.loaded++;
if (error)
error(path, "Couldn't load image " + path);
error(path, "Couldn't load image ".concat(path));
};
if (this.rawDataUris[path])
path = this.rawDataUris[path];
@ -2315,9 +2317,9 @@ var spine;
}
catch (e) {
var ex = e;
_this.errors[path] = "Couldn't load texture atlas " + path + ": " + ex.message;
_this.errors[path] = "Couldn't load texture atlas ".concat(path, ": ").concat(ex.message);
if (error)
error(path, "Couldn't load texture atlas " + path + ": " + ex.message);
error(path, "Couldn't load texture atlas ".concat(path, ": ").concat(ex.message));
_this.toLoad--;
_this.loaded++;
return;
@ -2340,17 +2342,17 @@ var spine;
}
catch (e) {
var ex = e;
_this.errors[path] = "Couldn't load texture atlas " + path + ": " + ex.message;
_this.errors[path] = "Couldn't load texture atlas ".concat(path, ": ").concat(ex.message);
if (error)
error(path, "Couldn't load texture atlas " + path + ": " + ex.message);
error(path, "Couldn't load texture atlas ".concat(path, ": ").concat(ex.message));
_this.toLoad--;
_this.loaded++;
}
}
else {
_this.errors[path] = "Couldn't load texture atlas page " + imagePath + "} of atlas " + path;
_this.errors[path] = "Couldn't load texture atlas page ".concat(imagePath, "} of atlas ").concat(path);
if (error)
error(path, "Couldn't load texture atlas page " + imagePath + " of atlas " + path);
error(path, "Couldn't load texture atlas page ".concat(imagePath, " of atlas ").concat(path));
_this.toLoad--;
_this.loaded++;
}
@ -2359,9 +2361,9 @@ var spine;
pageLoadError = true;
pagesLoaded.count++;
if (pagesLoaded.count == atlasPages.length) {
_this.errors[path] = "Couldn't load texture atlas page " + imagePath + "} of atlas " + path;
_this.errors[path] = "Couldn't load texture atlas page ".concat(imagePath, "} of atlas ").concat(path);
if (error)
error(path, "Couldn't load texture atlas page " + imagePath + " of atlas " + path);
error(path, "Couldn't load texture atlas page ".concat(imagePath, " of atlas ").concat(path));
_this.toLoad--;
_this.loaded++;
}
@ -2372,9 +2374,9 @@ var spine;
_loop_1(atlasPage);
}
}, function (state, responseText) {
_this.errors[path] = "Couldn't load texture atlas " + path + ": status " + status + ", " + responseText;
_this.errors[path] = "Couldn't load texture atlas ".concat(path, ": status ").concat(status, ", ").concat(responseText);
if (error)
error(path, "Couldn't load texture atlas " + path + ": status " + status + ", " + responseText);
error(path, "Couldn't load texture atlas ".concat(path, ": status ").concat(status, ", ").concat(responseText));
_this.toLoad--;
_this.loaded++;
});
@ -3540,7 +3542,7 @@ var spine;
_this.rawAssets[path] = request.responseText;
}
else {
_this.errors[path] = "Couldn't load text " + path + ": status " + request.status + ", " + request.responseText;
_this.errors[path] = "Couldn't load text ".concat(path, ": status ").concat(request.status, ", ").concat(request.responseText);
}
}
};
@ -3560,7 +3562,7 @@ var spine;
_this.rawAssets[path] = JSON.parse(request.responseText);
}
else {
_this.errors[path] = "Couldn't load text " + path + ": status " + request.status + ", " + request.responseText;
_this.errors[path] = "Couldn't load text ".concat(path, ": status ").concat(request.status, ", ").concat(request.responseText);
}
}
};
@ -3597,7 +3599,7 @@ var spine;
_this.rawAssets[path] = img_1;
};
img_1.onerror = function (ev) {
_this.errors[path] = "Couldn't load image " + path;
_this.errors[path] = "Couldn't load image ".concat(path);
};
img_1.src = path;
}
@ -6251,7 +6253,7 @@ var spine;
return spine.BlendMode.Multiply;
if (str == "screen")
return spine.BlendMode.Screen;
throw new Error("Unknown blend mode: " + str);
throw new Error("Unknown blend mode: ".concat(str));
};
SkeletonJson.positionModeFromString = function (str) {
str = str.toLowerCase();
@ -6259,7 +6261,7 @@ var spine;
return spine.PositionMode.Fixed;
if (str == "percent")
return spine.PositionMode.Percent;
throw new Error("Unknown position mode: " + str);
throw new Error("Unknown position mode: ".concat(str));
};
SkeletonJson.spacingModeFromString = function (str) {
str = str.toLowerCase();
@ -6269,7 +6271,7 @@ var spine;
return spine.SpacingMode.Fixed;
if (str == "percent")
return spine.SpacingMode.Percent;
throw new Error("Unknown position mode: " + str);
throw new Error("Unknown position mode: ".concat(str));
};
SkeletonJson.rotateModeFromString = function (str) {
str = str.toLowerCase();
@ -6279,7 +6281,7 @@ var spine;
return spine.RotateMode.Chain;
if (str == "chainscale")
return spine.RotateMode.ChainScale;
throw new Error("Unknown rotate mode: " + str);
throw new Error("Unknown rotate mode: ".concat(str));
};
SkeletonJson.transformModeFromString = function (str) {
str = str.toLowerCase();
@ -6293,7 +6295,7 @@ var spine;
return spine.TransformMode.NoScale;
if (str == "noscaleorreflection")
return spine.TransformMode.NoScaleOrReflection;
throw new Error("Unknown transform mode: " + str);
throw new Error("Unknown transform mode: ".concat(str));
};
return SkeletonJson;
}());
@ -6558,7 +6560,7 @@ var spine;
case "mipmaplinearnearest": return TextureFilter.MipMapLinearNearest;
case "mipmapnearestlinear": return TextureFilter.MipMapNearestLinear;
case "mipmaplinearlinear": return TextureFilter.MipMapLinearLinear;
default: throw new Error("Unknown texture filter " + text);
default: throw new Error("Unknown texture filter ".concat(text));
}
};
Texture.wrapFromString = function (text) {
@ -6566,7 +6568,7 @@ var spine;
case "mirroredtepeat": return TextureWrap.MirroredRepeat;
case "clamptoedge": return TextureWrap.ClampToEdge;
case "repeat": return TextureWrap.Repeat;
default: throw new Error("Unknown texture wrap " + text);
default: throw new Error("Unknown texture wrap ".concat(text));
}
};
return Texture;
@ -9528,14 +9530,14 @@ var spine;
var gl = this.context.gl;
var location = gl.getUniformLocation(this.program, uniform);
if (!location && !gl.isContextLost())
throw new Error("Couldn't find location for uniform " + uniform);
throw new Error("Couldn't find location for uniform ".concat(uniform));
return location;
};
Shader.prototype.getAttributeLocation = function (attribute) {
var gl = this.context.gl;
var location = gl.getAttribLocation(this.program, attribute);
if (location == -1 && !gl.isContextLost())
throw new Error("Couldn't find location for attribute " + attribute);
throw new Error("Couldn't find location for attribute ".concat(attribute));
return location;
};
Shader.prototype.dispose = function () {
@ -9555,17 +9557,17 @@ var spine;
}
};
Shader.newColoredTextured = function (context) {
var vs = "\n\t\t\t\tattribute vec4 " + Shader.POSITION + ";\n\t\t\t\tattribute vec4 " + Shader.COLOR + ";\n\t\t\t\tattribute vec2 " + Shader.TEXCOORDS + ";\n\t\t\t\tuniform mat4 " + Shader.MVP_MATRIX + ";\n\t\t\t\tvarying vec4 v_color;\n\t\t\t\tvarying vec2 v_texCoords;\n\n\t\t\t\tvoid main () {\n\t\t\t\t\tv_color = " + Shader.COLOR + ";\n\t\t\t\t\tv_texCoords = " + Shader.TEXCOORDS + ";\n\t\t\t\t\tgl_Position = " + Shader.MVP_MATRIX + " * " + Shader.POSITION + ";\n\t\t\t\t}\n\t\t\t";
var vs = "\n\t\t\t\tattribute vec4 ".concat(Shader.POSITION, ";\n\t\t\t\tattribute vec4 ").concat(Shader.COLOR, ";\n\t\t\t\tattribute vec2 ").concat(Shader.TEXCOORDS, ";\n\t\t\t\tuniform mat4 ").concat(Shader.MVP_MATRIX, ";\n\t\t\t\tvarying vec4 v_color;\n\t\t\t\tvarying vec2 v_texCoords;\n\n\t\t\t\tvoid main () {\n\t\t\t\t\tv_color = ").concat(Shader.COLOR, ";\n\t\t\t\t\tv_texCoords = ").concat(Shader.TEXCOORDS, ";\n\t\t\t\t\tgl_Position = ").concat(Shader.MVP_MATRIX, " * ").concat(Shader.POSITION, ";\n\t\t\t\t}\n\t\t\t");
var fs = "\n\t\t\t\t#ifdef GL_ES\n\t\t\t\t\t#define LOWP lowp\n\t\t\t\t\tprecision mediump float;\n\t\t\t\t#else\n\t\t\t\t\t#define LOWP\n\t\t\t\t#endif\n\t\t\t\tvarying LOWP vec4 v_color;\n\t\t\t\tvarying vec2 v_texCoords;\n\t\t\t\tuniform sampler2D u_texture;\n\n\t\t\t\tvoid main () {\n\t\t\t\t\tgl_FragColor = v_color * texture2D(u_texture, v_texCoords);\n\t\t\t\t}\n\t\t\t";
return new Shader(context, vs, fs);
};
Shader.newTwoColoredTextured = function (context) {
var vs = "\n\t\t\t\tattribute vec4 " + Shader.POSITION + ";\n\t\t\t\tattribute vec4 " + Shader.COLOR + ";\n\t\t\t\tattribute vec4 " + Shader.COLOR2 + ";\n\t\t\t\tattribute vec2 " + Shader.TEXCOORDS + ";\n\t\t\t\tuniform mat4 " + Shader.MVP_MATRIX + ";\n\t\t\t\tvarying vec4 v_light;\n\t\t\t\tvarying vec4 v_dark;\n\t\t\t\tvarying vec2 v_texCoords;\n\n\t\t\t\tvoid main () {\n\t\t\t\t\tv_light = " + Shader.COLOR + ";\n\t\t\t\t\tv_dark = " + Shader.COLOR2 + ";\n\t\t\t\t\tv_texCoords = " + Shader.TEXCOORDS + ";\n\t\t\t\t\tgl_Position = " + Shader.MVP_MATRIX + " * " + Shader.POSITION + ";\n\t\t\t\t}\n\t\t\t";
var vs = "\n\t\t\t\tattribute vec4 ".concat(Shader.POSITION, ";\n\t\t\t\tattribute vec4 ").concat(Shader.COLOR, ";\n\t\t\t\tattribute vec4 ").concat(Shader.COLOR2, ";\n\t\t\t\tattribute vec2 ").concat(Shader.TEXCOORDS, ";\n\t\t\t\tuniform mat4 ").concat(Shader.MVP_MATRIX, ";\n\t\t\t\tvarying vec4 v_light;\n\t\t\t\tvarying vec4 v_dark;\n\t\t\t\tvarying vec2 v_texCoords;\n\n\t\t\t\tvoid main () {\n\t\t\t\t\tv_light = ").concat(Shader.COLOR, ";\n\t\t\t\t\tv_dark = ").concat(Shader.COLOR2, ";\n\t\t\t\t\tv_texCoords = ").concat(Shader.TEXCOORDS, ";\n\t\t\t\t\tgl_Position = ").concat(Shader.MVP_MATRIX, " * ").concat(Shader.POSITION, ";\n\t\t\t\t}\n\t\t\t");
var fs = "\n\t\t\t\t#ifdef GL_ES\n\t\t\t\t\t#define LOWP lowp\n\t\t\t\t\tprecision mediump float;\n\t\t\t\t#else\n\t\t\t\t\t#define LOWP\n\t\t\t\t#endif\n\t\t\t\tvarying LOWP vec4 v_light;\n\t\t\t\tvarying LOWP vec4 v_dark;\n\t\t\t\tvarying vec2 v_texCoords;\n\t\t\t\tuniform sampler2D u_texture;\n\n\t\t\t\tvoid main () {\n\t\t\t\t\tvec4 texColor = texture2D(u_texture, v_texCoords);\n\t\t\t\t\tgl_FragColor.a = texColor.a * v_light.a;\n\t\t\t\t\tgl_FragColor.rgb = ((texColor.a - 1.0) * v_dark.a + 1.0 - texColor.rgb) * v_dark.rgb + texColor.rgb * v_light.rgb;\n\t\t\t\t}\n\t\t\t";
return new Shader(context, vs, fs);
};
Shader.newColored = function (context) {
var vs = "\n\t\t\t\tattribute vec4 " + Shader.POSITION + ";\n\t\t\t\tattribute vec4 " + Shader.COLOR + ";\n\t\t\t\tuniform mat4 " + Shader.MVP_MATRIX + ";\n\t\t\t\tvarying vec4 v_color;\n\n\t\t\t\tvoid main () {\n\t\t\t\t\tv_color = " + Shader.COLOR + ";\n\t\t\t\t\tgl_Position = " + Shader.MVP_MATRIX + " * " + Shader.POSITION + ";\n\t\t\t\t}\n\t\t\t";
var vs = "\n\t\t\t\tattribute vec4 ".concat(Shader.POSITION, ";\n\t\t\t\tattribute vec4 ").concat(Shader.COLOR, ";\n\t\t\t\tuniform mat4 ").concat(Shader.MVP_MATRIX, ";\n\t\t\t\tvarying vec4 v_color;\n\n\t\t\t\tvoid main () {\n\t\t\t\t\tv_color = ").concat(Shader.COLOR, ";\n\t\t\t\t\tgl_Position = ").concat(Shader.MVP_MATRIX, " * ").concat(Shader.POSITION, ";\n\t\t\t\t}\n\t\t\t");
var fs = "\n\t\t\t\t#ifdef GL_ES\n\t\t\t\t\t#define LOWP lowp\n\t\t\t\t\tprecision mediump float;\n\t\t\t\t#else\n\t\t\t\t\t#define LOWP\n\t\t\t\t#endif\n\t\t\t\tvarying LOWP vec4 v_color;\n\n\t\t\t\tvoid main () {\n\t\t\t\t\tgl_FragColor = v_color;\n\t\t\t\t}\n\t\t\t";
return new Shader(context, vs, fs);
};

File diff suppressed because one or more lines are too long

View file

@ -1,7 +1,7 @@
'use strict';
const webpack = require('webpack');
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
const TerserPlugin = require('terser-webpack-plugin');
const exec = require('child_process').exec;
const RemovePlugin = require('remove-files-webpack-plugin');
@ -53,18 +53,19 @@ module.exports = {
optimization: {
minimizer: [
new UglifyJSPlugin({
new TerserPlugin({
include: /\.min\.js$/,
parallel: true,
sourceMap: false,
uglifyOptions: {
extractComments: false,
terserOptions: {
format: {
comments: false
},
compress: true,
ie8: false,
ecma: 5,
output: {comments: false},
warnings: false
},
warningsFilter: () => false
}
})
]
},

View file

@ -1,7 +1,7 @@
'use strict';
const webpack = require('webpack');
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
const TerserPlugin = require('terser-webpack-plugin');
const exec = require('child_process').exec;
const RemovePlugin = require('remove-files-webpack-plugin');
@ -53,18 +53,19 @@ module.exports = {
optimization: {
minimizer: [
new UglifyJSPlugin({
new TerserPlugin({
include: /\.min\.js$/,
parallel: true,
sourceMap: false,
uglifyOptions: {
extractComments: false,
terserOptions: {
format: {
comments: false
},
compress: true,
ie8: false,
ecma: 5,
output: {comments: false},
warnings: false
},
warningsFilter: () => false
}
})
]
},

View file

@ -1,7 +1,7 @@
'use strict';
const webpack = require('webpack');
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
const TerserPlugin = require('terser-webpack-plugin');
const exec = require('child_process').exec;
const RemovePlugin = require('remove-files-webpack-plugin');
@ -53,18 +53,19 @@ module.exports = {
optimization: {
minimizer: [
new UglifyJSPlugin({
new TerserPlugin({
include: /\.min\.js$/,
parallel: true,
sourceMap: false,
uglifyOptions: {
extractComments: false,
terserOptions: {
format: {
comments: false
},
compress: true,
ie8: false,
ecma: 5,
output: {comments: false},
warnings: false
},
warningsFilter: () => false
}
})
]
},

View file

@ -603,6 +603,7 @@ var AnimationManager = new Class({
* Generates objects with string based frame names, as configured by the given {@link Phaser.Types.Animations.GenerateFrameNames}.
*
* It's a helper method, designed to make it easier for you to extract all of the frame names from texture atlases.
*
* If you're working with a sprite sheet, see the `generateFrameNumbers` method instead.
*
* Example:
@ -697,7 +698,6 @@ var AnimationManager = new Class({
* If you're working with a texture atlas, see the `generateFrameNames` method instead.
*
* It's a helper method, designed to make it easier for you to extract frames from sprite sheets.
* If you're working with a texture atlas, see the `generateFrameNames` method instead.
*
* Example:
*

View file

@ -472,7 +472,7 @@ var AnimationState = new Class({
* @method Phaser.Animations.AnimationState#chain
* @since 3.16.0
*
* @param {(string|Phaser.Animations.Animation|Phaser.Types.Animations.PlayAnimationConfig|string[]|Phaser.Animations.Animation[]|Phaser.Types.Animations.PlayAnimationConfig[])} key - The string-based key of the animation to play, or an Animation instance, or a `PlayAnimationConfig` object, or an array of them.
* @param {(string|Phaser.Animations.Animation|Phaser.Types.Animations.PlayAnimationConfig|string[]|Phaser.Animations.Animation[]|Phaser.Types.Animations.PlayAnimationConfig[])} [key] - The string-based key of the animation to play, or an Animation instance, or a `PlayAnimationConfig` object, or an array of them.
*
* @return {Phaser.GameObjects.GameObject} The Game Object that owns this Animation Component.
*/

View file

@ -46,97 +46,79 @@ var Config = new Class({
var defaultBannerTextColor = '#ffffff';
// Scale Manager - Anything set in here over-rides anything set in the core game config
var scaleConfig = GetValue(config, 'scale', null);
/**
* @const {(number|string)} Phaser.Core.Config#width - The width of the underlying canvas, in pixels.
*/
this.width = GetValue(config, 'width', 1024);
this.width = GetValue(scaleConfig, 'width', 1024, config);
/**
* @const {(number|string)} Phaser.Core.Config#height - The height of the underlying canvas, in pixels.
*/
this.height = GetValue(config, 'height', 768);
this.height = GetValue(scaleConfig, 'height', 768, config);
/**
* @const {(Phaser.Scale.ZoomType|number)} Phaser.Core.Config#zoom - The zoom factor, as used by the Scale Manager.
*/
this.zoom = GetValue(config, 'zoom', 1);
this.zoom = GetValue(scaleConfig, 'zoom', 1, config);
/**
* @const {?*} Phaser.Core.Config#parent - A parent DOM element into which the canvas created by the renderer will be injected.
*/
this.parent = GetValue(config, 'parent', undefined);
this.parent = GetValue(scaleConfig, 'parent', undefined, config);
/**
* @const {Phaser.Scale.ScaleModeType} Phaser.Core.Config#scaleMode - The scale mode as used by the Scale Manager. The default is zero, which is no scaling.
*/
this.scaleMode = GetValue(config, 'scaleMode', 0);
this.scaleMode = GetValue(scaleConfig, 'scaleMode', 0, config);
/**
* @const {boolean} Phaser.Core.Config#expandParent - Is the Scale Manager allowed to adjust the CSS height property of the parent to be 100%?
*/
this.expandParent = GetValue(config, 'expandParent', true);
this.expandParent = GetValue(scaleConfig, 'expandParent', true, config);
/**
* @const {boolean} Phaser.Core.Config#autoRound - Automatically round the display and style sizes of the canvas. This can help with performance in lower-powered devices.
*/
this.autoRound = GetValue(config, 'autoRound', false);
this.autoRound = GetValue(scaleConfig, 'autoRound', false, config);
/**
* @const {Phaser.Scale.CenterType} Phaser.Core.Config#autoCenter - Automatically center the canvas within the parent?
*/
this.autoCenter = GetValue(config, 'autoCenter', 0);
this.autoCenter = GetValue(scaleConfig, 'autoCenter', 0, config);
/**
* @const {number} Phaser.Core.Config#resizeInterval - How many ms should elapse before checking if the browser size has changed?
*/
this.resizeInterval = GetValue(config, 'resizeInterval', 500);
this.resizeInterval = GetValue(scaleConfig, 'resizeInterval', 500, config);
/**
* @const {?(HTMLElement|string)} Phaser.Core.Config#fullscreenTarget - The DOM element that will be sent into full screen mode, or its `id`. If undefined Phaser will create its own div and insert the canvas into it when entering fullscreen mode.
*/
this.fullscreenTarget = GetValue(config, 'fullscreenTarget', null);
this.fullscreenTarget = GetValue(scaleConfig, 'fullscreenTarget', null, config);
/**
* @const {number} Phaser.Core.Config#minWidth - The minimum width, in pixels, the canvas will scale down to. A value of zero means no minimum.
*/
this.minWidth = GetValue(config, 'minWidth', 0);
this.minWidth = GetValue(scaleConfig, 'minWidth', 0, config);
/**
* @const {number} Phaser.Core.Config#maxWidth - The maximum width, in pixels, the canvas will scale up to. A value of zero means no maximum.
*/
this.maxWidth = GetValue(config, 'maxWidth', 0);
this.maxWidth = GetValue(scaleConfig, 'maxWidth', 0, config);
/**
* @const {number} Phaser.Core.Config#minHeight - The minimum height, in pixels, the canvas will scale down to. A value of zero means no minimum.
*/
this.minHeight = GetValue(config, 'minHeight', 0);
this.minHeight = GetValue(scaleConfig, 'minHeight', 0, config);
/**
* @const {number} Phaser.Core.Config#maxHeight - The maximum height, in pixels, the canvas will scale up to. A value of zero means no maximum.
*/
this.maxHeight = GetValue(config, 'maxHeight', 0);
// Scale Manager - Anything set in here over-rides anything set above
var scaleConfig = GetValue(config, 'scale', null);
if (scaleConfig)
{
this.width = GetValue(scaleConfig, 'width', this.width);
this.height = GetValue(scaleConfig, 'height', this.height);
this.zoom = GetValue(scaleConfig, 'zoom', this.zoom);
this.parent = GetValue(scaleConfig, 'parent', this.parent);
this.scaleMode = GetValue(scaleConfig, 'mode', this.scaleMode);
this.expandParent = GetValue(scaleConfig, 'expandParent', this.expandParent);
this.autoRound = GetValue(scaleConfig, 'autoRound', this.autoRound);
this.autoCenter = GetValue(scaleConfig, 'autoCenter', this.autoCenter);
this.resizeInterval = GetValue(scaleConfig, 'resizeInterval', this.resizeInterval);
this.fullscreenTarget = GetValue(scaleConfig, 'fullscreenTarget', this.fullscreenTarget);
this.minWidth = GetValue(scaleConfig, 'min.width', this.minWidth);
this.maxWidth = GetValue(scaleConfig, 'max.width', this.maxWidth);
this.minHeight = GetValue(scaleConfig, 'min.height', this.minHeight);
this.maxHeight = GetValue(scaleConfig, 'max.height', this.maxHeight);
}
this.maxHeight = GetValue(scaleConfig, 'maxHeight', 0, config);
/**
* @const {number} Phaser.Core.Config#renderType - Force Phaser to use a specific renderer. Can be `CONST.CANVAS`, `CONST.WEBGL`, `CONST.HEADLESS` or `CONST.AUTO` (default)
@ -336,45 +318,44 @@ var Config = new Class({
*/
this.fps = GetValue(config, 'fps', null);
// Renderer Settings
// These can either be in a `render` object within the Config, or specified on their own
// Render Settings - Anything set in here over-rides anything set in the core game config
var renderConfig = GetValue(config, 'render', config);
var renderConfig = GetValue(config, 'render', null);
/**
* @const {Phaser.Types.Core.PipelineConfig} Phaser.Core.Config#pipeline - An object mapping WebGL names to WebGLPipeline classes. These should be class constructors, not instances.
*/
this.pipeline = GetValue(renderConfig, 'pipeline', null);
this.pipeline = GetValue(renderConfig, 'pipeline', null, config);
/**
* @const {boolean} Phaser.Core.Config#antialias - When set to `true`, WebGL uses linear interpolation to draw scaled or rotated textures, giving a smooth appearance. When set to `false`, WebGL uses nearest-neighbor interpolation, giving a crisper appearance. `false` also disables antialiasing of the game canvas itself, if the browser supports it, when the game canvas is scaled.
*/
this.antialias = GetValue(renderConfig, 'antialias', true);
this.antialias = GetValue(renderConfig, 'antialias', true, config);
/**
* @const {boolean} Phaser.Core.Config#antialiasGL - Sets the `antialias` property when the WebGL context is created. Setting this value does not impact any subsequent textures that are created, or the canvas style attributes.
*/
this.antialiasGL = GetValue(renderConfig, 'antialiasGL', true);
this.antialiasGL = GetValue(renderConfig, 'antialiasGL', true, config);
/**
* @const {string} Phaser.Core.Config#mipmapFilter - Sets the `mipmapFilter` property when the WebGL renderer is created.
*/
this.mipmapFilter = GetValue(renderConfig, 'mipmapFilter', 'LINEAR');
this.mipmapFilter = GetValue(renderConfig, 'mipmapFilter', 'LINEAR', config);
/**
* @const {boolean} Phaser.Core.Config#desynchronized - When set to `true` it will create a desynchronized context for both 2D and WebGL. See https://developers.google.com/web/updates/2019/05/desynchronized for details.
*/
this.desynchronized = GetValue(renderConfig, 'desynchronized', false);
this.desynchronized = GetValue(renderConfig, 'desynchronized', false, config);
/**
* @const {boolean} Phaser.Core.Config#roundPixels - Draw texture-based Game Objects at only whole-integer positions. Game Objects without textures, like Graphics, ignore this property.
*/
this.roundPixels = GetValue(renderConfig, 'roundPixels', false);
this.roundPixels = GetValue(renderConfig, 'roundPixels', false, config);
/**
* @const {boolean} Phaser.Core.Config#pixelArt - Prevent pixel art from becoming blurred when scaled. It will remain crisp (tells the WebGL renderer to automatically create textures using a linear filter mode).
*/
this.pixelArt = GetValue(renderConfig, 'pixelArt', this.zoom !== 1);
this.pixelArt = GetValue(renderConfig, 'pixelArt', this.zoom !== 1, config);
if (this.pixelArt)
{
@ -386,47 +367,47 @@ var Config = new Class({
/**
* @const {boolean} Phaser.Core.Config#transparent - Whether the game canvas will have a transparent background.
*/
this.transparent = GetValue(renderConfig, 'transparent', false);
this.transparent = GetValue(renderConfig, 'transparent', false, config);
/**
* @const {boolean} Phaser.Core.Config#clearBeforeRender - Whether the game canvas will be cleared between each rendering frame. You can disable this if you have a full-screen background image or game object.
*/
this.clearBeforeRender = GetValue(renderConfig, 'clearBeforeRender', true);
this.clearBeforeRender = GetValue(renderConfig, 'clearBeforeRender', true, config);
/**
* @const {boolean} Phaser.Core.Config#preserveDrawingBuffer - If the value is true the WebGL buffers will not be cleared and will preserve their values until cleared or overwritten by the author.
*/
this.preserveDrawingBuffer = GetValue(renderConfig, 'preserveDrawingBuffer', false);
this.preserveDrawingBuffer = GetValue(renderConfig, 'preserveDrawingBuffer', false, config);
/**
* @const {boolean} Phaser.Core.Config#premultipliedAlpha - In WebGL mode, sets the drawing buffer to contain colors with pre-multiplied alpha.
*/
this.premultipliedAlpha = GetValue(renderConfig, 'premultipliedAlpha', true);
this.premultipliedAlpha = GetValue(renderConfig, 'premultipliedAlpha', true, config);
/**
* @const {boolean} Phaser.Core.Config#failIfMajorPerformanceCaveat - Let the browser abort creating a WebGL context if it judges performance would be unacceptable.
*/
this.failIfMajorPerformanceCaveat = GetValue(renderConfig, 'failIfMajorPerformanceCaveat', false);
this.failIfMajorPerformanceCaveat = GetValue(renderConfig, 'failIfMajorPerformanceCaveat', false, config);
/**
* @const {string} Phaser.Core.Config#powerPreference - "high-performance", "low-power" or "default". A hint to the browser on how much device power the game might use.
*/
this.powerPreference = GetValue(renderConfig, 'powerPreference', 'default');
this.powerPreference = GetValue(renderConfig, 'powerPreference', 'default', config);
/**
* @const {number} Phaser.Core.Config#batchSize - The default WebGL Batch size. Represents the number of _quads_ that can be added to a single batch.
*/
this.batchSize = GetValue(renderConfig, 'batchSize', 4096);
this.batchSize = GetValue(renderConfig, 'batchSize', 4096, config);
/**
* @const {number} Phaser.Core.Config#maxTextures - When in WebGL mode, this sets the maximum number of GPU Textures to use. The default, -1, will use all available units. The WebGL1 spec says all browsers should provide a minimum of 8.
*/
this.maxTextures = GetValue(renderConfig, 'maxTextures', -1);
this.maxTextures = GetValue(renderConfig, 'maxTextures', -1, config);
/**
* @const {number} Phaser.Core.Config#maxLights - The maximum number of lights allowed to be visible within range of a single Camera in the LightManager.
*/
this.maxLights = GetValue(renderConfig, 'maxLights', 10);
this.maxLights = GetValue(renderConfig, 'maxLights', 10, config);
var bgc = GetValue(config, 'backgroundColor', 0);

View file

@ -651,7 +651,7 @@ var TimeStep = new Class({
this.startTime += -this.lastTime + (this.lastTime + window.performance.now());
}
this.raf.start(this.step.bind(this), this.useRAF);
this.raf.start(this.step.bind(this), this.forceSetTimeOut, this._target);
this.running = true;

View file

@ -85,17 +85,20 @@ var BlitterCanvasRenderer = function (renderer, src, camera, parentMatrix)
dy = Math.round(dy);
}
ctx.drawImage(
frame.source.image,
cd.x,
cd.y,
cd.width,
cd.height,
dx + bob.x + cameraScrollX,
dy + bob.y + cameraScrollY,
cd.width,
cd.height
);
if (cd.width > 0 && cd.height > 0)
{
ctx.drawImage(
frame.source.image,
cd.x,
cd.y,
cd.width,
cd.height,
dx + bob.x + cameraScrollX,
dy + bob.y + cameraScrollY,
cd.width,
cd.height
);
}
}
else
{
@ -111,11 +114,14 @@ var BlitterCanvasRenderer = function (renderer, src, camera, parentMatrix)
dy -= cd.height;
}
ctx.save();
ctx.translate(bob.x + cameraScrollX, bob.y + cameraScrollY);
ctx.scale(fx, fy);
ctx.drawImage(frame.source.image, cd.x, cd.y, cd.width, cd.height, dx, dy, cd.width, cd.height);
ctx.restore();
if (cd.width > 0 && cd.height > 0)
{
ctx.save();
ctx.translate(bob.x + cameraScrollX, bob.y + cameraScrollY);
ctx.scale(fx, fy);
ctx.drawImage(frame.source.image, cd.x, cd.y, cd.width, cd.height, dx, dy, cd.width, cd.height);
ctx.restore();
}
}
}

View file

@ -498,7 +498,8 @@ var Container = new Class({
}
else
{
output = new Vector2(source.x, source.y);
output.x = source.x;
output.y = source.y;
}
var tempMatrix = this.tempTransformMatrix;

View file

@ -1064,8 +1064,74 @@ var Mesh = new Class({
this.debugCallback = null;
this.debugGraphic = null;
}
},
/**
* Clears all tint values associated with this Game Object.
*
* Immediately sets the color values back to 0xffffff on all vertices,
* which results in no visible change to the texture.
*
* @method Phaser.GameObjects.Mesh#clearTint
* @webglOnly
* @since 3.60.0
*
* @return {this} This Game Object instance.
*/
clearTint: function ()
{
return this.setTint();
},
/**
* Sets an additive tint on all vertices of this Mesh Game Object.
*
* The tint works by taking the pixel color values from the Game Objects texture, and then
* multiplying it by the color value of the tint.
*
* To modify the tint color once set, either call this method again with new values or use the
* `tint` property to set all colors at once.
*
* To remove a tint call `clearTint`.
*
* @method Phaser.GameObjects.Mesh#setTint
* @webglOnly
* @since 3.60.0
*
* @param {number} [tint=0xffffff] - The tint being applied to all vertices of this Mesh Game Object.
*
* @return {this} This Game Object instance.
*/
setTint: function (tint)
{
if (tint === undefined) { tint = 0xffffff; }
var vertices = this.vertices;
for (var i = 0; i < vertices.length; i++)
{
vertices[i].color = tint;
}
return this;
},
/**
* The tint value being applied to the whole of the Game Object.
* This property is a setter-only.
*
* @method Phaser.GameObjects.Mesh#tint
* @type {number}
* @webglOnly
* @since 3.60.0
*/
tint: {
set: function (value)
{
this.setTint(value);
}
}
});
module.exports = Mesh;

View file

@ -103,26 +103,29 @@ var ParticleManagerCanvasRenderer = function (renderer, emitterManager, camera,
var frame = particle.frame;
var cd = frame.canvasData;
var x = -(frame.halfWidth);
var y = -(frame.halfHeight);
ctx.globalAlpha = alpha;
ctx.save();
calcMatrix.setToContext(ctx);
if (roundPixels)
if (cd.width > 0 && cd.height > 0)
{
x = Math.round(x);
y = Math.round(y);
var x = -(frame.halfWidth);
var y = -(frame.halfHeight);
ctx.globalAlpha = alpha;
ctx.save();
calcMatrix.setToContext(ctx);
if (roundPixels)
{
x = Math.round(x);
y = Math.round(y);
}
ctx.imageSmoothingEnabled = !(!renderer.antialias || frame.source.scaleMode);
ctx.drawImage(frame.source.image, cd.x, cd.y, cd.width, cd.height, x, y, cd.width, cd.height);
ctx.restore();
}
ctx.imageSmoothingEnabled = !(!renderer.antialias || frame.source.scaleMode);
ctx.drawImage(frame.source.image, cd.x, cd.y, cd.width, cd.height, x, y, cd.width, cd.height);
ctx.restore();
}
ctx.restore();

View file

@ -664,7 +664,10 @@ var RenderTexture = new Class({
* * A Texture Frame instance.
* * A string. This is used to look-up a texture from the Texture Manager.
*
* Note: You cannot draw a Render Texture to itself.
* Note 1: You cannot draw a Render Texture to itself.
*
* Note 2: For Game Objects that have Post FX Pipelines, the pipeline _cannot_ be
* used when drawn to this Render Texture.
*
* If passing in a Group or Container it will only draw children that return `true`
* when their `willRender()` method is called. I.e. a Container with 10 children,
@ -1279,7 +1282,10 @@ var RenderTexture = new Class({
matrix.setToContext(ctx);
ctx.drawImage(source, cd.x, cd.y, cd.width, cd.height, x, y, cd.width, cd.height);
if (cd.width > 0 && cd.height > 0)
{
ctx.drawImage(source, cd.x, cd.y, cd.width, cd.height, x, y, cd.width, cd.height);
}
ctx.restore();
}

View file

@ -56,7 +56,10 @@ var PolygonCanvasRenderer = function (renderer, src, camera, parentMatrix)
ctx.lineTo(px2, py2);
}
ctx.closePath();
if (src.closePath)
{
ctx.closePath();
}
if (src.isFilled)
{

View file

@ -346,7 +346,7 @@ var Sprite = new Class({
* @method Phaser.GameObjects.Sprite#chain
* @since 3.50.0
*
* @param {(string|Phaser.Animations.Animation|Phaser.Types.Animations.PlayAnimationConfig|string[]|Phaser.Animations.Animation[]|Phaser.Types.Animations.PlayAnimationConfig[])} key - The string-based key of the animation to play, or an Animation instance, or a `PlayAnimationConfig` object, or an array of them.
* @param {(string|Phaser.Animations.Animation|Phaser.Types.Animations.PlayAnimationConfig|string[]|Phaser.Animations.Animation[]|Phaser.Types.Animations.PlayAnimationConfig[])} [key] - The string-based key of the animation to play, or an Animation instance, or a `PlayAnimationConfig` object, or an array of them.
*
* @return {this} This Game Object.
*/

View file

@ -8,5 +8,5 @@
* @property {number} [width=512] - The width of the Tile Sprite. If zero it will use the size of the texture frame.
* @property {number} [height=512] - The height of the Tile Sprite. If zero it will use the size of the texture frame.
* @property {string} [key=''] - The key of the Texture this Tile Sprite will use to render with, as stored in the Texture Manager.
* @property {string} [frame=''] - An optional frame from the Texture this Tile Sprite is rendering with.
* @property {(number|string|Phaser.Textures.Frame)} [frame=''] - An optional frame from the Texture this Tile Sprite is rendering with.
*/

View file

@ -158,13 +158,21 @@ var HTML5AudioFile = new Class({
var audio = new Audio();
var dataset = audio.dataset;
if (dataset === undefined)
{
audio.dataset = dataset = {
name: '',
used: ''
};
}
dataset.name = this.key + '-' + i.toString();
dataset.used = 'false';
if (this.locked)
{
dataset.locked = 'true';
console.log('HTML5AudioFile:', dataset.name, 'locked');
// console.log('HTML5AudioFile:', dataset.name, 'locked');
}
else
{
@ -174,7 +182,7 @@ var HTML5AudioFile = new Class({
audio.oncanplaythrough = this.onProgress.bind(this);
audio.onerror = this.onError.bind(this);
console.log('HTML5AudioFile:', dataset.name, 'unlocked');
// console.log('HTML5AudioFile:', dataset.name, 'unlocked');
}
this.data.push(audio);
@ -189,7 +197,7 @@ var HTML5AudioFile = new Class({
if (!this.locked)
{
audio.load();
console.log('HTML5AudioFile:', dataset.name, 'load called');
// console.log('HTML5AudioFile:', dataset.name, 'load called');
}
}

View file

@ -1346,14 +1346,12 @@ var World = new Class({
* @param {ArcadePhysicsCallback} [processCallback] - The process callback.
* @param {*} [callbackContext] - The context in which to invoke the callback.
* @param {boolean} [overlapOnly] - If this a collide or overlap check?
* @param {boolean} [intersects] - Assert that the bodies intersect and should not be tested before separation.
*
* @return {boolean} True if separation occurred, otherwise false.
*/
separate: function (body1, body2, processCallback, callbackContext, overlapOnly, intersects)
separate: function (body1, body2, processCallback, callbackContext, overlapOnly)
{
if (
!intersects &&
!body1.enable ||
!body2.enable ||
body1.checkCollision.none ||
@ -2002,7 +2000,7 @@ var World = new Class({
continue;
}
if (this.separate(bodyA, bodyB, processCallback, callbackContext, overlapOnly, true))
if (this.separate(bodyA, bodyB, processCallback, callbackContext, overlapOnly))
{
if (collideCallback)
{

View file

@ -11,6 +11,7 @@ var Body = require('./lib/body/Body');
var BodyBounds = require('./BodyBounds');
var Bounds = require('./lib/geometry/Bounds');
var Class = require('../../utils/Class');
var Collision = require('./lib/collision/Collision');
var Composite = require('./lib/body/Composite');
var Composites = require('./lib/factory/Composites');
var Constraint = require('./lib/constraint/Constraint');
@ -193,6 +194,19 @@ var MatterPhysics = new Class({
// Collision:
/**
* A reference to the `Matter.Collision` module.
*
* The `Matter.Collision` module contains methods for detecting collisions between a given pair of bodies.
*
* For efficient detection between a list of bodies, see `Matter.Detector` and `Matter.Query`.
*
* @name Phaser.Physics.Matter.MatterPhysics#collision
* @type {MatterJS.Collision}
* @since 3.60.0
*/
this.collision = Collision;
/**
* A reference to the `Matter.Detector` module.
*

View file

@ -37,7 +37,12 @@ var Body = require('./Body');
constraints: [],
composites: [],
label: 'Composite',
plugin: {}
plugin: {},
cache: {
allBodies: null,
allConstraints: null,
allComposites: null
}
}, options);
};
@ -57,12 +62,18 @@ var Body = require('./Body');
composite.isModified = isModified;
if (isModified && composite.cache) {
composite.cache.allBodies = null;
composite.cache.allConstraints = null;
composite.cache.allComposites = null;
}
if (updateParents && composite.parent) {
Composite.setModified(composite.parent, isModified, updateParents, updateChildren);
}
if (updateChildren) {
for(var i = 0; i < composite.composites.length; i++) {
for (var i = 0; i < composite.composites.length; i++) {
var childComposite = composite.composites[i];
Composite.setModified(childComposite, isModified, updateParents, updateChildren);
}
@ -70,11 +81,11 @@ var Body = require('./Body');
};
/**
* Generic add function. Adds one or many body(s), constraint(s) or a composite(s) to the given composite.
* Generic single or multi-add function. Adds a single or an array of body(s), constraint(s) or composite(s) to the given composite.
* Triggers `beforeAdd` and `afterAdd` events on the `composite`.
* @method add
* @param {composite} composite
* @param {} object
* @param {object|array} object A single or an array of body(s), constraint(s) or composite(s)
* @return {composite} The original composite with the objects added
*/
Composite.add = function(composite, object) {
@ -120,7 +131,7 @@ var Body = require('./Body');
* Triggers `beforeRemove` and `afterRemove` events on the `composite`.
* @method remove
* @param {composite} composite
* @param {} object
* @param {object|array} object
* @param {boolean} [deep=false]
* @return {composite} The original composite with the objects removed
*/
@ -180,10 +191,9 @@ var Body = require('./Body');
* @return {composite} The original compositeA with the composite removed
*/
Composite.removeComposite = function(compositeA, compositeB, deep) {
var position = compositeA.composites.indexOf(compositeB);
var position = Common.indexOf(compositeA.composites, compositeB);
if (position !== -1) {
Composite.removeCompositeAt(compositeA, position);
Composite.setModified(compositeA, true, true, false);
}
if (deep) {
@ -233,10 +243,9 @@ var Body = require('./Body');
* @return {composite} The original composite with the body removed
*/
Composite.removeBody = function(composite, body, deep) {
var position = composite.bodies.indexOf(body);
var position = Common.indexOf(composite.bodies, body);
if (position !== -1) {
Composite.removeBodyAt(composite, position);
Composite.setModified(composite, true, true, false);
}
if (deep) {
@ -286,7 +295,7 @@ var Body = require('./Body');
* @return {composite} The original composite with the constraint removed
*/
Composite.removeConstraint = function(composite, constraint, deep) {
var position = composite.constraints.indexOf(constraint);
var position = Common.indexOf(composite.constraints, constraint);
if (position !== -1) {
Composite.removeConstraintAt(composite, position);
}
@ -337,6 +346,7 @@ var Body = require('./Body');
composite.constraints.length = 0;
composite.composites.length = 0;
Composite.setModified(composite, true, true, false);
return composite;
@ -349,11 +359,19 @@ var Body = require('./Body');
* @return {body[]} All the bodies
*/
Composite.allBodies = function(composite) {
if (composite.cache && composite.cache.allBodies) {
return composite.cache.allBodies;
}
var bodies = [].concat(composite.bodies);
for (var i = 0; i < composite.composites.length; i++)
bodies = bodies.concat(Composite.allBodies(composite.composites[i]));
if (composite.cache) {
composite.cache.allBodies = bodies;
}
return bodies;
};
@ -364,11 +382,19 @@ var Body = require('./Body');
* @return {constraint[]} All the constraints
*/
Composite.allConstraints = function(composite) {
if (composite.cache && composite.cache.allConstraints) {
return composite.cache.allConstraints;
}
var constraints = [].concat(composite.constraints);
for (var i = 0; i < composite.composites.length; i++)
constraints = constraints.concat(Composite.allConstraints(composite.composites[i]));
if (composite.cache) {
composite.cache.allConstraints = constraints;
}
return constraints;
};
@ -379,11 +405,19 @@ var Body = require('./Body');
* @return {composite[]} All the composites
*/
Composite.allComposites = function(composite) {
if (composite.cache && composite.cache.allComposites) {
return composite.cache.allComposites;
}
var composites = [].concat(composite.composites);
for (var i = 0; i < composite.composites.length; i++)
composites = composites.concat(Composite.allComposites(composite.composites[i]));
if (composite.cache) {
composite.cache.allComposites = composites;
}
return composites;
};
@ -450,8 +484,6 @@ var Body = require('./Body');
objects[i].id = Common.nextId();
}
Composite.setModified(composite, true, true, false);
return composite;
};
@ -470,8 +502,6 @@ var Body = require('./Body');
Body.translate(bodies[i], translation);
}
Composite.setModified(composite, true, true, false);
return composite;
};
@ -501,8 +531,6 @@ var Body = require('./Body');
Body.rotate(body, rotation);
}
Composite.setModified(composite, true, true, false);
return composite;
};
@ -531,8 +559,6 @@ var Body = require('./Body');
Body.scale(body, scaleX, scaleY);
}
Composite.setModified(composite, true, true, false);
return composite;
};
@ -685,4 +711,13 @@ var Body = require('./Body');
* @type {}
*/
/**
* An object used for storing cached results for performance reasons.
* This is used internally only and is automatically managed.
*
* @private
* @property cache
* @type {}
*/
})();

View file

@ -1,11 +1,13 @@
/**
* The `Matter.World` module contains methods for creating and manipulating the world composite.
* A `Matter.World` is a `Matter.Composite` body, which is a collection of `Matter.Body`, `Matter.Constraint` and other `Matter.Composite`.
* A `Matter.World` has a few additional properties including `gravity` and `bounds`.
* It is important to use the functions in the `Matter.Composite` module to modify the world composite, rather than directly modifying its properties.
* There are also a few methods here that alias those in `Matter.Composite` for easier readability.
* This module has now been replaced by `Matter.Composite`.
*
* See the included usage [examples](https://github.com/liabru/matter-js/tree/master/examples).
* All usage should be migrated to the equivalent functions found on `Matter.Composite`.
* For example `World.add(world, body)` now becomes `Composite.add(world, body)`.
*
* The property `world.gravity` has been moved to `engine.gravity`.
*
* For back-compatibility purposes this module will remain as a direct alias to `Matter.Composite` in the short term during migration.
* Eventually this alias module will be marked as deprecated and then later removed in a future release.
*
* @class World
* @extends Composite
@ -16,37 +18,19 @@ var World = {};
module.exports = World;
var Composite = require('./Composite');
var Constraint = require('../constraint/Constraint');
var Common = require('../core/Common');
(function() {
/**
* Creates a new world composite. The options parameter is an object that specifies any properties you wish to override the defaults.
* See the properties section below for detailed information on what you can pass via the `options` object.
* @method create
* @constructor
* @param {} options
* @return {world} A new world
* See above, aliases for back compatibility only
*/
World.create = function(options) {
var composite = Composite.create();
var defaults = {
label: 'World',
gravity: {
x: 0,
y: 1,
scale: 0.001
},
bounds: {
min: { x: -Infinity, y: -Infinity },
max: { x: Infinity, y: Infinity }
}
};
return Common.extend(composite, defaults, options);
};
World.create = Composite.create;
World.add = Composite.add;
World.remove = Composite.remove;
World.clear = Composite.clear;
World.addComposite = Composite.addComposite;
World.addBody = Composite.addBody;
World.addConstraint = Composite.addConstraint;
/*
*

View file

@ -0,0 +1,408 @@
/**
* The `Matter.Collision` module contains methods for detecting collisions between a given pair of bodies.
*
* For efficient detection between a list of bodies, see `Matter.Detector` and `Matter.Query`.
*
* See `Matter.Engine` for collision events.
*
* @class Collision
*/
var Collision = {};
module.exports = Collision;
var Vertices = require('../geometry/Vertices');
var Pair = require('./Pair');
(function() {
var _supports = [];
var _overlapAB = {
overlap: 0,
axis: null
};
var _overlapBA = {
overlap: 0,
axis: null
};
/**
* Creates a new collision record.
* @method create
* @param {body} bodyA The first body part represented by the collision record
* @param {body} bodyB The second body part represented by the collision record
* @return {collision} A new collision record
*/
Collision.create = function(bodyA, bodyB) {
return {
pair: null,
collided: false,
bodyA: bodyA,
bodyB: bodyB,
parentA: bodyA.parent,
parentB: bodyB.parent,
depth: 0,
normal: { x: 0, y: 0 },
tangent: { x: 0, y: 0 },
penetration: { x: 0, y: 0 },
supports: []
};
};
/**
* Detect collision between two bodies.
* @method collides
* @param {body} bodyA
* @param {body} bodyB
* @param {pairs} [pairs] Optionally reuse collision records from existing pairs.
* @return {collision|null} A collision record if detected, otherwise null
*/
Collision.collides = function(bodyA, bodyB, pairs) {
Collision._overlapAxes(_overlapAB, bodyA.vertices, bodyB.vertices, bodyA.axes);
if (_overlapAB.overlap <= 0) {
return null;
}
Collision._overlapAxes(_overlapBA, bodyB.vertices, bodyA.vertices, bodyB.axes);
if (_overlapBA.overlap <= 0) {
return null;
}
// reuse collision records for gc efficiency
var pair = pairs && pairs.table[Pair.id(bodyA, bodyB)],
collision;
if (!pair) {
collision = Collision.create(bodyA, bodyB);
collision.collided = true;
collision.bodyA = bodyA.id < bodyB.id ? bodyA : bodyB;
collision.bodyB = bodyA.id < bodyB.id ? bodyB : bodyA;
collision.parentA = collision.bodyA.parent;
collision.parentB = collision.bodyB.parent;
} else {
collision = pair.collision;
}
bodyA = collision.bodyA;
bodyB = collision.bodyB;
var minOverlap;
if (_overlapAB.overlap < _overlapBA.overlap) {
minOverlap = _overlapAB;
} else {
minOverlap = _overlapBA;
}
var normal = collision.normal,
supports = collision.supports,
minAxis = minOverlap.axis,
minAxisX = minAxis.x,
minAxisY = minAxis.y;
// ensure normal is facing away from bodyA
if (minAxisX * (bodyB.position.x - bodyA.position.x) + minAxisY * (bodyB.position.y - bodyA.position.y) < 0) {
normal.x = minAxisX;
normal.y = minAxisY;
} else {
normal.x = -minAxisX;
normal.y = -minAxisY;
}
collision.tangent.x = -normal.y;
collision.tangent.y = normal.x;
collision.depth = minOverlap.overlap;
collision.penetration.x = normal.x * collision.depth;
collision.penetration.y = normal.y * collision.depth;
// find support points, there is always either exactly one or two
var supportsB = Collision._findSupports(bodyA, bodyB, normal, 1),
supportCount = 0;
// find the supports from bodyB that are inside bodyA
if (Vertices.contains(bodyA.vertices, supportsB[0])) {
supports[supportCount++] = supportsB[0];
}
if (Vertices.contains(bodyA.vertices, supportsB[1])) {
supports[supportCount++] = supportsB[1];
}
// find the supports from bodyA that are inside bodyB
if (supportCount < 2) {
var supportsA = Collision._findSupports(bodyB, bodyA, normal, -1);
if (Vertices.contains(bodyB.vertices, supportsA[0])) {
supports[supportCount++] = supportsA[0];
}
if (supportCount < 2 && Vertices.contains(bodyB.vertices, supportsA[1])) {
supports[supportCount++] = supportsA[1];
}
}
// account for the edge case of overlapping but no vertex containment
if (supportCount === 0) {
supports[supportCount++] = supportsB[0];
}
// update supports array size
supports.length = supportCount;
return collision;
};
/**
* Find the overlap between two sets of vertices.
* @method _overlapAxes
* @private
* @param {object} result
* @param {vertices} verticesA
* @param {vertices} verticesB
* @param {axes} axes
*/
Collision._overlapAxes = function(result, verticesA, verticesB, axes) {
var verticesALength = verticesA.length,
verticesBLength = verticesB.length,
verticesAX = verticesA[0].x,
verticesAY = verticesA[0].y,
verticesBX = verticesB[0].x,
verticesBY = verticesB[0].y,
axesLength = axes.length,
overlapMin = Number.MAX_VALUE,
overlapAxisNumber = 0,
overlap,
overlapAB,
overlapBA,
dot,
i,
j;
for (i = 0; i < axesLength; i++) {
var axis = axes[i],
axisX = axis.x,
axisY = axis.y,
minA = verticesAX * axisX + verticesAY * axisY,
minB = verticesBX * axisX + verticesBY * axisY,
maxA = minA,
maxB = minB;
for (j = 1; j < verticesALength; j += 1) {
dot = verticesA[j].x * axisX + verticesA[j].y * axisY;
if (dot > maxA) {
maxA = dot;
} else if (dot < minA) {
minA = dot;
}
}
for (j = 1; j < verticesBLength; j += 1) {
dot = verticesB[j].x * axisX + verticesB[j].y * axisY;
if (dot > maxB) {
maxB = dot;
} else if (dot < minB) {
minB = dot;
}
}
overlapAB = maxA - minB;
overlapBA = maxB - minA;
overlap = overlapAB < overlapBA ? overlapAB : overlapBA;
if (overlap < overlapMin) {
overlapMin = overlap;
overlapAxisNumber = i;
if (overlap <= 0) {
// can not be intersecting
break;
}
}
}
result.axis = axes[overlapAxisNumber];
result.overlap = overlapMin;
};
/**
* Projects vertices on an axis and returns an interval.
* @method _projectToAxis
* @private
* @param {} projection
* @param {} vertices
* @param {} axis
*/
Collision._projectToAxis = function(projection, vertices, axis) {
var min = vertices[0].x * axis.x + vertices[0].y * axis.y,
max = min;
for (var i = 1; i < vertices.length; i += 1) {
var dot = vertices[i].x * axis.x + vertices[i].y * axis.y;
if (dot > max) {
max = dot;
} else if (dot < min) {
min = dot;
}
}
projection.min = min;
projection.max = max;
};
/**
* Finds supporting vertices given two bodies along a given direction using hill-climbing.
* @method _findSupports
* @private
* @param {body} bodyA
* @param {body} bodyB
* @param {vector} normal
* @param {number} direction
* @return [vector]
*/
Collision._findSupports = function(bodyA, bodyB, normal, direction) {
var vertices = bodyB.vertices,
verticesLength = vertices.length,
bodyAPositionX = bodyA.position.x,
bodyAPositionY = bodyA.position.y,
normalX = normal.x * direction,
normalY = normal.y * direction,
nearestDistance = Number.MAX_VALUE,
vertexA,
vertexB,
vertexC,
distance,
j;
// find deepest vertex relative to the axis
for (j = 0; j < verticesLength; j += 1) {
vertexB = vertices[j];
distance = normalX * (bodyAPositionX - vertexB.x) + normalY * (bodyAPositionY - vertexB.y);
// convex hill-climbing
if (distance < nearestDistance) {
nearestDistance = distance;
vertexA = vertexB;
}
}
// measure next vertex
vertexC = vertices[(verticesLength + vertexA.index - 1) % verticesLength];
nearestDistance = normalX * (bodyAPositionX - vertexC.x) + normalY * (bodyAPositionY - vertexC.y);
// compare with previous vertex
vertexB = vertices[(vertexA.index + 1) % verticesLength];
if (normalX * (bodyAPositionX - vertexB.x) + normalY * (bodyAPositionY - vertexB.y) < nearestDistance) {
_supports[0] = vertexA;
_supports[1] = vertexB;
return _supports;
}
_supports[0] = vertexA;
_supports[1] = vertexC;
return _supports;
};
/*
*
* Properties Documentation
*
*/
/**
* A reference to the pair using this collision record, if there is one.
*
* @property pair
* @type {pair|null}
* @default null
*/
/**
* A flag that indicates if the bodies were colliding when the collision was last updated.
*
* @property collided
* @type boolean
* @default false
*/
/**
* The first body part represented by the collision (see also `collision.parentA`).
*
* @property bodyA
* @type body
*/
/**
* The second body part represented by the collision (see also `collision.parentB`).
*
* @property bodyB
* @type body
*/
/**
* The first body represented by the collision (i.e. `collision.bodyA.parent`).
*
* @property parentA
* @type body
*/
/**
* The second body represented by the collision (i.e. `collision.bodyB.parent`).
*
* @property parentB
* @type body
*/
/**
* A `Number` that represents the minimum separating distance between the bodies along the collision normal.
*
* @readOnly
* @property depth
* @type number
* @default 0
*/
/**
* A normalised `Vector` that represents the direction between the bodies that provides the minimum separating distance.
*
* @property normal
* @type vector
* @default { x: 0, y: 0 }
*/
/**
* A normalised `Vector` that is the tangent direction to the collision normal.
*
* @property tangent
* @type vector
* @default { x: 0, y: 0 }
*/
/**
* A `Vector` that represents the direction and depth of the collision.
*
* @property penetration
* @type vector
* @default { x: 0, y: 0 }
*/
/**
* An array of body vertices that represent the support points in the collision.
* These are the deepest vertices (along the collision normal) of each body that are contained by the other body's vertices.
*
* @property supports
* @type vector[]
* @default []
*/
})();

View file

@ -0,0 +1,27 @@
/**
* The `Matter.Contact` module contains methods for creating and manipulating collision contacts.
*
* @class Contact
*/
var Contact = {};
module.exports = Contact;
(function() {
/**
* Creates a new contact.
* @method create
* @param {vertex} vertex
* @return {contact} A new contact
*/
Contact.create = function(vertex) {
return {
vertex: vertex,
normalImpulse: 0,
tangentImpulse: 0
};
};
})();

View file

@ -1,84 +1,132 @@
/**
* The `Matter.Detector` module contains methods for detecting collisions given a set of pairs.
* The `Matter.Detector` module contains methods for efficiently detecting collisions between a list of bodies using a broadphase algorithm.
*
* @class Detector
*/
// TODO: speculative contacts
var Detector = {};
module.exports = Detector;
var SAT = require('./SAT');
var Pair = require('./Pair');
var Bounds = require('../geometry/Bounds');
var Common = require('../core/Common');
var Collision = require('./Collision');
(function() {
/**
* Finds all collisions given a list of pairs.
* @method collisions
* @param {pair[]} broadphasePairs
* @param {engine} engine
* @return {array} collisions
* Creates a new collision detector.
* @method create
* @param {} options
* @return {detector} A new collision detector
*/
Detector.collisions = function(broadphasePairs, engine) {
Detector.create = function(options) {
var defaults = {
bodies: [],
pairs: null
};
return Common.extend(defaults, options);
};
/**
* Sets the list of bodies in the detector.
* @method setBodies
* @param {detector} detector
* @param {body[]} bodies
*/
Detector.setBodies = function(detector, bodies) {
detector.bodies = bodies.slice(0);
};
/**
* Clears the detector including its list of bodies.
* @method clear
* @param {detector} detector
*/
Detector.clear = function(detector) {
detector.bodies = [];
};
/**
* Efficiently finds all collisions among all the bodies in `detector.bodies` using a broadphase algorithm.
*
* _Note:_ The specific ordering of collisions returned is not guaranteed between releases and may change for performance reasons.
* If a specific ordering is required then apply a sort to the resulting array.
* @method collisions
* @param {detector} detector
* @return {collision[]} collisions
*/
Detector.collisions = function(detector) {
var collisions = [],
pairsTable = engine.pairs.table;
pairs = detector.pairs,
bodies = detector.bodies,
bodiesLength = bodies.length,
canCollide = Detector.canCollide,
collides = Collision.collides,
i,
j;
// @if DEBUG
var metrics = engine.metrics;
// @endif
bodies.sort(Detector._compareBoundsX);
for (var i = 0; i < broadphasePairs.length; i++) {
var bodyA = broadphasePairs[i][0],
bodyB = broadphasePairs[i][1];
for (i = 0; i < bodiesLength; i++) {
var bodyA = bodies[i],
boundsA = bodyA.bounds,
boundXMax = bodyA.bounds.max.x,
boundYMax = bodyA.bounds.max.y,
boundYMin = bodyA.bounds.min.y,
bodyAStatic = bodyA.isStatic || bodyA.isSleeping,
partsALength = bodyA.parts.length,
partsASingle = partsALength === 1;
if ((bodyA.isStatic || bodyA.isSleeping) && (bodyB.isStatic || bodyB.isSleeping))
continue;
for (j = i + 1; j < bodiesLength; j++) {
var bodyB = bodies[j],
boundsB = bodyB.bounds;
if (!Detector.canCollide(bodyA.collisionFilter, bodyB.collisionFilter))
continue;
if (boundsB.min.x > boundXMax) {
break;
}
// @if DEBUG
metrics.midphaseTests += 1;
// @endif
if (boundYMax < boundsB.min.y || boundYMin > boundsB.max.y) {
continue;
}
// mid phase
if (Bounds.overlaps(bodyA.bounds, bodyB.bounds)) {
for (var j = bodyA.parts.length > 1 ? 1 : 0; j < bodyA.parts.length; j++) {
var partA = bodyA.parts[j];
if (bodyAStatic && (bodyB.isStatic || bodyB.isSleeping)) {
continue;
}
for (var k = bodyB.parts.length > 1 ? 1 : 0; k < bodyB.parts.length; k++) {
var partB = bodyB.parts[k];
if (!canCollide(bodyA.collisionFilter, bodyB.collisionFilter)) {
continue;
}
if ((partA === bodyA && partB === bodyB) || Bounds.overlaps(partA.bounds, partB.bounds)) {
// find a previous collision we could reuse
var pairId = Pair.id(partA, partB),
pair = pairsTable[pairId],
previousCollision;
var partsBLength = bodyB.parts.length;
if (pair && pair.isActive) {
previousCollision = pair.collision;
} else {
previousCollision = null;
if (partsASingle && partsBLength === 1) {
var collision = collides(bodyA, bodyB, pairs);
if (collision) {
collisions.push(collision);
}
} else {
var partsAStart = partsALength > 1 ? 1 : 0,
partsBStart = partsBLength > 1 ? 1 : 0;
for (var k = partsAStart; k < partsALength; k++) {
var partA = bodyA.parts[k],
boundsA = partA.bounds;
for (var z = partsBStart; z < partsBLength; z++) {
var partB = bodyB.parts[z],
boundsB = partB.bounds;
if (boundsA.min.x > boundsB.max.x || boundsA.max.x < boundsB.min.x
|| boundsA.max.y < boundsB.min.y || boundsA.min.y > boundsB.max.y) {
continue;
}
// narrow phase
var collision = SAT.collides(partA, partB, previousCollision);
var collision = collides(partA, partB, pairs);
// @if DEBUG
metrics.narrowphaseTests += 1;
if (collision.reused)
metrics.narrowReuseCount += 1;
// @endif
if (collision.collided) {
if (collision) {
collisions.push(collision);
// @if DEBUG
metrics.narrowDetections += 1;
// @endif
}
}
}
@ -104,4 +152,39 @@ var Bounds = require('../geometry/Bounds');
return (filterA.mask & filterB.category) !== 0 && (filterB.mask & filterA.category) !== 0;
};
/**
* The comparison function used in the broadphase algorithm.
* Returns the signed delta of the bodies bounds on the x-axis.
* @private
* @method _sortCompare
* @param {body} bodyA
* @param {body} bodyB
* @return {number} The signed delta used for sorting
*/
Detector._compareBoundsX = function(bodyA, bodyB) {
return bodyA.bounds.min.x - bodyB.bounds.min.x;
};
/*
*
* Properties Documentation
*
*/
/**
* The array of `Matter.Body` between which the detector finds collisions.
*
* _Note:_ The order of bodies in this array _is not fixed_ and will be continually managed by the detector.
* @property bodies
* @type body[]
* @default []
*/
/**
* Optional. A `Matter.Pairs` object from which previous collision objects may be reused. Intended for internal `Matter.Engine` usage.
* @property pairs
* @type {pairs|null}
* @default null
*/
})();

View file

@ -1,7 +1,13 @@
/**
* This module has now been replaced by `Matter.Detector`.
*
* All usage should be migrated to `Matter.Detector` or another alternative.
* For back-compatibility purposes this module will remain for a short term and then later removed in a future release.
*
* The `Matter.Grid` module contains methods for creating and manipulating collision broadphase grid structures.
*
* @class Grid
* @deprecated
*/
var Grid = {};
@ -9,21 +15,20 @@ var Grid = {};
module.exports = Grid;
var Pair = require('./Pair');
var Detector = require('./Detector');
var Common = require('../core/Common');
var deprecated = Common.deprecated;
(function() {
/**
* Creates a new grid.
* @deprecated replaced by Matter.Detector
* @method create
* @param {} options
* @return {grid} A new grid
*/
Grid.create = function(options) {
var defaults = {
controller: Grid,
detector: Detector.collisions,
buckets: {},
pairs: {},
pairsList: [],
@ -52,6 +57,7 @@ var Common = require('../core/Common');
/**
* Updates the grid.
* @deprecated replaced by Matter.Detector
* @method update
* @param {grid} grid
* @param {body[]} bodies
@ -66,20 +72,15 @@ var Common = require('../core/Common');
bucketId,
gridChanged = false;
// @if DEBUG
var metrics = engine.metrics;
metrics.broadphaseTests = 0;
// @endif
for (i = 0; i < bodies.length; i++) {
var body = bodies[i];
if (body.isSleeping && !forceUpdate)
continue;
// don't update out of world bodies
if (body.bounds.max.x < world.bounds.min.x || body.bounds.min.x > world.bounds.max.x
|| body.bounds.max.y < world.bounds.min.y || body.bounds.min.y > world.bounds.max.y)
// temporary back compatibility bounds check
if (world.bounds && (body.bounds.max.x < world.bounds.min.x || body.bounds.min.x > world.bounds.max.x
|| body.bounds.max.y < world.bounds.min.y || body.bounds.min.y > world.bounds.max.y))
continue;
var newRegion = Grid._getRegion(grid, body);
@ -87,10 +88,6 @@ var Common = require('../core/Common');
// if the body has changed grid region
if (!body.region || newRegion.id !== body.region.id || forceUpdate) {
// @if DEBUG
metrics.broadphaseTests += 1;
// @endif
if (!body.region || forceUpdate)
body.region = newRegion;
@ -139,8 +136,11 @@ var Common = require('../core/Common');
grid.pairsList = Grid._createActivePairsList(grid);
};
deprecated(Grid, 'update', 'Grid.update ➤ replaced by Matter.Detector');
/**
* Clears the grid.
* @deprecated replaced by Matter.Detector
* @method clear
* @param {grid} grid
*/
@ -150,9 +150,12 @@ var Common = require('../core/Common');
grid.pairsList = [];
};
deprecated(Grid, 'clear', 'Grid.clear ➤ replaced by Matter.Detector');
/**
* Finds the union of two regions.
* @method _regionUnion
* @deprecated replaced by Matter.Detector
* @private
* @param {} regionA
* @param {} regionB
@ -170,6 +173,7 @@ var Common = require('../core/Common');
/**
* Gets the region a given body falls in for a given grid.
* @method _getRegion
* @deprecated replaced by Matter.Detector
* @private
* @param {} grid
* @param {} body
@ -188,6 +192,7 @@ var Common = require('../core/Common');
/**
* Creates a region.
* @method _createRegion
* @deprecated replaced by Matter.Detector
* @private
* @param {} startCol
* @param {} endCol
@ -208,6 +213,7 @@ var Common = require('../core/Common');
/**
* Gets the bucket id at the given position.
* @method _getBucketId
* @deprecated replaced by Matter.Detector
* @private
* @param {} column
* @param {} row
@ -220,6 +226,7 @@ var Common = require('../core/Common');
/**
* Creates a bucket.
* @method _createBucket
* @deprecated replaced by Matter.Detector
* @private
* @param {} buckets
* @param {} bucketId
@ -233,14 +240,20 @@ var Common = require('../core/Common');
/**
* Adds a body to a bucket.
* @method _bucketAddBody
* @deprecated replaced by Matter.Detector
* @private
* @param {} grid
* @param {} bucket
* @param {} body
*/
Grid._bucketAddBody = function(grid, bucket, body) {
var gridPairs = grid.pairs,
pairId = Pair.id,
bucketLength = bucket.length,
i;
// add new pairs
for (var i = 0; i < bucket.length; i++) {
for (i = 0; i < bucketLength; i++) {
var bodyB = bucket[i];
if (body.id === bodyB.id || (body.isStatic && bodyB.isStatic))
@ -248,13 +261,13 @@ var Common = require('../core/Common');
// keep track of the number of buckets the pair exists in
// important for Grid.update to work
var pairId = Pair.id(body, bodyB),
pair = grid.pairs[pairId];
var id = pairId(body, bodyB),
pair = gridPairs[id];
if (pair) {
pair[2] += 1;
} else {
grid.pairs[pairId] = [body, bodyB, 1];
gridPairs[id] = [body, bodyB, 1];
}
}
@ -265,22 +278,27 @@ var Common = require('../core/Common');
/**
* Removes a body from a bucket.
* @method _bucketRemoveBody
* @deprecated replaced by Matter.Detector
* @private
* @param {} grid
* @param {} bucket
* @param {} body
*/
Grid._bucketRemoveBody = function(grid, bucket, body) {
var gridPairs = grid.pairs,
pairId = Pair.id,
i;
// remove from bucket
bucket.splice(bucket.indexOf(body), 1);
bucket.splice(Common.indexOf(bucket, body), 1);
var bucketLength = bucket.length;
// update pair counts
for (var i = 0; i < bucket.length; i++) {
for (i = 0; i < bucketLength; i++) {
// keep track of the number of buckets the pair exists in
// important for _createActivePairsList to work
var bodyB = bucket[i],
pairId = Pair.id(body, bodyB),
pair = grid.pairs[pairId];
var pair = gridPairs[pairId(body, bucket[i])];
if (pair)
pair[2] -= 1;
@ -290,28 +308,29 @@ var Common = require('../core/Common');
/**
* Generates a list of the active pairs in the grid.
* @method _createActivePairsList
* @deprecated replaced by Matter.Detector
* @private
* @param {} grid
* @return [] pairs
*/
Grid._createActivePairsList = function(grid) {
var pairKeys,
pair,
pairs = [];
// grid.pairs is used as a hashmap
pairKeys = Common.keys(grid.pairs);
var pair,
gridPairs = grid.pairs,
pairKeys = Common.keys(gridPairs),
pairKeysLength = pairKeys.length,
pairs = [],
k;
// iterate over grid.pairs
for (var k = 0; k < pairKeys.length; k++) {
pair = grid.pairs[pairKeys[k]];
for (k = 0; k < pairKeysLength; k++) {
pair = gridPairs[pairKeys[k]];
// if pair exists in at least one bucket
// it is a pair that needs further collision testing so push it
if (pair[2] > 0) {
pairs.push(pair);
} else {
delete grid.pairs[pairKeys[k]];
delete gridPairs[pairKeys[k]];
}
}

View file

@ -8,6 +8,8 @@ var Pair = {};
module.exports = Pair;
var Contact = require('./Contact');
(function() {
/**
@ -25,6 +27,8 @@ module.exports = Pair;
id: Pair.id(bodyA, bodyB),
bodyA: bodyA,
bodyB: bodyB,
collision: collision,
contacts: [],
activeContacts: [],
separation: 0,
isActive: true,
@ -32,7 +36,6 @@ module.exports = Pair;
isSensor: bodyA.isSensor || bodyB.isSensor,
timeCreated: timestamp,
timeUpdated: timestamp,
collision: null,
inverseMass: 0,
friction: 0,
frictionStatic: 0,
@ -53,35 +56,36 @@ module.exports = Pair;
* @param {number} timestamp
*/
Pair.update = function(pair, collision, timestamp) {
var contacts = pair.contacts,
supports = collision.supports,
activeContacts = pair.activeContacts,
parentA = collision.parentA,
parentB = collision.parentB,
parentAVerticesLength = parentA.vertices.length;
pair.isActive = true;
pair.timeUpdated = timestamp;
pair.collision = collision;
pair.separation = collision.depth;
pair.inverseMass = parentA.inverseMass + parentB.inverseMass;
pair.friction = parentA.friction < parentB.friction ? parentA.friction : parentB.friction;
pair.frictionStatic = parentA.frictionStatic > parentB.frictionStatic ? parentA.frictionStatic : parentB.frictionStatic;
pair.restitution = parentA.restitution > parentB.restitution ? parentA.restitution : parentB.restitution;
pair.slop = parentA.slop > parentB.slop ? parentA.slop : parentB.slop;
if (collision.collided) {
var supports = collision.supports,
activeContacts = pair.activeContacts,
parentA = collision.parentA,
parentB = collision.parentB;
collision.pair = pair;
activeContacts.length = 0;
pair.inverseMass = parentA.inverseMass + parentB.inverseMass;
pair.friction = Math.min(parentA.friction, parentB.friction);
pair.frictionStatic = Math.max(parentA.frictionStatic, parentB.frictionStatic);
pair.restitution = Math.max(parentA.restitution, parentB.restitution);
pair.slop = Math.max(parentA.slop, parentB.slop);
for (var i = 0; i < supports.length; i++) {
var support = supports[i],
contactId = support.body === parentA ? support.index : parentAVerticesLength + support.index,
contact = contacts[contactId];
for (var i = 0; i < supports.length; i++) {
activeContacts[i] = supports[i].contact;
if (contact) {
activeContacts.push(contact);
} else {
activeContacts.push(contacts[contactId] = Contact.create(support));
}
// optimise array size
var supportCount = supports.length;
if (supportCount < activeContacts.length) {
activeContacts.length = supportCount;
}
pair.separation = collision.depth;
Pair.setActive(pair, true, timestamp);
} else {
if (pair.isActive === true)
Pair.setActive(pair, false, timestamp);
}
};

View file

@ -13,8 +13,6 @@ var Common = require('../core/Common');
(function() {
Pairs._pairMaxIdleLife = 1000;
/**
* Creates a new pairs structure.
* @method create
@ -40,12 +38,14 @@ var Common = require('../core/Common');
*/
Pairs.update = function(pairs, collisions, timestamp) {
var pairsList = pairs.list,
pairsListLength = pairsList.length,
pairsTable = pairs.table,
collisionsLength = collisions.length,
collisionStart = pairs.collisionStart,
collisionEnd = pairs.collisionEnd,
collisionActive = pairs.collisionActive,
collision,
pairId,
pairIndex,
pair,
i;
@ -54,90 +54,61 @@ var Common = require('../core/Common');
collisionEnd.length = 0;
collisionActive.length = 0;
for (i = 0; i < pairsList.length; i++) {
for (i = 0; i < pairsListLength; i++) {
pairsList[i].confirmedActive = false;
}
for (i = 0; i < collisions.length; i++) {
for (i = 0; i < collisionsLength; i++) {
collision = collisions[i];
pair = collision.pair;
if (collision.collided) {
pairId = Pair.id(collision.bodyA, collision.bodyB);
pair = pairsTable[pairId];
if (pair) {
// pair already exists (but may or may not be active)
if (pair.isActive) {
// pair exists and is active
collisionActive.push(pair);
} else {
// pair exists but was inactive, so a collision has just started again
collisionStart.push(pair);
}
// update the pair
Pair.update(pair, collision, timestamp);
pair.confirmedActive = true;
if (pair) {
// pair already exists (but may or may not be active)
if (pair.isActive) {
// pair exists and is active
collisionActive.push(pair);
} else {
// pair did not exist, create a new pair
pair = Pair.create(collision, timestamp);
pairsTable[pairId] = pair;
// push the new pair
// pair exists but was inactive, so a collision has just started again
collisionStart.push(pair);
pairsList.push(pair);
}
// update the pair
Pair.update(pair, collision, timestamp);
pair.confirmedActive = true;
} else {
// pair did not exist, create a new pair
pair = Pair.create(collision, timestamp);
pairsTable[pair.id] = pair;
// push the new pair
collisionStart.push(pair);
pairsList.push(pair);
}
}
// find pairs that are no longer active
var removePairIndex = [];
pairsListLength = pairsList.length;
for (i = 0; i < pairsListLength; i++) {
pair = pairsList[i];
if (!pair.confirmedActive) {
Pair.setActive(pair, false, timestamp);
collisionEnd.push(pair);
if (!pair.collision.bodyA.isSleeping && !pair.collision.bodyB.isSleeping) {
removePairIndex.push(i);
}
}
}
// deactivate previously active pairs that are now inactive
for (i = 0; i < pairsList.length; i++) {
pair = pairsList[i];
if (pair.isActive && !pair.confirmedActive) {
Pair.setActive(pair, false, timestamp);
collisionEnd.push(pair);
}
}
};
/**
* Finds and removes pairs that have been inactive for a set amount of time.
* @method removeOld
* @param {object} pairs
* @param {number} timestamp
*/
Pairs.removeOld = function(pairs, timestamp) {
var pairsList = pairs.list,
pairsTable = pairs.table,
indexesToRemove = [],
pair,
collision,
pairIndex,
i;
for (i = 0; i < pairsList.length; i++) {
pair = pairsList[i];
collision = pair.collision;
// never remove sleeping pairs
if (collision.bodyA.isSleeping || collision.bodyB.isSleeping) {
pair.timeUpdated = timestamp;
continue;
}
// if pair is inactive for too long, mark it to be removed
if (timestamp - pair.timeUpdated > Pairs._pairMaxIdleLife) {
indexesToRemove.push(i);
}
}
// remove marked pairs
for (i = 0; i < indexesToRemove.length; i++) {
pairIndex = indexesToRemove[i] - i;
// remove inactive pairs
for (i = 0; i < removePairIndex.length; i++) {
pairIndex = removePairIndex[i] - i;
pair = pairsList[pairIndex];
delete pairsTable[pair.id];
pairsList.splice(pairIndex, 1);
delete pairsTable[pair.id];
}
};

View file

@ -11,7 +11,7 @@ var Query = {};
module.exports = Query;
var Vector = require('../geometry/Vector');
var SAT = require('./SAT');
var Collision = require('./Collision');
var Bounds = require('../geometry/Bounds');
var Bodies = require('../factory/Bodies');
var Vertices = require('../geometry/Vertices');
@ -23,13 +23,19 @@ var Vertices = require('../geometry/Vertices');
* @method collides
* @param {body} body
* @param {body[]} bodies
* @return {object[]} Collisions
* @return {collision[]} Collisions
*/
Query.collides = function(body, bodies) {
var collisions = [];
var collisions = [],
bodiesLength = bodies.length,
bounds = body.bounds,
collides = Collision.collides,
overlaps = Bounds.overlaps;
for (var i = 0; i < bodies.length; i++) {
var bodyA = bodies[i];
for (var i = 0; i < bodiesLength; i++) {
var bodyA = bodies[i],
partsALength = bodyA.parts.length,
partsAStart = partsALength === 1 ? 0 : 1;
// Phaser addition - skip same body checks
if (body === bodyA)
@ -37,14 +43,14 @@ var Vertices = require('../geometry/Vertices');
continue;
}
if (Bounds.overlaps(bodyA.bounds, body.bounds)) {
for (var j = bodyA.parts.length === 1 ? 0 : 1; j < bodyA.parts.length; j++) {
if (overlaps(bodyA.bounds, bounds)) {
for (var j = partsAStart; j < partsALength; j++) {
var part = bodyA.parts[j];
if (Bounds.overlaps(part.bounds, body.bounds)) {
var collision = SAT.collides(part, body);
if (overlaps(part.bounds, bounds)) {
var collision = collides(part, body);
if (collision.collided) {
if (collision) {
collisions.push(collision);
break;
}
@ -63,7 +69,7 @@ var Vertices = require('../geometry/Vertices');
* @param {vector} startPoint
* @param {vector} endPoint
* @param {number} [rayWidth]
* @return {object[]} Collisions
* @return {collision[]} Collisions
*/
Query.ray = function(bodies, startPoint, endPoint, rayWidth) {
rayWidth = rayWidth || 1e-100;

View file

@ -9,8 +9,6 @@ var Resolver = {};
module.exports = Resolver;
var Vertices = require('../geometry/Vertices');
var Vector = require('../geometry/Vector');
var Common = require('../core/Common');
var Bounds = require('../geometry/Bounds');
(function() {
@ -29,10 +27,11 @@ var Bounds = require('../geometry/Bounds');
Resolver.preSolvePosition = function(pairs) {
var i,
pair,
activeCount;
activeCount,
pairsLength = pairs.length;
// find total contacts on each body
for (i = 0; i < pairs.length; i++) {
for (i = 0; i < pairsLength; i++) {
pair = pairs[i];
if (!pair.isActive)
@ -48,36 +47,22 @@ var Bounds = require('../geometry/Bounds');
* Find a solution for pair positions.
* @method solvePosition
* @param {pair[]} pairs
* @param {body[]} bodies
* @param {number} timeScale
*/
Resolver.solvePosition = function(pairs, bodies, timeScale) {
Resolver.solvePosition = function(pairs, timeScale) {
var i,
normalX,
normalY,
pair,
collision,
bodyA,
bodyB,
normal,
separation,
penetration,
positionImpulseA,
positionImpulseB,
contactShare,
bodyBtoAX,
bodyBtoAY,
positionImpulse,
impulseCoefficient = timeScale * Resolver._positionDampen;
for (i = 0; i < bodies.length; i++) {
var body = bodies[i];
body.previousPositionImpulse.x = body.positionImpulse.x;
body.previousPositionImpulse.y = body.positionImpulse.y;
}
positionDampen = Resolver._positionDampen,
pairsLength = pairs.length;
// find impulses required to resolve penetration
for (i = 0; i < pairs.length; i++) {
for (i = 0; i < pairsLength; i++) {
pair = pairs[i];
if (!pair.isActive || pair.isSensor)
@ -88,35 +73,37 @@ var Bounds = require('../geometry/Bounds');
bodyB = collision.parentB;
normal = collision.normal;
positionImpulseA = bodyA.previousPositionImpulse;
positionImpulseB = bodyB.previousPositionImpulse;
// get current separation between body edges involved in collision
pair.separation =
normal.x * (bodyB.positionImpulse.x + collision.penetration.x - bodyA.positionImpulse.x)
+ normal.y * (bodyB.positionImpulse.y + collision.penetration.y - bodyA.positionImpulse.y);
}
penetration = collision.penetration;
for (i = 0; i < pairsLength; i++) {
pair = pairs[i];
bodyBtoAX = positionImpulseB.x - positionImpulseA.x + penetration.x;
bodyBtoAY = positionImpulseB.y - positionImpulseA.y + penetration.y;
if (!pair.isActive || pair.isSensor)
continue;
normalX = normal.x;
normalY = normal.y;
separation = normalX * bodyBtoAX + normalY * bodyBtoAY;
pair.separation = separation;
positionImpulse = (separation - pair.slop) * impulseCoefficient;
collision = pair.collision;
bodyA = collision.parentA;
bodyB = collision.parentB;
normal = collision.normal;
positionImpulse = (pair.separation - pair.slop) * timeScale;
if (bodyA.isStatic || bodyB.isStatic)
positionImpulse *= 2;
if (!(bodyA.isStatic || bodyA.isSleeping)) {
contactShare = positionImpulse / bodyA.totalContacts;
bodyA.positionImpulse.x += normalX * contactShare;
bodyA.positionImpulse.y += normalY * contactShare;
contactShare = positionDampen / bodyA.totalContacts;
bodyA.positionImpulse.x += normal.x * positionImpulse * contactShare;
bodyA.positionImpulse.y += normal.y * positionImpulse * contactShare;
}
if (!(bodyB.isStatic || bodyB.isSleeping)) {
contactShare = positionImpulse / bodyB.totalContacts;
bodyB.positionImpulse.x -= normalX * contactShare;
bodyB.positionImpulse.y -= normalY * contactShare;
contactShare = positionDampen / bodyB.totalContacts;
bodyB.positionImpulse.x -= normal.x * positionImpulse * contactShare;
bodyB.positionImpulse.y -= normal.y * positionImpulse * contactShare;
}
}
};
@ -127,34 +114,43 @@ var Bounds = require('../geometry/Bounds');
* @param {body[]} bodies
*/
Resolver.postSolvePosition = function(bodies) {
for (var i = 0; i < bodies.length; i++) {
var body = bodies[i];
var positionWarming = Resolver._positionWarming,
bodiesLength = bodies.length,
verticesTranslate = Vertices.translate,
boundsUpdate = Bounds.update;
for (var i = 0; i < bodiesLength; i++) {
var body = bodies[i],
positionImpulse = body.positionImpulse,
positionImpulseX = positionImpulse.x,
positionImpulseY = positionImpulse.y,
velocity = body.velocity;
// reset contact count
body.totalContacts = 0;
if (body.positionImpulse.x !== 0 || body.positionImpulse.y !== 0) {
if (positionImpulseX !== 0 || positionImpulseY !== 0) {
// update body geometry
for (var j = 0; j < body.parts.length; j++) {
var part = body.parts[j];
Vertices.translate(part.vertices, body.positionImpulse);
Bounds.update(part.bounds, part.vertices, body.velocity);
part.position.x += body.positionImpulse.x;
part.position.y += body.positionImpulse.y;
verticesTranslate(part.vertices, positionImpulse);
boundsUpdate(part.bounds, part.vertices, velocity);
part.position.x += positionImpulseX;
part.position.y += positionImpulseY;
}
// move the body without changing velocity
body.positionPrev.x += body.positionImpulse.x;
body.positionPrev.y += body.positionImpulse.y;
body.positionPrev.x += positionImpulseX;
body.positionPrev.y += positionImpulseY;
if (Vector.dot(body.positionImpulse, body.velocity) < 0) {
if (positionImpulseX * velocity.x + positionImpulseY * velocity.y < 0) {
// reset cached impulse if the body has velocity along it
body.positionImpulse.x = 0;
body.positionImpulse.y = 0;
positionImpulse.x = 0;
positionImpulse.y = 0;
} else {
// warm the next iteration
body.positionImpulse.x *= Resolver._positionWarming;
body.positionImpulse.y *= Resolver._positionWarming;
positionImpulse.x *= positionWarming;
positionImpulse.y *= positionWarming;
}
}
}
@ -166,61 +162,53 @@ var Bounds = require('../geometry/Bounds');
* @param {pair[]} pairs
*/
Resolver.preSolveVelocity = function(pairs) {
var i,
j,
pair,
contacts,
collision,
bodyA,
bodyB,
normal,
tangent,
contact,
contactVertex,
normalImpulse,
tangentImpulse,
offset,
impulse = Vector._temp[0],
tempA = Vector._temp[1];
var pairsLength = pairs.length,
i,
j;
for (i = 0; i < pairs.length; i++) {
pair = pairs[i];
for (i = 0; i < pairsLength; i++) {
var pair = pairs[i];
if (!pair.isActive || pair.isSensor)
continue;
contacts = pair.activeContacts;
collision = pair.collision;
bodyA = collision.parentA;
bodyB = collision.parentB;
normal = collision.normal;
tangent = collision.tangent;
var contacts = pair.activeContacts,
contactsLength = contacts.length,
collision = pair.collision,
bodyA = collision.parentA,
bodyB = collision.parentB,
normal = collision.normal,
tangent = collision.tangent;
// resolve each contact
for (j = 0; j < contacts.length; j++) {
contact = contacts[j];
contactVertex = contact.vertex;
normalImpulse = contact.normalImpulse;
tangentImpulse = contact.tangentImpulse;
for (j = 0; j < contactsLength; j++) {
var contact = contacts[j],
contactVertex = contact.vertex,
normalImpulse = contact.normalImpulse,
tangentImpulse = contact.tangentImpulse;
if (normalImpulse !== 0 || tangentImpulse !== 0) {
// total impulse from contact
impulse.x = (normal.x * normalImpulse) + (tangent.x * tangentImpulse);
impulse.y = (normal.y * normalImpulse) + (tangent.y * tangentImpulse);
var impulseX = normal.x * normalImpulse + tangent.x * tangentImpulse,
impulseY = normal.y * normalImpulse + tangent.y * tangentImpulse;
// apply impulse from contact
if (!(bodyA.isStatic || bodyA.isSleeping)) {
offset = Vector.sub(contactVertex, bodyA.position, tempA);
bodyA.positionPrev.x += impulse.x * bodyA.inverseMass;
bodyA.positionPrev.y += impulse.y * bodyA.inverseMass;
bodyA.anglePrev += Vector.cross(offset, impulse) * bodyA.inverseInertia;
bodyA.positionPrev.x += impulseX * bodyA.inverseMass;
bodyA.positionPrev.y += impulseY * bodyA.inverseMass;
bodyA.anglePrev += bodyA.inverseInertia * (
(contactVertex.x - bodyA.position.x) * impulseY
- (contactVertex.y - bodyA.position.y) * impulseX
);
}
if (!(bodyB.isStatic || bodyB.isSleeping)) {
offset = Vector.sub(contactVertex, bodyB.position, tempA);
bodyB.positionPrev.x -= impulse.x * bodyB.inverseMass;
bodyB.positionPrev.y -= impulse.y * bodyB.inverseMass;
bodyB.anglePrev -= Vector.cross(offset, impulse) * bodyB.inverseInertia;
bodyB.positionPrev.x -= impulseX * bodyB.inverseMass;
bodyB.positionPrev.y -= impulseY * bodyB.inverseMass;
bodyB.anglePrev -= bodyB.inverseInertia * (
(contactVertex.x - bodyB.position.x) * impulseY
- (contactVertex.y - bodyB.position.y) * impulseX
);
}
}
}
@ -235,14 +223,17 @@ var Bounds = require('../geometry/Bounds');
*/
Resolver.solveVelocity = function(pairs, timeScale) {
var timeScaleSquared = timeScale * timeScale,
impulse = Vector._temp[0],
tempA = Vector._temp[1],
tempB = Vector._temp[2],
tempC = Vector._temp[3],
tempD = Vector._temp[4],
tempE = Vector._temp[5];
restingThresh = Resolver._restingThresh * timeScaleSquared,
frictionNormalMultiplier = Resolver._frictionNormalMultiplier,
restingThreshTangent = Resolver._restingThreshTangent * timeScaleSquared,
NumberMaxValue = Number.MAX_VALUE,
pairsLength = pairs.length,
tangentImpulse,
maxFriction,
i,
j;
for (var i = 0; i < pairs.length; i++) {
for (i = 0; i < pairsLength; i++) {
var pair = pairs[i];
if (!pair.isActive || pair.isSensor)
@ -251,97 +242,119 @@ var Bounds = require('../geometry/Bounds');
var collision = pair.collision,
bodyA = collision.parentA,
bodyB = collision.parentB,
normal = collision.normal,
tangent = collision.tangent,
bodyAVelocity = bodyA.velocity,
bodyBVelocity = bodyB.velocity,
normalX = collision.normal.x,
normalY = collision.normal.y,
tangentX = collision.tangent.x,
tangentY = collision.tangent.y,
contacts = pair.activeContacts,
contactShare = 1 / contacts.length;
contactsLength = contacts.length,
contactShare = 1 / contactsLength,
inverseMassTotal = bodyA.inverseMass + bodyB.inverseMass,
friction = pair.friction * pair.frictionStatic * frictionNormalMultiplier * timeScaleSquared;
// update body velocities
bodyA.velocity.x = bodyA.position.x - bodyA.positionPrev.x;
bodyA.velocity.y = bodyA.position.y - bodyA.positionPrev.y;
bodyB.velocity.x = bodyB.position.x - bodyB.positionPrev.x;
bodyB.velocity.y = bodyB.position.y - bodyB.positionPrev.y;
bodyAVelocity.x = bodyA.position.x - bodyA.positionPrev.x;
bodyAVelocity.y = bodyA.position.y - bodyA.positionPrev.y;
bodyBVelocity.x = bodyB.position.x - bodyB.positionPrev.x;
bodyBVelocity.y = bodyB.position.y - bodyB.positionPrev.y;
bodyA.angularVelocity = bodyA.angle - bodyA.anglePrev;
bodyB.angularVelocity = bodyB.angle - bodyB.anglePrev;
// resolve each contact
for (var j = 0; j < contacts.length; j++) {
for (j = 0; j < contactsLength; j++) {
var contact = contacts[j],
contactVertex = contact.vertex,
offsetA = Vector.sub(contactVertex, bodyA.position, tempA),
offsetB = Vector.sub(contactVertex, bodyB.position, tempB),
velocityPointA = Vector.add(bodyA.velocity, Vector.mult(Vector.perp(offsetA), bodyA.angularVelocity), tempC),
velocityPointB = Vector.add(bodyB.velocity, Vector.mult(Vector.perp(offsetB), bodyB.angularVelocity), tempD),
relativeVelocity = Vector.sub(velocityPointA, velocityPointB, tempE),
normalVelocity = Vector.dot(normal, relativeVelocity);
contactVertex = contact.vertex;
var tangentVelocity = Vector.dot(tangent, relativeVelocity),
tangentSpeed = Math.abs(tangentVelocity),
tangentVelocityDirection = Common.sign(tangentVelocity);
var offsetAX = contactVertex.x - bodyA.position.x,
offsetAY = contactVertex.y - bodyA.position.y,
offsetBX = contactVertex.x - bodyB.position.x,
offsetBY = contactVertex.y - bodyB.position.y;
// raw impulses
var normalImpulse = (1 + pair.restitution) * normalVelocity,
normalForce = Common.clamp(pair.separation + normalVelocity, 0, 1) * Resolver._frictionNormalMultiplier;
var velocityPointAX = bodyAVelocity.x - offsetAY * bodyA.angularVelocity,
velocityPointAY = bodyAVelocity.y + offsetAX * bodyA.angularVelocity,
velocityPointBX = bodyBVelocity.x - offsetBY * bodyB.angularVelocity,
velocityPointBY = bodyBVelocity.y + offsetBX * bodyB.angularVelocity;
var relativeVelocityX = velocityPointAX - velocityPointBX,
relativeVelocityY = velocityPointAY - velocityPointBY;
var normalVelocity = normalX * relativeVelocityX + normalY * relativeVelocityY,
tangentVelocity = tangentX * relativeVelocityX + tangentY * relativeVelocityY;
// coulomb friction
var tangentImpulse = tangentVelocity,
maxFriction = Infinity;
var normalOverlap = pair.separation + normalVelocity;
var normalForce = Math.min(normalOverlap, 1);
normalForce = normalOverlap < 0 ? 0 : normalForce;
if (tangentSpeed > pair.friction * pair.frictionStatic * normalForce * timeScaleSquared) {
maxFriction = tangentSpeed;
tangentImpulse = Common.clamp(
pair.friction * tangentVelocityDirection * timeScaleSquared,
-maxFriction, maxFriction
);
var frictionLimit = normalForce * friction;
if (tangentVelocity > frictionLimit || -tangentVelocity > frictionLimit) {
maxFriction = tangentVelocity > 0 ? tangentVelocity : -tangentVelocity;
tangentImpulse = pair.friction * (tangentVelocity > 0 ? 1 : -1) * timeScaleSquared;
if (tangentImpulse < -maxFriction) {
tangentImpulse = -maxFriction;
} else if (tangentImpulse > maxFriction) {
tangentImpulse = maxFriction;
}
} else {
tangentImpulse = tangentVelocity;
maxFriction = NumberMaxValue;
}
// modify impulses accounting for mass, inertia and offset
var oAcN = Vector.cross(offsetA, normal),
oBcN = Vector.cross(offsetB, normal),
share = contactShare / (bodyA.inverseMass + bodyB.inverseMass + bodyA.inverseInertia * oAcN * oAcN + bodyB.inverseInertia * oBcN * oBcN);
// account for mass, inertia and contact offset
var oAcN = offsetAX * normalY - offsetAY * normalX,
oBcN = offsetBX * normalY - offsetBY * normalX,
share = contactShare / (inverseMassTotal + bodyA.inverseInertia * oAcN * oAcN + bodyB.inverseInertia * oBcN * oBcN);
normalImpulse *= share;
// raw impulses
var normalImpulse = (1 + pair.restitution) * normalVelocity * share;
tangentImpulse *= share;
// handle high velocity and resting collisions separately
if (normalVelocity < 0 && normalVelocity * normalVelocity > Resolver._restingThresh * timeScaleSquared) {
if (normalVelocity * normalVelocity > restingThresh && normalVelocity < 0) {
// high normal velocity so clear cached contact normal impulse
contact.normalImpulse = 0;
} else {
// solve resting collision constraints using Erin Catto's method (GDC08)
// impulse constraint tends to 0
var contactNormalImpulse = contact.normalImpulse;
contact.normalImpulse = Math.min(contact.normalImpulse + normalImpulse, 0);
contact.normalImpulse += normalImpulse;
contact.normalImpulse = Math.min(contact.normalImpulse, 0);
normalImpulse = contact.normalImpulse - contactNormalImpulse;
}
// handle high velocity and resting collisions separately
if (tangentVelocity * tangentVelocity > Resolver._restingThreshTangent * timeScaleSquared) {
if (tangentVelocity * tangentVelocity > restingThreshTangent) {
// high tangent velocity so clear cached contact tangent impulse
contact.tangentImpulse = 0;
} else {
// solve resting collision constraints using Erin Catto's method (GDC08)
// tangent impulse tends to -tangentSpeed or +tangentSpeed
var contactTangentImpulse = contact.tangentImpulse;
contact.tangentImpulse = Common.clamp(contact.tangentImpulse + tangentImpulse, -maxFriction, maxFriction);
contact.tangentImpulse += tangentImpulse;
if (contact.tangentImpulse < -maxFriction) contact.tangentImpulse = -maxFriction;
if (contact.tangentImpulse > maxFriction) contact.tangentImpulse = maxFriction;
tangentImpulse = contact.tangentImpulse - contactTangentImpulse;
}
// total impulse from contact
impulse.x = (normal.x * normalImpulse) + (tangent.x * tangentImpulse);
impulse.y = (normal.y * normalImpulse) + (tangent.y * tangentImpulse);
var impulseX = normalX * normalImpulse + tangentX * tangentImpulse,
impulseY = normalY * normalImpulse + tangentY * tangentImpulse;
// apply impulse from contact
if (!(bodyA.isStatic || bodyA.isSleeping)) {
bodyA.positionPrev.x += impulse.x * bodyA.inverseMass;
bodyA.positionPrev.y += impulse.y * bodyA.inverseMass;
bodyA.anglePrev += Vector.cross(offsetA, impulse) * bodyA.inverseInertia;
bodyA.positionPrev.x += impulseX * bodyA.inverseMass;
bodyA.positionPrev.y += impulseY * bodyA.inverseMass;
bodyA.anglePrev += (offsetAX * impulseY - offsetAY * impulseX) * bodyA.inverseInertia;
}
if (!(bodyB.isStatic || bodyB.isSleeping)) {
bodyB.positionPrev.x -= impulse.x * bodyB.inverseMass;
bodyB.positionPrev.y -= impulse.y * bodyB.inverseMass;
bodyB.anglePrev -= Vector.cross(offsetB, impulse) * bodyB.inverseInertia;
bodyB.positionPrev.x -= impulseX * bodyB.inverseMass;
bodyB.positionPrev.y -= impulseY * bodyB.inverseMass;
bodyB.anglePrev -= (offsetBX * impulseY - offsetBY * impulseX) * bodyB.inverseInertia;
}
}
}

View file

@ -1,270 +1,37 @@
/**
* This module has now been replaced by `Matter.Collision`.
*
* All usage should be migrated to `Matter.Collision`.
* For back-compatibility purposes this module will remain for a short term and then later removed in a future release.
*
* The `Matter.SAT` module contains methods for detecting collisions using the Separating Axis Theorem.
*
* @class SAT
* @deprecated
*/
// TODO: true circles and curves
var SAT = {};
module.exports = SAT;
var Vertices = require('../geometry/Vertices');
var Vector = require('../geometry/Vector');
var Collision = require('./Collision');
var Common = require('../core/Common');
var deprecated = Common.deprecated;
(function() {
/**
* Detect collision between two bodies using the Separating Axis Theorem.
* @deprecated replaced by Collision.collides
* @method collides
* @param {body} bodyA
* @param {body} bodyB
* @param {collision} previousCollision
* @return {collision} collision
*/
SAT.collides = function(bodyA, bodyB, previousCollision) {
var overlapAB,
overlapBA,
minOverlap,
collision,
canReusePrevCol = false;
if (previousCollision) {
// estimate total motion
var parentA = bodyA.parent,
parentB = bodyB.parent,
motion = parentA.speed * parentA.speed + parentA.angularSpeed * parentA.angularSpeed
+ parentB.speed * parentB.speed + parentB.angularSpeed * parentB.angularSpeed;
// we may be able to (partially) reuse collision result
// but only safe if collision was resting
canReusePrevCol = previousCollision && previousCollision.collided && motion < 0.2;
// reuse collision object
collision = previousCollision;
} else {
collision = { collided: false, bodyA: bodyA, bodyB: bodyB };
}
if (previousCollision && canReusePrevCol) {
// if we can reuse the collision result
// we only need to test the previously found axis
var axisBodyA = collision.axisBody,
axisBodyB = axisBodyA === bodyA ? bodyB : bodyA,
axes = [axisBodyA.axes[previousCollision.axisNumber]];
minOverlap = SAT._overlapAxes(axisBodyA.vertices, axisBodyB.vertices, axes);
collision.reused = true;
if (minOverlap.overlap <= 0) {
collision.collided = false;
return collision;
}
} else {
// if we can't reuse a result, perform a full SAT test
overlapAB = SAT._overlapAxes(bodyA.vertices, bodyB.vertices, bodyA.axes);
if (overlapAB.overlap <= 0) {
collision.collided = false;
return collision;
}
overlapBA = SAT._overlapAxes(bodyB.vertices, bodyA.vertices, bodyB.axes);
if (overlapBA.overlap <= 0) {
collision.collided = false;
return collision;
}
if (overlapAB.overlap < overlapBA.overlap) {
minOverlap = overlapAB;
collision.axisBody = bodyA;
} else {
minOverlap = overlapBA;
collision.axisBody = bodyB;
}
// important for reuse later
collision.axisNumber = minOverlap.axisNumber;
}
collision.bodyA = bodyA.id < bodyB.id ? bodyA : bodyB;
collision.bodyB = bodyA.id < bodyB.id ? bodyB : bodyA;
collision.collided = true;
collision.depth = minOverlap.overlap;
collision.parentA = collision.bodyA.parent;
collision.parentB = collision.bodyB.parent;
bodyA = collision.bodyA;
bodyB = collision.bodyB;
// ensure normal is facing away from bodyA
if (Vector.dot(minOverlap.axis, Vector.sub(bodyB.position, bodyA.position)) < 0) {
collision.normal = {
x: minOverlap.axis.x,
y: minOverlap.axis.y
};
} else {
collision.normal = {
x: -minOverlap.axis.x,
y: -minOverlap.axis.y
};
}
collision.tangent = Vector.perp(collision.normal);
collision.penetration = collision.penetration || {};
collision.penetration.x = collision.normal.x * collision.depth;
collision.penetration.y = collision.normal.y * collision.depth;
// find support points, there is always either exactly one or two
var verticesB = SAT._findSupports(bodyA, bodyB, collision.normal),
supports = [];
// find the supports from bodyB that are inside bodyA
if (Vertices.contains(bodyA.vertices, verticesB[0]))
supports.push(verticesB[0]);
if (Vertices.contains(bodyA.vertices, verticesB[1]))
supports.push(verticesB[1]);
// find the supports from bodyA that are inside bodyB
if (supports.length < 2) {
var verticesA = SAT._findSupports(bodyB, bodyA, Vector.neg(collision.normal));
if (Vertices.contains(bodyB.vertices, verticesA[0]))
supports.push(verticesA[0]);
if (supports.length < 2 && Vertices.contains(bodyB.vertices, verticesA[1]))
supports.push(verticesA[1]);
}
// account for the edge case of overlapping but no vertex containment
if (supports.length < 1)
supports = [verticesB[0]];
collision.supports = supports;
return collision;
SAT.collides = function(bodyA, bodyB) {
return Collision.collides(bodyA, bodyB);
};
/**
* Find the overlap between two sets of vertices.
* @method _overlapAxes
* @private
* @param {} verticesA
* @param {} verticesB
* @param {} axes
* @return result
*/
SAT._overlapAxes = function(verticesA, verticesB, axes) {
var projectionA = Vector._temp[0],
projectionB = Vector._temp[1],
result = { overlap: Number.MAX_VALUE },
overlap,
axis;
for (var i = 0; i < axes.length; i++) {
axis = axes[i];
SAT._projectToAxis(projectionA, verticesA, axis);
SAT._projectToAxis(projectionB, verticesB, axis);
overlap = Math.min(projectionA.max - projectionB.min, projectionB.max - projectionA.min);
if (overlap <= 0) {
result.overlap = overlap;
return result;
}
if (overlap < result.overlap) {
result.overlap = overlap;
result.axis = axis;
result.axisNumber = i;
}
}
return result;
};
/**
* Projects vertices on an axis and returns an interval.
* @method _projectToAxis
* @private
* @param {} projection
* @param {} vertices
* @param {} axis
*/
SAT._projectToAxis = function(projection, vertices, axis) {
var min = Vector.dot(vertices[0], axis),
max = min;
for (var i = 1; i < vertices.length; i += 1) {
var dot = Vector.dot(vertices[i], axis);
if (dot > max) {
max = dot;
} else if (dot < min) {
min = dot;
}
}
projection.min = min;
projection.max = max;
};
/**
* Finds supporting vertices given two bodies along a given direction using hill-climbing.
* @method _findSupports
* @private
* @param {} bodyA
* @param {} bodyB
* @param {} normal
* @return [vector]
*/
SAT._findSupports = function(bodyA, bodyB, normal) {
var nearestDistance = Number.MAX_VALUE,
vertexToBody = Vector._temp[0],
vertices = bodyB.vertices,
bodyAPosition = bodyA.position,
distance,
vertex,
vertexA,
vertexB;
// find closest vertex on bodyB
for (var i = 0; i < vertices.length; i++) {
vertex = vertices[i];
vertexToBody.x = vertex.x - bodyAPosition.x;
vertexToBody.y = vertex.y - bodyAPosition.y;
distance = -Vector.dot(normal, vertexToBody);
if (distance < nearestDistance) {
nearestDistance = distance;
vertexA = vertex;
}
}
// find next closest vertex using the two connected to it
var prevIndex = vertexA.index - 1 >= 0 ? vertexA.index - 1 : vertices.length - 1;
vertex = vertices[prevIndex];
vertexToBody.x = vertex.x - bodyAPosition.x;
vertexToBody.y = vertex.y - bodyAPosition.y;
nearestDistance = -Vector.dot(normal, vertexToBody);
vertexB = vertex;
var nextIndex = (vertexA.index + 1) % vertices.length;
vertex = vertices[nextIndex];
vertexToBody.x = vertex.x - bodyAPosition.x;
vertexToBody.y = vertex.y - bodyAPosition.y;
distance = -Vector.dot(normal, vertexToBody);
if (distance < nearestDistance) {
vertexB = vertex;
}
return [vertexA, vertexB];
};
deprecated(SAT, 'collides', 'SAT.collides ➤ replaced by Collision.collides');
})();

View file

@ -312,8 +312,10 @@ var Common = require('../core/Common');
*/
Constraint.pointAWorld = function(constraint) {
return {
x: (constraint.bodyA ? constraint.bodyA.position.x : 0) + constraint.pointA.x,
y: (constraint.bodyA ? constraint.bodyA.position.y : 0) + constraint.pointA.y
x: (constraint.bodyA ? constraint.bodyA.position.x : 0)
+ (constraint.pointA ? constraint.pointA.x : 0),
y: (constraint.bodyA ? constraint.bodyA.position.y : 0)
+ (constraint.pointA ? constraint.pointA.y : 0)
};
};
@ -325,8 +327,10 @@ var Common = require('../core/Common');
*/
Constraint.pointBWorld = function(constraint) {
return {
x: (constraint.bodyB ? constraint.bodyB.position.x : 0) + constraint.pointB.x,
y: (constraint.bodyB ? constraint.bodyB.position.y : 0) + constraint.pointB.y
x: (constraint.bodyB ? constraint.bodyB.position.x : 0)
+ (constraint.pointB ? constraint.pointB.x : 0),
y: (constraint.bodyB ? constraint.bodyB.position.y : 0)
+ (constraint.pointB ? constraint.pointB.y : 0)
};
};

View file

@ -13,6 +13,8 @@ module.exports = Common;
Common._nextId = 0;
Common._seed = 0;
Common._nowStartTime = +(new Date());
Common._warnedOnce = {};
Common._decomp = null;
/**
* Extends the object in the first argument using the object in the second argument.
@ -221,7 +223,7 @@ module.exports = Common;
* @return {boolean} True if the object is a string, otherwise false
*/
Common.isString = function(obj) {
return Object.prototype.toString.call(obj) === '[object String]';
return toString.call(obj) === '[object String]';
};
/**
@ -252,9 +254,9 @@ module.exports = Common;
/**
* Returns the current timestamp since the time origin (e.g. from page load).
* The result will be high-resolution including decimal places if available.
* The result is in milliseconds and will use high-resolution timing if available.
* @method now
* @return {number} the current timestamp
* @return {number} the current timestamp in milliseconds
*/
Common.now = function() {
if (typeof window !== 'undefined' && window.performance) {
@ -265,6 +267,10 @@ module.exports = Common;
}
}
if (Date.now) {
return Date.now();
}
return (new Date()) - Common._nowStartTime;
};
@ -358,6 +364,35 @@ module.exports = Common;
}
};
/**
* Uses `Common.warn` to log the given message one time only.
* @method warnOnce
* @param ...objs {} The objects to log.
*/
Common.warnOnce = function() {
var message = Array.prototype.slice.call(arguments).join(' ');
if (!Common._warnedOnce[message]) {
Common.warn(message);
Common._warnedOnce[message] = true;
}
};
/**
* Shows a deprecated console warning when the function on the given object is called.
* The target function will be replaced with a new function that first shows the warning
* and then calls the original function.
* @method deprecated
* @param {object} obj The object or module
* @param {string} name The property name of the function on obj
* @param {string} warning The one-time message to show if the function is called
*/
Common.deprecated = function(obj, prop, warning) {
obj[prop] = Common.chain(function() {
Common.warnOnce('🔅 deprecated 🔅', warning);
}, obj[prop]);
};
/**
* Returns the next unique sequential ID.
* @method nextId
@ -535,4 +570,42 @@ module.exports = Common;
func
));
};
/**
* Provide the [poly-decomp](https://github.com/schteppe/poly-decomp.js) library module to enable
* concave vertex decomposition support when using `Bodies.fromVertices` e.g. `Common.setDecomp(require('poly-decomp'))`.
* @method setDecomp
* @param {} decomp The [poly-decomp](https://github.com/schteppe/poly-decomp.js) library module.
*/
Common.setDecomp = function(decomp) {
Common._decomp = decomp;
};
/**
* Returns the [poly-decomp](https://github.com/schteppe/poly-decomp.js) library module provided through `Common.setDecomp`,
* otherwise returns the global `decomp` if set.
* @method getDecomp
* @return {} The [poly-decomp](https://github.com/schteppe/poly-decomp.js) library module if provided.
*/
Common.getDecomp = function() {
// get user provided decomp if set
var decomp = Common._decomp;
try {
// otherwise from window global
if (!decomp && typeof window !== 'undefined') {
decomp = window.decomp;
}
// otherwise from node global
if (!decomp && typeof global !== 'undefined') {
decomp = global.decomp;
}
} catch (e) {
// decomp not available
decomp = null;
}
return decomp;
};
})();

View file

@ -12,12 +12,10 @@ var Engine = {};
module.exports = Engine;
var World = require('../body/World');
var Sleeping = require('./Sleeping');
var Resolver = require('../collision/Resolver');
var Detector = require('../collision/Detector');
var Pairs = require('../collision/Pairs');
var Metrics = require('./Metrics');
var Grid = require('../collision/Grid');
var Events = require('./Events');
var Composite = require('../body/Composite');
var Constraint = require('../constraint/Constraint');
@ -34,16 +32,9 @@ var Body = require('../body/Body');
* @param {object} [options]
* @return {engine} engine
*/
Engine.create = function(element, options) {
// options may be passed as the first (and only) argument
options = Common.isElement(element) ? options : element;
element = Common.isElement(element) ? element : null;
Engine.create = function(options) {
options = options || {};
if (element || options.render) {
Common.warn('Engine.create: engine.render is deprecated (see docs)');
}
var defaults = {
positionIterations: 6,
velocityIterations: 4,
@ -51,25 +42,30 @@ var Body = require('../body/Body');
enableSleeping: false,
events: [],
plugin: {},
gravity: {
x: 0,
y: 1,
scale: 0.001
},
timing: {
timestamp: 0,
timeScale: 1
},
broadphase: {
controller: Grid
timeScale: 1,
lastDelta: 0,
lastElapsed: 0
}
};
var engine = Common.extend(defaults, options);
engine.world = options.world || World.create(engine.world);
engine.pairs = Pairs.create();
engine.broadphase = engine.broadphase.controller.create(engine.broadphase);
engine.metrics = engine.metrics || { extended: false };
engine.world = options.world || Composite.create({ label: 'World' });
engine.pairs = options.pairs || Pairs.create();
engine.detector = options.detector || Detector.create();
// @if DEBUG
engine.metrics = Metrics.create(engine.metrics);
// @endif
// for temporary back compatibility only
engine.grid = { buckets: [] };
engine.world.gravity = engine.gravity;
engine.broadphase = engine.grid;
engine.metrics = {};
return engine;
};
@ -90,17 +86,21 @@ var Body = require('../body/Body');
* @param {number} [correction=1]
*/
Engine.update = function(engine, delta, correction) {
var startTime = Common.now();
delta = delta || 1000 / 60;
correction = correction || 1;
var world = engine.world,
detector = engine.detector,
pairs = engine.pairs,
timing = engine.timing,
broadphase = engine.broadphase,
broadphasePairs = [],
timestamp = timing.timestamp,
i;
// increment timestamp
timing.timestamp += delta * timing.timeScale;
timing.lastDelta = delta * timing.timeScale;
// create an event object
var event = {
@ -109,21 +109,26 @@ var Body = require('../body/Body');
Events.trigger(engine, 'beforeUpdate', event);
// get lists of all bodies and constraints, no matter what composites they are in
// get all bodies and all constraints in the world
var allBodies = Composite.allBodies(world),
allConstraints = Composite.allConstraints(world);
// @if DEBUG
// reset metrics logging
Metrics.reset(engine.metrics);
// @endif
// update the detector bodies if they have changed
if (world.isModified) {
Detector.setBodies(detector, allBodies);
}
// if sleeping enabled, call the sleeping controller
// reset all composite modified flags
if (world.isModified) {
Composite.setModified(world, false, false, true);
}
// update sleeping if enabled
if (engine.enableSleeping)
Sleeping.update(allBodies, timing.timeScale);
// applies gravity to all bodies
Engine._bodiesApplyGravity(allBodies, world.gravity);
// apply gravity to all bodies
Engine._bodiesApplyGravity(allBodies, engine.gravity);
// update all body position and rotation by integration
Engine._bodiesUpdate(allBodies, delta, timing.timeScale, correction, world.bounds);
@ -135,33 +140,12 @@ var Body = require('../body/Body');
}
Constraint.postSolveAll(allBodies);
// broadphase pass: find potential collision pairs
if (broadphase.controller) {
// if world is dirty, we must flush the whole grid
if (world.isModified)
broadphase.controller.clear(broadphase);
// update the grid buckets based on current bodies
broadphase.controller.update(broadphase, allBodies, engine, world.isModified);
broadphasePairs = broadphase.pairsList;
} else {
// if no broadphase set, we just pass all bodies
broadphasePairs = allBodies;
}
// clear all composite modified flags
if (world.isModified) {
Composite.setModified(world, false, false, true);
}
// narrowphase pass: find actual collisions, then create or update collision pairs
var collisions = broadphase.detector(broadphasePairs, engine);
// find all collisions
detector.pairs = engine.pairs;
var collisions = Detector.collisions(detector);
// update collision pairs
var pairs = engine.pairs,
timestamp = timing.timestamp;
Pairs.update(pairs, collisions, timestamp);
Pairs.removeOld(pairs, timestamp);
// wake up bodies involved in collisions
if (engine.enableSleeping)
@ -174,7 +158,7 @@ var Body = require('../body/Body');
// iteratively resolve position between collisions
Resolver.preSolvePosition(pairs.list);
for (i = 0; i < engine.positionIterations; i++) {
Resolver.solvePosition(pairs.list, allBodies, timing.timeScale);
Resolver.solvePosition(pairs.list, timing.timeScale);
}
Resolver.postSolvePosition(allBodies);
@ -198,16 +182,14 @@ var Body = require('../body/Body');
if (pairs.collisionEnd.length > 0)
Events.trigger(engine, 'collisionEnd', { pairs: pairs.collisionEnd });
// @if DEBUG
// update metrics log
Metrics.update(engine.metrics, engine);
// @endif
// clear force buffers
Engine._bodiesClearForces(allBodies);
Events.trigger(engine, 'afterUpdate', event);
// log the time elapsed computing this update
engine.timing.lastElapsed = Common.now() - startTime;
return engine;
};
@ -236,21 +218,13 @@ var Body = require('../body/Body');
};
/**
* Clears the engine including the world, pairs and broadphase.
* Clears the engine pairs and detector.
* @method clear
* @param {engine} engine
*/
Engine.clear = function(engine) {
var world = engine.world;
Pairs.clear(engine.pairs);
var broadphase = engine.broadphase;
if (broadphase.controller) {
var bodies = Composite.allBodies(world);
broadphase.controller.clear(broadphase);
broadphase.controller.update(broadphase, bodies, engine, true);
}
Detector.clear(engine.detector);
};
/**
@ -320,7 +294,8 @@ var Body = require('../body/Body');
};
/**
* An alias for `Runner.run`, see `Matter.Runner` for more information.
* A deprecated alias for `Runner.run`, use `Matter.Runner.run(engine)` instead and see `Matter.Runner` for more information.
* @deprecated use Matter.Runner.run(engine) instead
* @method run
* @param {engine} engine
*/
@ -329,53 +304,53 @@ var Body = require('../body/Body');
* Fired just before an update
*
* @event beforeUpdate
* @param {} event An event object
* @param {object} event An event object
* @param {number} event.timestamp The engine.timing.timestamp of the event
* @param {} event.source The source object of the event
* @param {} event.name The name of the event
* @param {engine} event.source The source object of the event
* @param {string} event.name The name of the event
*/
/**
* Fired after engine update and all collision events
*
* @event afterUpdate
* @param {} event An event object
* @param {object} event An event object
* @param {number} event.timestamp The engine.timing.timestamp of the event
* @param {} event.source The source object of the event
* @param {} event.name The name of the event
* @param {engine} event.source The source object of the event
* @param {string} event.name The name of the event
*/
/**
* Fired after engine update, provides a list of all pairs that have started to collide in the current tick (if any)
*
* @event collisionStart
* @param {} event An event object
* @param {} event.pairs List of affected pairs
* @param {object} event An event object
* @param {pair[]} event.pairs List of affected pairs
* @param {number} event.timestamp The engine.timing.timestamp of the event
* @param {} event.source The source object of the event
* @param {} event.name The name of the event
* @param {engine} event.source The source object of the event
* @param {string} event.name The name of the event
*/
/**
* Fired after engine update, provides a list of all pairs that are colliding in the current tick (if any)
*
* @event collisionActive
* @param {} event An event object
* @param {} event.pairs List of affected pairs
* @param {object} event An event object
* @param {pair[]} event.pairs List of affected pairs
* @param {number} event.timestamp The engine.timing.timestamp of the event
* @param {} event.source The source object of the event
* @param {} event.name The name of the event
* @param {engine} event.source The source object of the event
* @param {string} event.name The name of the event
*/
/**
* Fired after engine update, provides a list of all pairs that have ended collision in the current tick (if any)
*
* @event collisionEnd
* @param {} event An event object
* @param {} event.pairs List of affected pairs
* @param {object} event An event object
* @param {pair[]} event.pairs List of affected pairs
* @param {number} event.timestamp The engine.timing.timestamp of the event
* @param {} event.source The source object of the event
* @param {} event.name The name of the event
* @param {engine} event.source The source object of the event
* @param {string} event.name The name of the event
*/
/*
@ -449,32 +424,56 @@ var Body = require('../body/Body');
*/
/**
* An instance of a `Render` controller. The default value is a `Matter.Render` instance created by `Engine.create`.
* One may also develop a custom renderer module based on `Matter.Render` and pass an instance of it to `Engine.create` via `options.render`.
* A `Number` that represents the total execution time elapsed during the last `Engine.update` in milliseconds.
* It is updated by timing from the start of the last `Engine.update` call until it ends.
*
* A minimal custom renderer object must define at least three functions: `create`, `clear` and `world` (see `Matter.Render`).
* It is also possible to instead pass the _module_ reference via `options.render.controller` and `Engine.create` will instantiate one for you.
* This value will also include the total execution time of all event handlers directly or indirectly triggered by the engine update.
*
* @property render
* @type render
* @deprecated see Demo.js for an example of creating a renderer
* @default a Matter.Render instance
* @property timing.lastElapsed
* @type number
* @default 0
*/
/**
* An instance of a broadphase controller. The default value is a `Matter.Grid` instance created by `Engine.create`.
* A `Number` that represents the `delta` value used in the last engine update.
*
* @property timing.lastDelta
* @type number
* @default 0
*/
/**
* A `Matter.Detector` instance.
*
* @property detector
* @type detector
* @default a Matter.Detector instance
*/
/**
* A `Matter.Grid` instance.
*
* @deprecated replaced by `engine.detector`
* @property grid
* @type grid
* @default a Matter.Grid instance
*/
/**
* Replaced by and now alias for `engine.grid`.
*
* @deprecated replaced by `engine.detector`
* @property broadphase
* @type grid
* @default a Matter.Grid instance
*/
/**
* A `World` composite object that will contain all simulated bodies and constraints.
* The root `Matter.Composite` instance that will contain all bodies, constraints and other composites to be simulated by this engine.
*
* @property world
* @type world
* @default a Matter.World instance
* @type composite
* @default a Matter.Composite instance
*/
/**
@ -484,4 +483,35 @@ var Body = require('../body/Body');
* @type {}
*/
/**
* The gravity to apply on all bodies in `engine.world`.
*
* @property gravity
* @type object
*/
/**
* The gravity x component.
*
* @property gravity.x
* @type object
* @default 0
*/
/**
* The gravity y component.
*
* @property gravity.y
* @type object
* @default 1
*/
/**
* The gravity scale factor.
*
* @property gravity.scale
* @type object
* @default 0.001
*/
})();

View file

@ -27,7 +27,7 @@ var Common = require('./Common');
* @readOnly
* @type {String}
*/
Matter.version = '0.14.2';
Matter.version = '0.18.0';
/**
* A list of plugin dependencies to be installed. These are normally set and installed through `Matter.use`.

View file

@ -1,93 +0,0 @@
// @if DEBUG
/**
* _Internal Class_, not generally used outside of the engine's internals.
*
*/
var Metrics = {};
module.exports = Metrics;
var Composite = require('../body/Composite');
var Common = require('./Common');
(function() {
/**
* Creates a new metrics.
* @method create
* @private
* @return {metrics} A new metrics
*/
Metrics.create = function(options) {
var defaults = {
extended: false,
narrowDetections: 0,
narrowphaseTests: 0,
narrowReuse: 0,
narrowReuseCount: 0,
midphaseTests: 0,
broadphaseTests: 0,
narrowEff: 0.0001,
midEff: 0.0001,
broadEff: 0.0001,
collisions: 0,
buckets: 0,
bodies: 0,
pairs: 0
};
return Common.extend(defaults, false, options);
};
/**
* Resets metrics.
* @method reset
* @private
* @param {metrics} metrics
*/
Metrics.reset = function(metrics) {
if (metrics.extended) {
metrics.narrowDetections = 0;
metrics.narrowphaseTests = 0;
metrics.narrowReuse = 0;
metrics.narrowReuseCount = 0;
metrics.midphaseTests = 0;
metrics.broadphaseTests = 0;
metrics.narrowEff = 0;
metrics.midEff = 0;
metrics.broadEff = 0;
metrics.collisions = 0;
metrics.buckets = 0;
metrics.pairs = 0;
metrics.bodies = 0;
}
};
/**
* Updates metrics.
* @method update
* @private
* @param {metrics} metrics
* @param {engine} engine
*/
Metrics.update = function(metrics, engine) {
if (metrics.extended) {
var world = engine.world,
bodies = Composite.allBodies(world);
metrics.collisions = metrics.narrowDetections;
metrics.pairs = engine.pairs.list.length;
metrics.bodies = bodies.length;
metrics.midEff = (metrics.narrowDetections / (metrics.midphaseTests || 1)).toFixed(2);
metrics.narrowEff = (metrics.narrowDetections / (metrics.narrowphaseTests || 1)).toFixed(2);
metrics.broadEff = (1 - (metrics.broadphaseTests / (bodies.length || 1))).toFixed(2);
metrics.narrowReuse = (metrics.narrowReuseCount / (metrics.narrowphaseTests || 1)).toFixed(2);
//var broadphase = engine.broadphase[engine.broadphase.current];
//if (broadphase.instance)
// metrics.buckets = Common.keys(broadphase.instance.buckets).length;
}
};
})();
// @endif

View file

@ -240,7 +240,7 @@ var Common = require('./Common');
*/
Plugin.dependencyParse = function(dependency) {
if (Common.isString(dependency)) {
var pattern = /^[\w-]+(@(\*|[\^~]?\d+\.\d+\.\d+(-[0-9A-Za-z-]+)?))?$/;
var pattern = /^[\w-]+(@(\*|[\^~]?\d+\.\d+\.\d+(-[0-9A-Za-z-+]+)?))?$/;
if (!pattern.test(dependency)) {
Common.warn('Plugin.dependencyParse:', dependency, 'is not a valid dependency string.');
@ -266,6 +266,8 @@ var Common = require('./Common');
* Only the following range types are supported:
* - Tilde ranges e.g. `~1.2.3`
* - Caret ranges e.g. `^1.2.3`
* - Greater than ranges e.g. `>1.2.3`
* - Greater than or equal ranges e.g. `>=1.2.3`
* - Exact version e.g. `1.2.3`
* - Any version `*`
* @method versionParse
@ -273,29 +275,28 @@ var Common = require('./Common');
* @return {object} The version range parsed into its components.
*/
Plugin.versionParse = function(range) {
var pattern = /^\*|[\^~]?\d+\.\d+\.\d+(-[0-9A-Za-z-]+)?$/;
var pattern = /^(\*)|(\^|~|>=|>)?\s*((\d+)\.(\d+)\.(\d+))(-[0-9A-Za-z-+]+)?$/;
if (!pattern.test(range)) {
Common.warn('Plugin.versionParse:', range, 'is not a valid version or range.');
}
var identifiers = range.split('-');
range = identifiers[0];
var isRange = isNaN(Number(range[0])),
version = isRange ? range.substr(1) : range,
parts = Common.map(version.split('.'), function(part) {
return Number(part);
});
var parts = pattern.exec(range);
var major = Number(parts[4]);
var minor = Number(parts[5]);
var patch = Number(parts[6]);
return {
isRange: isRange,
version: version,
isRange: Boolean(parts[1] || parts[2]),
version: parts[3],
range: range,
operator: isRange ? range[0] : '',
parts: parts,
prerelease: identifiers[1],
number: parts[0] * 1e8 + parts[1] * 1e4 + parts[2]
operator: parts[1] || parts[2] || '',
major: major,
minor: minor,
patch: patch,
parts: [major, minor, patch],
prerelease: parts[7],
number: major * 1e8 + minor * 1e4 + patch
};
};
@ -311,30 +312,36 @@ var Common = require('./Common');
Plugin.versionSatisfies = function(version, range) {
range = range || '*';
var rangeParsed = Plugin.versionParse(range),
rangeParts = rangeParsed.parts,
versionParsed = Plugin.versionParse(version),
versionParts = versionParsed.parts;
var r = Plugin.versionParse(range),
v = Plugin.versionParse(version);
if (rangeParsed.isRange) {
if (rangeParsed.operator === '*' || version === '*') {
if (r.isRange) {
if (r.operator === '*' || version === '*') {
return true;
}
if (rangeParsed.operator === '~') {
return versionParts[0] === rangeParts[0] && versionParts[1] === rangeParts[1] && versionParts[2] >= rangeParts[2];
if (r.operator === '>') {
return v.number > r.number;
}
if (rangeParsed.operator === '^') {
if (rangeParts[0] > 0) {
return versionParts[0] === rangeParts[0] && versionParsed.number >= rangeParsed.number;
if (r.operator === '>=') {
return v.number >= r.number;
}
if (r.operator === '~') {
return v.major === r.major && v.minor === r.minor && v.patch >= r.patch;
}
if (r.operator === '^') {
if (r.major > 0) {
return v.major === r.major && v.number >= r.number;
}
if (rangeParts[1] > 0) {
return versionParts[1] === rangeParts[1] && versionParts[2] >= rangeParts[2];
if (r.minor > 0) {
return v.minor === r.minor && v.patch >= r.patch;
}
return versionParts[2] === rangeParts[2];
return v.patch === r.patch;
}
}

View file

@ -101,7 +101,6 @@ var Common = require('./Common');
/**
* A game loop utility that updates the engine and renderer by one step (a 'tick').
* Features delta smoothing, time correction and fixed or dynamic timing.
* Triggers `beforeTick`, `tick` and `afterTick` events on the engine.
* Consider just `Engine.update(engine, delta)` if you're using your own loop.
* @method tick
* @param {runner} runner
@ -119,7 +118,6 @@ var Common = require('./Common');
};
Events.trigger(runner, 'beforeTick', event);
Events.trigger(engine, 'beforeTick', event); // @deprecated
if (runner.isFixed) {
// fixed timestep
@ -164,35 +162,13 @@ var Common = require('./Common');
}
Events.trigger(runner, 'tick', event);
Events.trigger(engine, 'tick', event); // @deprecated
// if world has been modified, clear the render scene graph
if (engine.world.isModified
&& engine.render
&& engine.render.controller
&& engine.render.controller.clear) {
engine.render.controller.clear(engine.render); // @deprecated
}
// update
Events.trigger(runner, 'beforeUpdate', event);
Engine.update(engine, delta, correction);
Events.trigger(runner, 'afterUpdate', event);
// render
// @deprecated
if (engine.render && engine.render.controller) {
Events.trigger(runner, 'beforeRender', event);
Events.trigger(engine, 'beforeRender', event); // @deprecated
engine.render.controller.world(engine.render);
Events.trigger(runner, 'afterRender', event);
Events.trigger(engine, 'afterRender', event); // @deprecated
}
Events.trigger(runner, 'afterTick', event);
Events.trigger(engine, 'afterTick', event); // @deprecated
};
/**
@ -271,28 +247,6 @@ var Common = require('./Common');
* @param {} event.name The name of the event
*/
/**
* Fired before rendering
*
* @event beforeRender
* @param {} event An event object
* @param {number} event.timestamp The engine.timing.timestamp of the event
* @param {} event.source The source object of the event
* @param {} event.name The name of the event
* @deprecated
*/
/**
* Fired after rendering
*
* @event afterRender
* @param {} event An event object
* @param {number} event.timestamp The engine.timing.timestamp of the event
* @param {} event.source The source object of the event
* @param {} event.name The name of the event
* @deprecated
*/
/*
*
* Properties Documentation

View file

@ -18,7 +18,6 @@ var Common = require('../core/Common');
var Body = require('../body/Body');
var Bounds = require('../geometry/Bounds');
var Vector = require('../geometry/Vector');
var decomp = require('../../poly-decomp');
(function() {
@ -177,29 +176,46 @@ var decomp = require('../../poly-decomp');
};
/**
* Creates a body using the supplied vertices (or an array containing multiple sets of vertices).
* If the vertices are convex, they will pass through as supplied.
* Otherwise if the vertices are concave, they will be decomposed if [poly-decomp.js](https://github.com/schteppe/poly-decomp.js) is available.
* Note that this process is not guaranteed to support complex sets of vertices (e.g. those with holes may fail).
* By default the decomposition will discard collinear edges (to improve performance).
* It can also optionally discard any parts that have an area less than `minimumArea`.
* If the vertices can not be decomposed, the result will fall back to using the convex hull.
* The options parameter is an object that specifies any `Matter.Body` properties you wish to override the defaults.
* Utility to create a compound body based on set(s) of vertices.
*
* _Note:_ To optionally enable automatic concave vertices decomposition the [poly-decomp](https://github.com/schteppe/poly-decomp.js)
* package must be first installed and provided see `Common.setDecomp`, otherwise the convex hull of each vertex set will be used.
*
* The resulting vertices are reorientated about their centre of mass,
* and offset such that `body.position` corresponds to this point.
*
* The resulting offset may be found if needed by subtracting `body.bounds` from the original input bounds.
* To later move the centre of mass see `Body.setCentre`.
*
* Note that automatic conconcave decomposition results are not always optimal.
* For best results, simplify the input vertices as much as possible first.
* By default this function applies some addtional simplification to help.
*
* Some outputs may also require further manual processing afterwards to be robust.
* In particular some parts may need to be overlapped to avoid collision gaps.
* Thin parts and sharp points should be avoided or removed where possible.
*
* The options parameter object specifies any `Matter.Body` properties you wish to override the defaults.
*
* See the properties section of the `Matter.Body` module for detailed information on what you can pass via the `options` object.
* @method fromVertices
* @param {number} x
* @param {number} y
* @param [[vector]] vertexSets
* @param {object} [options]
* @param {bool} [flagInternal=false]
* @param {number} [removeCollinear=0.01]
* @param {number} [minimumArea=10]
* @param {array} vertexSets One or more arrays of vertex points e.g. `[[{ x: 0, y: 0 }...], ...]`.
* @param {object} [options] The body options.
* @param {bool} [flagInternal=false] Optionally marks internal edges with `isInternal`.
* @param {number} [removeCollinear=0.01] Threshold when simplifying vertices along the same edge.
* @param {number} [minimumArea=10] Threshold when removing small parts.
* @param {number} [removeDuplicatePoints=0.01] Threshold when simplifying nearby vertices.
* @return {body}
*/
Bodies.fromVertices = function(x, y, vertexSets, options, flagInternal, removeCollinear, minimumArea) {
var body,
Bodies.fromVertices = function(x, y, vertexSets, options, flagInternal, removeCollinear, minimumArea, removeDuplicatePoints) {
var decomp = Common.getDecomp(),
canDecomp,
body,
parts,
isConvex,
isConcave,
vertices,
i,
j,
@ -207,16 +223,16 @@ var decomp = require('../../poly-decomp');
v,
z;
// check decomp is as expected
canDecomp = Boolean(decomp && decomp.quickDecomp);
options = options || {};
parts = [];
flagInternal = typeof flagInternal !== 'undefined' ? flagInternal : false;
removeCollinear = typeof removeCollinear !== 'undefined' ? removeCollinear : 0.01;
minimumArea = typeof minimumArea !== 'undefined' ? minimumArea : 10;
if (!decomp) {
Common.warn('Bodies.fromVertices: poly-decomp.js required. Could not decompose vertices. Fallback to convex hull.');
}
removeDuplicatePoints = typeof removeDuplicatePoints !== 'undefined' ? removeDuplicatePoints : 0.01;
// ensure vertexSets is an array of arrays
if (!Common.isArray(vertexSets[0])) {
@ -226,8 +242,15 @@ var decomp = require('../../poly-decomp');
for (v = 0; v < vertexSets.length; v += 1) {
vertices = vertexSets[v];
isConvex = Vertices.isConvex(vertices);
isConcave = !isConvex;
if (isConvex || !decomp) {
if (isConcave && !canDecomp) {
Common.warnOnce(
'Bodies.fromVertices: Install the \'poly-decomp\' library and use Common.setDecomp or provide \'decomp\' as a global to decompose concave vertices.'
);
}
if (isConvex || !canDecomp) {
if (isConvex) {
vertices = Vertices.clockwiseSort(vertices);
} else {
@ -249,6 +272,8 @@ var decomp = require('../../poly-decomp');
decomp.makeCCW(concave);
if (removeCollinear !== false)
decomp.removeCollinearPoints(concave, removeCollinear);
if (removeDuplicatePoints !== false && decomp.removeDuplicatePoints)
decomp.removeDuplicatePoints(concave, removeDuplicatePoints);
// use the quick decomposition algorithm (Bayazit)
var decomposed = decomp.quickDecomp(concave);
@ -283,14 +308,45 @@ var decomp = require('../../poly-decomp');
parts[i] = Body.create(Common.extend(parts[i], options));
}
if (flagInternal)
{
Bodies.flagCoincidentParts(parts, 5);
// flag internal edges (coincident part edges)
if (flagInternal) {
var coincident_max_dist = 5;
for (i = 0; i < parts.length; i++) {
var partA = parts[i];
for (j = i + 1; j < parts.length; j++) {
var partB = parts[j];
if (Bounds.overlaps(partA.bounds, partB.bounds)) {
var pav = partA.vertices,
pbv = partB.vertices;
// iterate vertices of both parts
for (k = 0; k < partA.vertices.length; k++) {
for (z = 0; z < partB.vertices.length; z++) {
// find distances between the vertices
var da = Vector.magnitudeSquared(Vector.sub(pav[(k + 1) % pav.length], pbv[z])),
db = Vector.magnitudeSquared(Vector.sub(pav[k], pbv[(z + 1) % pbv.length]));
// if both vertices are very close, consider the edge concident (internal)
if (da < coincident_max_dist && db < coincident_max_dist) {
pav[k].isInternal = true;
pbv[z].isInternal = true;
}
}
}
}
}
}
}
if (parts.length > 1) {
// create the parent body to be returned, that contains generated compound parts
body = Body.create(Common.extend({ parts: parts.slice(0) }, options));
// offset such that body.position is at the centre off mass
Body.setPosition(body, { x: x, y: y });
return body;
@ -299,54 +355,4 @@ var decomp = require('../../poly-decomp');
}
};
/**
* Takes an array of Body objects and flags all internal edges (coincident parts) based on the maxDistance
* value. The array is changed in-place and returned, so you can pass this function a `Body.parts` property.
*
* @method flagCoincidentParts
* @param {body[]} parts - The Body parts, or array of bodies, to flag.
* @param {number} [maxDistance=5]
* @return {body[]} The modified `parts` parameter.
*/
Bodies.flagCoincidentParts = function (parts, maxDistance)
{
if (maxDistance === undefined) { maxDistance = 5; }
for (var i = 0; i < parts.length; i++)
{
var partA = parts[i];
for (var j = i + 1; j < parts.length; j++)
{
var partB = parts[j];
if (Bounds.overlaps(partA.bounds, partB.bounds))
{
var pav = partA.vertices;
var pbv = partB.vertices;
// iterate vertices of both parts
for (var k = 0; k < partA.vertices.length; k++)
{
for (var z = 0; z < partB.vertices.length; z++)
{
// find distances between the vertices
var da = Vector.magnitudeSquared(Vector.sub(pav[(k + 1) % pav.length], pbv[z]));
var db = Vector.magnitudeSquared(Vector.sub(pav[k], pbv[(z + 1) % pbv.length]));
// if both vertices are very close, consider the edge concident (internal)
if (da < maxDistance && db < maxDistance)
{
pav[k].isInternal = true;
pbv[z].isInternal = true;
}
}
}
}
}
}
return parts;
};
})();

View file

@ -16,6 +16,7 @@ var Constraint = require('../constraint/Constraint');
var Common = require('../core/Common');
var Body = require('../body/Body');
var Bodies = require('./Bodies');
var deprecated = Common.deprecated;
(function() {
@ -202,7 +203,8 @@ var Bodies = require('./Bodies');
};
/**
* Creates a composite with a Newton's Cradle setup of bodies and constraints.
* This has now moved to the [newtonsCradle example](https://github.com/liabru/matter-js/blob/master/examples/newtonsCradle.js), follow that instead as this function is deprecated here.
* @deprecated moved to newtonsCradle example
* @method newtonsCradle
* @param {number} xx
* @param {number} yy
@ -227,8 +229,11 @@ var Bodies = require('./Bodies');
return newtonsCradle;
};
deprecated(Composites, 'newtonsCradle', 'Composites.newtonsCradle ➤ moved to newtonsCradle example');
/**
* Creates a composite with simple car setup of bodies and constraints.
* This has now moved to the [car example](https://github.com/liabru/matter-js/blob/master/examples/car.js), follow that instead as this function is deprecated here.
* @deprecated moved to car example
* @method car
* @param {number} xx
* @param {number} yy
@ -294,8 +299,12 @@ var Bodies = require('./Bodies');
return car;
};
deprecated(Composites, 'car', 'Composites.car ➤ moved to car example');
/**
* Creates a simple soft body like object.
* This has now moved to the [softBody example](https://github.com/liabru/matter-js/blob/master/examples/softBody.js)
* and the [cloth example](https://github.com/liabru/matter-js/blob/master/examples/cloth.js), follow those instead as this function is deprecated here.
* @deprecated moved to softBody and cloth examples
* @method softBody
* @param {number} xx
* @param {number} yy
@ -324,4 +333,5 @@ var Bodies = require('./Bodies');
return softBody;
};
deprecated(Composites, 'softBody', 'Composites.softBody ➤ moved to softBody and cloth examples');
})();

View file

@ -44,17 +44,9 @@ var Common = require('../core/Common');
y: point.y,
index: i,
body: body,
isInternal: false,
contact: null,
offset: null
isInternal: false
};
vertex.contact = {
vertex: vertex,
normalImpulse: 0,
tangentImpulse: 0
};
vertices.push(vertex);
}
@ -177,17 +169,16 @@ var Common = require('../core/Common');
* @param {number} scalar
*/
Vertices.translate = function(vertices, vector, scalar) {
var i;
if (scalar) {
for (i = 0; i < vertices.length; i++) {
vertices[i].x += vector.x * scalar;
vertices[i].y += vector.y * scalar;
}
} else {
for (i = 0; i < vertices.length; i++) {
vertices[i].x += vector.x;
vertices[i].y += vector.y;
}
scalar = typeof scalar !== 'undefined' ? scalar : 1;
var verticesLength = vertices.length,
translateX = vector.x * scalar,
translateY = vector.y * scalar,
i;
for (i = 0; i < verticesLength; i++) {
vertices[i].x += translateX;
vertices[i].y += translateY;
}
return vertices;
@ -205,15 +196,21 @@ var Common = require('../core/Common');
return;
var cos = Math.cos(angle),
sin = Math.sin(angle);
sin = Math.sin(angle),
pointX = point.x,
pointY = point.y,
verticesLength = vertices.length,
vertex,
dx,
dy,
i;
for (var i = 0; i < vertices.length; i++) {
var vertice = vertices[i],
dx = vertice.x - point.x,
dy = vertice.y - point.y;
vertice.x = point.x + (dx * cos - dy * sin);
vertice.y = point.y + (dx * sin + dy * cos);
for (i = 0; i < verticesLength; i++) {
vertex = vertices[i];
dx = vertex.x - pointX;
dy = vertex.y - pointY;
vertex.x = pointX + (dx * cos - dy * sin);
vertex.y = pointY + (dx * sin + dy * cos);
}
return vertices;
@ -227,12 +224,21 @@ var Common = require('../core/Common');
* @return {boolean} True if the vertices contains point, otherwise false
*/
Vertices.contains = function(vertices, point) {
for (var i = 0; i < vertices.length; i++) {
var vertice = vertices[i],
nextVertice = vertices[(i + 1) % vertices.length];
if ((point.x - vertice.x) * (nextVertice.y - vertice.y) + (point.y - vertice.y) * (vertice.x - nextVertice.x) > 0) {
var pointX = point.x,
pointY = point.y,
verticesLength = vertices.length,
vertex = vertices[verticesLength - 1],
nextVertex;
for (var i = 0; i < verticesLength; i++) {
nextVertex = vertices[i];
if ((pointX - vertex.x) * (nextVertex.y - vertex.y)
+ (pointY - vertex.y) * (vertex.x - nextVertex.x) > 0) {
return false;
}
vertex = nextVertex;
}
return true;

View file

@ -9,7 +9,7 @@ var MatterAttractors =
{
name: 'matter-attractors',
version: '0.1.7',
for: 'matter-js@^0.14.2',
for: 'matter-js@^0.18.0',
silent: true,
// installs the plugin where `base` is `Matter`

View file

@ -8,7 +8,7 @@ var MatterCollisionEvents = {
name: 'matter-collision-events',
version: '0.1.6',
for: 'matter-js@^0.14.2',
for: 'matter-js@^0.18.0',
silent: true,
install: function (matter)

View file

@ -9,7 +9,7 @@ var MatterWrap = {
// plugin meta
name: 'matter-wrap', // PLUGIN_NAME
version: '0.1.4', // PLUGIN_VERSION
for: 'matter-js@^0.14.2',
for: 'matter-js@^0.18.0',
silent: true, // no console log please
// installs the plugin where `base` is `Matter`

View file

@ -44,4 +44,6 @@ if (typeof window.Uint32Array !== 'function' && typeof window.Uint32Array !== 'o
CheapArray('Uint16Array'); // jshint ignore:line
CheapArray('Int16Array'); // jshint ignore:line
CheapArray('ArrayBuffer'); // jshint ignore:line
CheapArray('Int8Array'); // jshint ignore:line
CheapArray('Uint8Array'); // jshint ignore:line
}

View file

@ -818,7 +818,10 @@ var CanvasRenderer = new Class({
sprite.mask.preRenderCanvas(this, sprite, camera);
}
ctx.drawImage(frame.source.image, frameX, frameY, frameWidth, frameHeight, x, y, frameWidth / res, frameHeight / res);
if (frameWidth > 0 && frameHeight > 0)
{
ctx.drawImage(frame.source.image, frameX, frameY, frameWidth, frameHeight, x, y, frameWidth / res, frameHeight / res);
}
if (sprite.mask)
{

View file

@ -45,7 +45,10 @@ var CanvasSnapshot = function (canvas, config)
var copyCanvas = CanvasPool.createWebGL(this, width, height);
var ctx = copyCanvas.getContext('2d');
ctx.drawImage(canvas, x, y, width, height, 0, 0, width, height);
if (width > 0 && height > 0)
{
ctx.drawImage(canvas, x, y, width, height, 0, 0, width, height);
}
var image1 = new Image();

View file

@ -17,12 +17,12 @@ var GetFastValue = require('../../utils/object/GetFastValue');
* @function Phaser.Renderer.Snapshot.WebGL
* @since 3.0.0
*
* @param {HTMLCanvasElement} sourceCanvas - The canvas to take a snapshot of.
* @param {WebGLRenderingContext} sourceContext - The WebGL context to take a snapshot of.
* @param {Phaser.Types.Renderer.Snapshot.SnapshotState} config - The snapshot configuration object.
*/
var WebGLSnapshot = function (sourceCanvas, config)
var WebGLSnapshot = function (sourceContext, config)
{
var gl = sourceCanvas.getContext('experimental-webgl');
var gl = sourceContext;
var callback = GetFastValue(config, 'callback');
var type = GetFastValue(config, 'type', 'image/png');

View file

@ -2654,7 +2654,7 @@ var WebGLRenderer = new Class({
if (state.callback)
{
WebGLSnapshot(this.canvas, state);
WebGLSnapshot(this.gl, state);
state.callback = null;
}
@ -2814,7 +2814,7 @@ var WebGLRenderer = new Class({
this.setFramebuffer(framebuffer);
WebGLSnapshot(this.canvas, state);
WebGLSnapshot(this.gl, state);
this.setFramebuffer(currentFramebuffer);

View file

@ -194,30 +194,28 @@ var BaseSoundManager = new Class({
var _this = this;
var body = document.body;
var bodyAdd = body.addEventListener;
var bodyRemove = body.removeEventListener;
var unlockHandler = function unlockHandler ()
{
if (!_this.pendingUnlock)
{
return;
}
_this.unlockHandler();
bodyRemove('touchstart', unlockHandler);
bodyRemove('touchend', unlockHandler);
bodyRemove('click', unlockHandler);
bodyRemove('keydown', unlockHandler);
};
if (body)
{
bodyAdd('touchstart', unlockHandler, false);
bodyAdd('touchend', unlockHandler, false);
bodyAdd('click', unlockHandler, false);
bodyAdd('keydown', unlockHandler, false);
var unlockHandler = function unlockHandler ()
{
if (!_this.pendingUnlock)
{
return;
}
_this.unlockHandler();
body.removeEventListener('touchstart', unlockHandler);
body.removeEventListener('touchend', unlockHandler);
body.removeEventListener('click', unlockHandler);
body.removeEventListener('keydown', unlockHandler);
};
body.addEventListener('touchstart', unlockHandler, false);
body.addEventListener('touchend', unlockHandler, false);
body.addEventListener('click', unlockHandler, false);
body.addEventListener('keydown', unlockHandler, false);
this.pendingUnlock = true;
}

View file

@ -156,7 +156,15 @@ var WebAudioSoundManager = new Class({
}
else if (window.hasOwnProperty('webkitAudioContext'))
{
context = new window.webkitAudioContext({ latencyHint: 'interactive' });
try
{
context = new window.webkitAudioContext({ latencyHint: 'interactive' });
}
catch (e)
{
// For iOS10 and legacy devices we create without arguments:
context = new window.webkitAudioContext();
}
}
this.setAudioContext(context);

View file

@ -331,17 +331,20 @@ var TextureManager = new Class({
var canvas = CanvasPool.create2D(this, cd.width, cd.height);
var ctx = canvas.getContext('2d');
ctx.drawImage(
textureFrame.source.image,
cd.x,
cd.y,
cd.width,
cd.height,
0,
0,
cd.width,
cd.height
);
if (cd.width > 0 && cd.height > 0)
{
ctx.drawImage(
textureFrame.source.image,
cd.x,
cd.y,
cd.width,
cd.height,
0,
0,
cd.width,
cd.height
);
}
data = canvas.toDataURL(type, encoderOptions);

View file

@ -90,15 +90,14 @@ var TilemapLayerCanvasRenderer = function (renderer, src, camera, parentMatrix)
var image = tileset.image.getSourceImage();
var tileTexCoords = tileset.getTileTextureCoordinates(tile.index);
var tileWidth = tileset.tileWidth;
var tileHeight = tileset.tileHeight;
if (tileTexCoords === null)
if (tileTexCoords === null || tileWidth === 0 || tileHeight === 0)
{
continue;
}
var tileWidth = tileset.tileWidth;
var tileHeight = tileset.tileHeight;
var halfWidth = tileWidth * 0.5;
var halfHeight = tileHeight * 0.5;

View file

@ -967,13 +967,16 @@ var Tween = new Class({
this.state = TWEEN_CONST.ACTIVE;
}
this.isSeeking = true;
do
if (toPosition > 0)
{
this.update(0, delta);
this.isSeeking = true;
} while (this.totalProgress < toPosition);
do
{
this.update(0, delta);
} while (this.totalProgress < toPosition);
}
this.isSeeking = false;

View file

@ -24,8 +24,7 @@ var SafeRange = function (array, startIndex, endIndex, throwError)
if (startIndex < 0 ||
startIndex > len ||
startIndex >= endIndex ||
endIndex > len ||
startIndex + endIndex > len)
endIndex > len)
{
if (throwError)
{

View file

@ -4,47 +4,79 @@
* @license {@link https://opensource.org/licenses/MIT|MIT License}
*/
// Source object
// The key as a string, or an array of keys, i.e. 'banner', or 'banner.hideBanner'
// The default value to use if the key doesn't exist
/**
* Retrieves a value from an object.
* Retrieves a value from an object, or an alternative object, falling to a back-up default value if not found.
*
* The key is a string, which can be split based on the use of the period character.
*
* For example:
*
* ```javascript
* const source = {
* lives: 3,
* render: {
* screen: {
* width: 1024
* }
* }
* }
*
* const lives = GetValue(source, 'lives', 1);
* const width = GetValue(source, 'render.screen.width', 800);
* const height = GetValue(source, 'render.screen.height', 600);
* ```
*
* In the code above, `lives` will be 3 because it's defined at the top level of `source`.
* The `width` value will be 1024 because it can be found inside the `render.screen` object.
* The `height` value will be 600, the default value, because it is missing from the `render.screen` object.
*
* @function Phaser.Utils.Objects.GetValue
* @since 3.0.0
*
* @param {object} source - The object to retrieve the value from.
* @param {object} source - The primary object to try to retrieve the value from. If not found in here, `altSource` is checked.
* @param {string} key - The name of the property to retrieve from the object. If a property is nested, the names of its preceding properties should be separated by a dot (`.`) - `banner.hideBanner` would return the value of the `hideBanner` property from the object stored in the `banner` property of the `source` object.
* @param {*} defaultValue - The value to return if the `key` isn't found in the `source` object.
* @param {object} [altSource] - An alternative object to retrieve the value from. If the property exists in `source` then `altSource` will not be used.
*
* @return {*} The value of the requested key.
*/
var GetValue = function (source, key, defaultValue)
var GetValue = function (source, key, defaultValue, altSource)
{
if (!source || typeof source === 'number')
if ((!source && !altSource) || typeof source === 'number')
{
return defaultValue;
}
else if (source.hasOwnProperty(key))
else if (source && source.hasOwnProperty(key))
{
return source[key];
}
else if (altSource && altSource.hasOwnProperty(key))
{
return altSource[key];
}
else if (key.indexOf('.') !== -1)
{
var keys = key.split('.');
var parent = source;
var parentA = source;
var parentB = altSource;
var value = defaultValue;
// Use for loop here so we can break early
for (var i = 0; i < keys.length; i++)
{
if (parent.hasOwnProperty(keys[i]))
if (parentA && parentA.hasOwnProperty(keys[i]))
{
// Yes it has a key property, let's carry on down
value = parent[keys[i]];
// Yes parentA has a key property, let's carry on down
value = parentA[keys[i]];
parent = parent[keys[i]];
parentA = parentA[keys[i]];
}
else if (parentB && parentB.hasOwnProperty(keys[i]))
{
// Yes parentB has a key property, let's carry on down
value = parentB[keys[i]];
parentB = parentB[keys[i]];
}
else
{