mirror of
https://github.com/photonstorm/phaser
synced 2024-11-25 22:20:44 +00:00
Merge branch 'master' of https://github.com/photonstorm/phaser
This commit is contained in:
commit
3546140b51
72 changed files with 93052 additions and 90179 deletions
|
@ -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
651
package-lock.json
generated
File diff suppressed because it is too large
Load diff
17
package.json
17
package.json
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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`.
|
||||
|
||||
|
|
59107
plugins/spine/dist/SpineCanvasPlugin.js
vendored
59107
plugins/spine/dist/SpineCanvasPlugin.js
vendored
File diff suppressed because it is too large
Load diff
2
plugins/spine/dist/SpineCanvasPlugin.min.js
vendored
2
plugins/spine/dist/SpineCanvasPlugin.min.js
vendored
File diff suppressed because one or more lines are too long
60170
plugins/spine/dist/SpinePlugin.js
vendored
60170
plugins/spine/dist/SpinePlugin.js
vendored
File diff suppressed because it is too large
Load diff
2
plugins/spine/dist/SpinePlugin.min.js
vendored
2
plugins/spine/dist/SpinePlugin.min.js
vendored
File diff suppressed because one or more lines are too long
59679
plugins/spine/dist/SpineWebGLPlugin.js
vendored
59679
plugins/spine/dist/SpineWebGLPlugin.js
vendored
File diff suppressed because it is too large
Load diff
2
plugins/spine/dist/SpineWebGLPlugin.min.js
vendored
2
plugins/spine/dist/SpineWebGLPlugin.min.js
vendored
File diff suppressed because one or more lines are too long
3
plugins/spine/src/runtimes/spine-both.d.ts
vendored
3
plugins/spine/src/runtimes/spine-both.d.ts
vendored
|
@ -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;
|
||||
|
|
|
@ -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
|
@ -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
3
plugins/spine/src/runtimes/spine-webgl.d.ts
vendored
3
plugins/spine/src/runtimes/spine-webgl.d.ts
vendored
|
@ -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;
|
||||
|
|
|
@ -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
|
@ -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
|
||||
}
|
||||
})
|
||||
]
|
||||
},
|
||||
|
|
|
@ -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
|
||||
}
|
||||
})
|
||||
]
|
||||
},
|
||||
|
|
|
@ -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
|
||||
}
|
||||
})
|
||||
]
|
||||
},
|
||||
|
|
|
@ -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:
|
||||
*
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
|
|
|
@ -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 {}
|
||||
*/
|
||||
|
||||
})();
|
||||
|
|
|
@ -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;
|
||||
|
||||
/*
|
||||
*
|
||||
|
|
408
src/physics/matter-js/lib/collision/Collision.js
Normal file
408
src/physics/matter-js/lib/collision/Collision.js
Normal 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 []
|
||||
*/
|
||||
|
||||
})();
|
27
src/physics/matter-js/lib/collision/Contact.js
Normal file
27
src/physics/matter-js/lib/collision/Contact.js
Normal 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
|
||||
};
|
||||
};
|
||||
|
||||
})();
|
|
@ -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
|
||||
*/
|
||||
|
||||
})();
|
||||
|
|
|
@ -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]];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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');
|
||||
|
||||
})();
|
||||
|
|
|
@ -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)
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
})();
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
||||
})();
|
||||
|
|
|
@ -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`.
|
||||
|
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
})();
|
||||
|
|
|
@ -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');
|
||||
})();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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`
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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`
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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');
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue