melonjs 14.0.1 → 14.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/dist/melonjs.mjs/_virtual/_commonjsHelpers.js +10 -0
- package/dist/melonjs.mjs/_virtual/arraymultimap.js +10 -0
- package/dist/melonjs.mjs/_virtual/earcut.js +10 -0
- package/dist/melonjs.mjs/_virtual/howler.js +10 -0
- package/dist/melonjs.mjs/_virtual/index.js +10 -0
- package/dist/melonjs.mjs/_virtual/index2.js +10 -0
- package/dist/melonjs.mjs/_virtual/multimap.js +10 -0
- package/dist/melonjs.mjs/_virtual/setmultimap.js +10 -0
- package/dist/melonjs.mjs/application/application.js +240 -0
- package/dist/melonjs.mjs/audio/audio.js +536 -0
- package/dist/melonjs.mjs/camera/camera2d.js +732 -0
- package/dist/melonjs.mjs/entity/entity.js +248 -0
- package/dist/melonjs.mjs/game.js +29 -0
- package/dist/melonjs.mjs/geometries/ellipse.js +275 -0
- package/dist/melonjs.mjs/geometries/line.js +116 -0
- package/dist/melonjs.mjs/geometries/path2d.js +319 -0
- package/dist/melonjs.mjs/geometries/point.js +89 -0
- package/dist/melonjs.mjs/geometries/poly.js +500 -0
- package/dist/melonjs.mjs/geometries/rectangle.js +375 -0
- package/dist/melonjs.mjs/geometries/roundrect.js +168 -0
- package/dist/melonjs.mjs/index.js +248 -0
- package/dist/melonjs.mjs/input/gamepad.js +501 -0
- package/dist/melonjs.mjs/input/input.js +26 -0
- package/dist/melonjs.mjs/input/keyboard.js +470 -0
- package/dist/melonjs.mjs/input/pointer.js +393 -0
- package/dist/melonjs.mjs/input/pointerevent.js +818 -0
- package/dist/melonjs.mjs/lang/deprecated.js +157 -0
- package/dist/melonjs.mjs/level/level.js +297 -0
- package/dist/melonjs.mjs/level/tiled/TMXGroup.js +141 -0
- package/dist/melonjs.mjs/level/tiled/TMXLayer.js +448 -0
- package/dist/melonjs.mjs/level/tiled/TMXObject.js +355 -0
- package/dist/melonjs.mjs/level/tiled/TMXTile.js +194 -0
- package/dist/melonjs.mjs/level/tiled/TMXTileMap.js +639 -0
- package/dist/melonjs.mjs/level/tiled/TMXTileset.js +311 -0
- package/dist/melonjs.mjs/level/tiled/TMXTilesetGroup.js +83 -0
- package/dist/melonjs.mjs/level/tiled/TMXUtils.js +367 -0
- package/dist/melonjs.mjs/level/tiled/renderer/TMXHexagonalRenderer.js +506 -0
- package/dist/melonjs.mjs/level/tiled/renderer/TMXIsometricRenderer.js +220 -0
- package/dist/melonjs.mjs/level/tiled/renderer/TMXOrthogonalRenderer.js +157 -0
- package/dist/melonjs.mjs/level/tiled/renderer/TMXRenderer.js +125 -0
- package/dist/melonjs.mjs/level/tiled/renderer/TMXStaggeredRenderer.js +109 -0
- package/dist/melonjs.mjs/loader/loader.js +801 -0
- package/dist/melonjs.mjs/loader/loadingscreen.js +120 -0
- package/dist/melonjs.mjs/loader/melonjs_logo.png.js +11 -0
- package/dist/melonjs.mjs/math/color.js +618 -0
- package/dist/melonjs.mjs/math/math.js +218 -0
- package/dist/melonjs.mjs/math/matrix2.js +503 -0
- package/dist/melonjs.mjs/math/matrix3.js +681 -0
- package/dist/melonjs.mjs/math/observable_vector2.js +471 -0
- package/dist/melonjs.mjs/math/observable_vector3.js +561 -0
- package/dist/melonjs.mjs/math/vector2.js +528 -0
- package/dist/melonjs.mjs/math/vector3.js +569 -0
- package/dist/melonjs.mjs/node_modules/@teppeis/multimaps/dist/src/arraymultimap.js +73 -0
- package/dist/melonjs.mjs/node_modules/@teppeis/multimaps/dist/src/index.js +21 -0
- package/dist/melonjs.mjs/node_modules/@teppeis/multimaps/dist/src/multimap.js +324 -0
- package/dist/melonjs.mjs/node_modules/@teppeis/multimaps/dist/src/setmultimap.js +69 -0
- package/dist/melonjs.mjs/node_modules/earcut/src/earcut.js +691 -0
- package/dist/melonjs.mjs/node_modules/eventemitter3/index.js +350 -0
- package/dist/melonjs.mjs/node_modules/howler/dist/howler.js +3241 -0
- package/dist/melonjs.mjs/particles/emitter.js +267 -0
- package/dist/melonjs.mjs/particles/particle.js +188 -0
- package/dist/melonjs.mjs/particles/settings.js +319 -0
- package/dist/melonjs.mjs/physics/body.js +704 -0
- package/dist/melonjs.mjs/physics/bounds.js +460 -0
- package/dist/melonjs.mjs/physics/collision.js +132 -0
- package/dist/melonjs.mjs/physics/detector.js +194 -0
- package/dist/melonjs.mjs/physics/quadtree.js +391 -0
- package/dist/melonjs.mjs/physics/response.js +57 -0
- package/dist/melonjs.mjs/physics/sat.js +483 -0
- package/dist/melonjs.mjs/physics/world.js +221 -0
- package/dist/melonjs.mjs/plugin/plugin.js +141 -0
- package/dist/melonjs.mjs/renderable/collectable.js +62 -0
- package/dist/melonjs.mjs/renderable/colorlayer.js +80 -0
- package/dist/melonjs.mjs/renderable/container.js +1018 -0
- package/dist/melonjs.mjs/renderable/dragndrop.js +224 -0
- package/dist/melonjs.mjs/renderable/imagelayer.js +306 -0
- package/dist/melonjs.mjs/renderable/light2d.js +156 -0
- package/dist/melonjs.mjs/renderable/nineslicesprite.js +247 -0
- package/dist/melonjs.mjs/renderable/renderable.js +783 -0
- package/dist/melonjs.mjs/renderable/sprite.js +654 -0
- package/dist/melonjs.mjs/renderable/trigger.js +157 -0
- package/dist/melonjs.mjs/renderable/ui/uibaseelement.js +213 -0
- package/dist/melonjs.mjs/renderable/ui/uispriteelement.js +226 -0
- package/dist/melonjs.mjs/renderable/ui/uitextbutton.js +128 -0
- package/dist/melonjs.mjs/state/stage.js +237 -0
- package/dist/melonjs.mjs/state/state.js +596 -0
- package/dist/melonjs.mjs/system/device.js +909 -0
- package/dist/melonjs.mjs/system/dom.js +78 -0
- package/dist/melonjs.mjs/system/event.js +537 -0
- package/dist/melonjs.mjs/system/platform.js +41 -0
- package/dist/melonjs.mjs/system/pooling.js +209 -0
- package/dist/melonjs.mjs/system/save.js +157 -0
- package/dist/melonjs.mjs/system/timer.js +286 -0
- package/dist/melonjs.mjs/text/bitmaptext.js +364 -0
- package/dist/melonjs.mjs/text/bitmaptextdata.js +199 -0
- package/dist/melonjs.mjs/text/glyph.js +66 -0
- package/dist/melonjs.mjs/text/text.js +453 -0
- package/dist/melonjs.mjs/text/textmetrics.js +176 -0
- package/dist/melonjs.mjs/text/textstyle.js +23 -0
- package/dist/melonjs.mjs/tweens/easing.js +336 -0
- package/dist/melonjs.mjs/tweens/interpolation.js +112 -0
- package/dist/melonjs.mjs/tweens/tween.js +480 -0
- package/dist/melonjs.mjs/utils/agent.js +76 -0
- package/dist/melonjs.mjs/utils/array.js +63 -0
- package/dist/melonjs.mjs/utils/file.js +42 -0
- package/dist/melonjs.mjs/utils/function.js +70 -0
- package/dist/melonjs.mjs/utils/string.js +82 -0
- package/dist/melonjs.mjs/utils/utils.js +173 -0
- package/dist/melonjs.mjs/video/canvas/canvas_renderer.js +807 -0
- package/dist/melonjs.mjs/video/renderer.js +411 -0
- package/dist/melonjs.mjs/video/texture/atlas.js +519 -0
- package/dist/melonjs.mjs/video/texture/cache.js +143 -0
- package/dist/melonjs.mjs/video/texture/canvas_texture.js +144 -0
- package/dist/melonjs.mjs/video/video.js +462 -0
- package/dist/melonjs.mjs/video/webgl/buffer/vertex.js +143 -0
- package/dist/melonjs.mjs/video/webgl/glshader.js +168 -0
- package/dist/melonjs.mjs/video/webgl/shaders/primitive.frag.js +10 -0
- package/dist/melonjs.mjs/video/webgl/shaders/primitive.vert.js +10 -0
- package/dist/melonjs.mjs/video/webgl/shaders/quad.frag.js +10 -0
- package/dist/melonjs.mjs/video/webgl/shaders/quad.vert.js +10 -0
- package/dist/melonjs.mjs/video/webgl/utils/attributes.js +25 -0
- package/dist/melonjs.mjs/video/webgl/utils/precision.js +20 -0
- package/dist/melonjs.mjs/video/webgl/utils/program.js +67 -0
- package/dist/melonjs.mjs/video/webgl/utils/string.js +25 -0
- package/dist/melonjs.mjs/video/webgl/utils/uniforms.js +92 -0
- package/dist/melonjs.mjs/video/webgl/webgl_compositor.js +495 -0
- package/dist/melonjs.mjs/video/webgl/webgl_renderer.js +1036 -0
- package/dist/melonjs.module.d.ts +1163 -1163
- package/dist/melonjs.module.js +1903 -3274
- package/package.json +22 -17
- package/src/application/application.js +3 -3
- package/src/audio/audio.js +32 -32
- package/src/camera/camera2d.js +31 -31
- package/src/entity/entity.js +17 -17
- package/src/geometries/ellipse.js +16 -16
- package/src/geometries/line.js +5 -5
- package/src/geometries/path2d.js +32 -32
- package/src/geometries/poly.js +15 -15
- package/src/geometries/rectangle.js +18 -18
- package/src/geometries/roundrect.js +8 -8
- package/src/input/gamepad.js +15 -15
- package/src/input/keyboard.js +12 -12
- package/src/input/pointer.js +6 -6
- package/src/input/pointerevent.js +12 -12
- package/src/lang/deprecated.js +12 -12
- package/src/level/level.js +25 -25
- package/src/level/tiled/TMXLayer.js +22 -22
- package/src/level/tiled/TMXTile.js +5 -5
- package/src/level/tiled/TMXTileMap.js +6 -6
- package/src/level/tiled/TMXTileset.js +2 -2
- package/src/level/tiled/TMXUtils.js +5 -5
- package/src/level/tiled/renderer/TMXHexagonalRenderer.js +2 -2
- package/src/level/tiled/renderer/TMXIsometricRenderer.js +2 -2
- package/src/level/tiled/renderer/TMXOrthogonalRenderer.js +1 -1
- package/src/level/tiled/renderer/TMXRenderer.js +19 -19
- package/src/loader/loader.js +20 -20
- package/src/math/color.js +20 -20
- package/src/math/math.js +16 -16
- package/src/math/matrix2.js +16 -16
- package/src/math/matrix3.js +25 -25
- package/src/math/observable_vector2.js +14 -14
- package/src/math/observable_vector3.js +16 -16
- package/src/math/vector2.js +9 -9
- package/src/math/vector3.js +10 -10
- package/src/particles/emitter.js +6 -6
- package/src/particles/particle.js +2 -2
- package/src/physics/body.js +28 -28
- package/src/physics/bounds.js +8 -8
- package/src/physics/collision.js +2 -2
- package/src/physics/detector.js +6 -6
- package/src/physics/quadtree.js +11 -11
- package/src/physics/sat.js +31 -31
- package/src/physics/world.js +5 -5
- package/src/plugin/plugin.js +5 -5
- package/src/renderable/collectable.js +3 -3
- package/src/renderable/colorlayer.js +5 -5
- package/src/renderable/container.js +21 -21
- package/src/renderable/dragndrop.js +14 -14
- package/src/renderable/imagelayer.js +13 -13
- package/src/renderable/light2d.js +3 -3
- package/src/renderable/nineslicesprite.js +16 -16
- package/src/renderable/renderable.js +23 -23
- package/src/renderable/sprite.js +28 -28
- package/src/renderable/trigger.js +15 -15
- package/src/renderable/ui/uibaseelement.js +7 -7
- package/src/renderable/ui/uispriteelement.js +6 -6
- package/src/renderable/ui/uitextbutton.js +13 -13
- package/src/state/stage.js +7 -7
- package/src/state/state.js +17 -17
- package/src/system/device.js +11 -11
- package/src/system/event.js +10 -10
- package/src/system/pooling.js +9 -9
- package/src/system/save.js +2 -2
- package/src/system/timer.js +10 -10
- package/src/text/bitmaptext.js +18 -18
- package/src/text/bitmaptextdata.js +2 -2
- package/src/text/text.js +23 -23
- package/src/text/textmetrics.js +8 -8
- package/src/tweens/tween.js +19 -19
- package/src/utils/agent.js +5 -5
- package/src/utils/array.js +4 -4
- package/src/utils/file.js +2 -2
- package/src/utils/function.js +6 -6
- package/src/utils/string.js +5 -5
- package/src/utils/utils.js +4 -4
- package/src/video/canvas/canvas_renderer.js +70 -70
- package/src/video/renderer.js +26 -26
- package/src/video/texture/atlas.js +22 -22
- package/src/video/texture/canvas_texture.js +9 -9
- package/src/video/video.js +17 -17
- package/src/video/webgl/glshader.js +10 -10
- package/src/video/webgl/webgl_compositor.js +41 -41
- package/src/video/webgl/webgl_renderer.js +75 -75
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* melonJS Game Engine - v14.1.0
|
|
3
|
+
* http://www.melonjs.org
|
|
4
|
+
* melonjs is licensed under the MIT License.
|
|
5
|
+
* http://www.opensource.org/licenses/mit-license
|
|
6
|
+
* @copyright (C) 2011 - 2022 Olivier Biot (AltByte Pte Ltd)
|
|
7
|
+
*/
|
|
8
|
+
import * as sat from './sat.js';
|
|
9
|
+
import ResponseObject from './response.js';
|
|
10
|
+
import Vector2d from '../math/vector2.js';
|
|
11
|
+
import game from '../game.js';
|
|
12
|
+
import Bounds from './bounds.js';
|
|
13
|
+
|
|
14
|
+
// a dummy object when using Line for raycasting
|
|
15
|
+
let dummyObj = {
|
|
16
|
+
pos : new Vector2d(0, 0),
|
|
17
|
+
ancestor : {
|
|
18
|
+
_absPos : new Vector2d(0, 0),
|
|
19
|
+
getAbsolutePosition : function () {
|
|
20
|
+
return this._absPos;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
let boundsA = new Bounds();
|
|
26
|
+
let boundsB = new Bounds();
|
|
27
|
+
|
|
28
|
+
// the global response object used for collisions
|
|
29
|
+
let globalResponse = new ResponseObject();
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* a function used to determine if two objects should collide (based on both respective objects collision mask and type).<br>
|
|
33
|
+
* you can redefine this function if you need any specific rules over what should collide with what.
|
|
34
|
+
* @name shouldCollide
|
|
35
|
+
* @memberof collision
|
|
36
|
+
* @ignore
|
|
37
|
+
* @param {Renderable} a - a reference to the object A.
|
|
38
|
+
* @param {Renderable} b - a reference to the object B.
|
|
39
|
+
* @returns {boolean} true if they should collide, false otherwise
|
|
40
|
+
*/
|
|
41
|
+
function shouldCollide(a, b) {
|
|
42
|
+
var bodyA = a.body,
|
|
43
|
+
bodyB = b.body;
|
|
44
|
+
return (
|
|
45
|
+
a !== b &&
|
|
46
|
+
a.isKinematic !== true && b.isKinematic !== true &&
|
|
47
|
+
typeof bodyA === "object" && typeof bodyB === "object" &&
|
|
48
|
+
bodyA.shapes.length > 0 && bodyB.shapes.length > 0 &&
|
|
49
|
+
!(bodyA.isStatic === true && bodyB.isStatic === true) &&
|
|
50
|
+
(bodyA.collisionMask & bodyB.collisionType) !== 0 &&
|
|
51
|
+
(bodyA.collisionType & bodyB.collisionMask) !== 0
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* find all the collisions for the specified object
|
|
59
|
+
* @name collisionCheck
|
|
60
|
+
* @ignore
|
|
61
|
+
* @param {Renderable} objA - object to be tested for collision
|
|
62
|
+
* @param {ResponseObject} [response] - a user defined response object that will be populated if they intersect.
|
|
63
|
+
* @returns {boolean} in case of collision, false otherwise
|
|
64
|
+
*/
|
|
65
|
+
function collisionCheck(objA, response = globalResponse) {
|
|
66
|
+
var collisionCounter = 0;
|
|
67
|
+
// retreive a list of potential colliding objects from the game world
|
|
68
|
+
var candidates = game.world.broadphase.retrieve(objA);
|
|
69
|
+
|
|
70
|
+
boundsA.addBounds(objA.getBounds(), true);
|
|
71
|
+
boundsA.addBounds(objA.body.getBounds());
|
|
72
|
+
|
|
73
|
+
candidates.forEach((objB) => {
|
|
74
|
+
// check if both objects "should" collide
|
|
75
|
+
if (shouldCollide(objA, objB)) {
|
|
76
|
+
|
|
77
|
+
boundsB.addBounds(objB.getBounds(), true);
|
|
78
|
+
boundsB.addBounds(objB.body.getBounds());
|
|
79
|
+
|
|
80
|
+
// fast AABB check if both bounding boxes are overlaping
|
|
81
|
+
if (boundsA.overlaps(boundsB)) {
|
|
82
|
+
// for each shape in body A
|
|
83
|
+
objA.body.shapes.forEach((shapeA, indexA) => {
|
|
84
|
+
// for each shape in body B
|
|
85
|
+
objB.body.shapes.forEach((shapeB, indexB) => {
|
|
86
|
+
// full SAT collision check
|
|
87
|
+
if (sat["test" + shapeA.shapeType + shapeB.shapeType].call(
|
|
88
|
+
this,
|
|
89
|
+
objA, // a reference to the object A
|
|
90
|
+
shapeA,
|
|
91
|
+
objB, // a reference to the object B
|
|
92
|
+
shapeB,
|
|
93
|
+
// clear response object before reusing
|
|
94
|
+
response.clear()) === true
|
|
95
|
+
) {
|
|
96
|
+
// we touched something !
|
|
97
|
+
collisionCounter++;
|
|
98
|
+
|
|
99
|
+
// set the shape index
|
|
100
|
+
response.indexShapeA = indexA;
|
|
101
|
+
response.indexShapeB = indexB;
|
|
102
|
+
|
|
103
|
+
// execute the onCollision callback
|
|
104
|
+
if (objA.onCollision && objA.onCollision(response, objB) !== false && objA.body.isStatic === false) {
|
|
105
|
+
objA.body.respondToCollision.call(objA.body, response);
|
|
106
|
+
}
|
|
107
|
+
if (objB.onCollision && objB.onCollision(response, objA) !== false && objB.body.isStatic === false) {
|
|
108
|
+
objB.body.respondToCollision.call(objB.body, response);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
// we could return the amount of objects we collided with ?
|
|
117
|
+
return collisionCounter > 0;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Checks for object colliding with the given line
|
|
122
|
+
* @name rayCast
|
|
123
|
+
* @ignore
|
|
124
|
+
* @param {Line} line - line to be tested for collision
|
|
125
|
+
* @param {Array.<Renderable>} [result] - a user defined array that will be populated with intersecting physic objects.
|
|
126
|
+
* @returns {Array.<Renderable>} an array of intersecting physic objects
|
|
127
|
+
* @example
|
|
128
|
+
* // define a line accross the viewport
|
|
129
|
+
* var ray = new me.Line(
|
|
130
|
+
* // absolute position of the line
|
|
131
|
+
* 0, 0, [
|
|
132
|
+
* // starting point relative to the initial position
|
|
133
|
+
* new me.Vector2d(0, 0),
|
|
134
|
+
* // ending point
|
|
135
|
+
* new me.Vector2d(me.game.viewport.width, me.game.viewport.height)
|
|
136
|
+
* ]);
|
|
137
|
+
*
|
|
138
|
+
* // check for collition
|
|
139
|
+
* result = me.collision.rayCast(ray);
|
|
140
|
+
*
|
|
141
|
+
* if (result.length > 0) {
|
|
142
|
+
* // ...
|
|
143
|
+
* }
|
|
144
|
+
*/
|
|
145
|
+
function rayCast(line, result = []) {
|
|
146
|
+
var collisionCounter = 0;
|
|
147
|
+
|
|
148
|
+
// retrieve a list of potential colliding objects from the game world
|
|
149
|
+
var candidates = game.world.broadphase.retrieve(line);
|
|
150
|
+
|
|
151
|
+
for (var i = candidates.length, objB; i--, (objB = candidates[i]);) {
|
|
152
|
+
|
|
153
|
+
// fast AABB check if both bounding boxes are overlaping
|
|
154
|
+
if (objB.body && line.getBounds().overlaps(objB.getBounds())) {
|
|
155
|
+
|
|
156
|
+
// go trough all defined shapes in B (if any)
|
|
157
|
+
var bLen = objB.body.shapes.length;
|
|
158
|
+
if ( objB.body.shapes.length === 0) {
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
var shapeA = line;
|
|
163
|
+
|
|
164
|
+
// go through all defined shapes in B
|
|
165
|
+
var indexB = 0;
|
|
166
|
+
do {
|
|
167
|
+
var shapeB = objB.body.getShape(indexB);
|
|
168
|
+
|
|
169
|
+
// full SAT collision check
|
|
170
|
+
if (sat["test" + shapeA.shapeType + shapeB.shapeType]
|
|
171
|
+
.call(
|
|
172
|
+
this,
|
|
173
|
+
dummyObj, // a reference to the object A
|
|
174
|
+
shapeA,
|
|
175
|
+
objB, // a reference to the object B
|
|
176
|
+
shapeB
|
|
177
|
+
)) {
|
|
178
|
+
// we touched something !
|
|
179
|
+
result[collisionCounter] = objB;
|
|
180
|
+
collisionCounter++;
|
|
181
|
+
}
|
|
182
|
+
indexB++;
|
|
183
|
+
} while (indexB < bLen);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// cap result in case it was not empty
|
|
188
|
+
result.length = collisionCounter;
|
|
189
|
+
|
|
190
|
+
// return the list of colliding objects
|
|
191
|
+
return result;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
export { collisionCheck, rayCast };
|
|
@@ -0,0 +1,391 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* melonJS Game Engine - v14.1.0
|
|
3
|
+
* http://www.melonjs.org
|
|
4
|
+
* melonjs is licensed under the MIT License.
|
|
5
|
+
* http://www.opensource.org/licenses/mit-license
|
|
6
|
+
* @copyright (C) 2011 - 2022 Olivier Biot (AltByte Pte Ltd)
|
|
7
|
+
*/
|
|
8
|
+
import Vector2d from '../math/vector2.js';
|
|
9
|
+
import Container from '../renderable/container.js';
|
|
10
|
+
import { remove } from '../utils/array.js';
|
|
11
|
+
|
|
12
|
+
/*
|
|
13
|
+
* A QuadTree implementation in JavaScript, a 2d spatial subdivision algorithm.
|
|
14
|
+
* Based on the QuadTree Library by Timo Hausmann and released under the MIT license
|
|
15
|
+
* https://github.com/timohausmann/quadtree-js/
|
|
16
|
+
**/
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* a pool of `QuadTree` objects
|
|
21
|
+
* @ignore
|
|
22
|
+
*/
|
|
23
|
+
var QT_ARRAY = [];
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* will pop a quadtree object from the array
|
|
27
|
+
* or create a new one if the array is empty
|
|
28
|
+
* @ignore
|
|
29
|
+
*/
|
|
30
|
+
function QT_ARRAY_POP(world, bounds, max_objects = 4, max_levels = 4, level = 0) {
|
|
31
|
+
if (QT_ARRAY.length > 0) {
|
|
32
|
+
var _qt = QT_ARRAY.pop();
|
|
33
|
+
_qt.world = world;
|
|
34
|
+
_qt.bounds = bounds;
|
|
35
|
+
_qt.max_objects = max_objects;
|
|
36
|
+
_qt.max_levels = max_levels;
|
|
37
|
+
_qt.level = level;
|
|
38
|
+
return _qt;
|
|
39
|
+
} else {
|
|
40
|
+
return new QuadTree(world, bounds, max_objects, max_levels, level);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Push back a quadtree back into the array
|
|
46
|
+
* @ignore
|
|
47
|
+
*/
|
|
48
|
+
function QT_ARRAY_PUSH(qt) {
|
|
49
|
+
QT_ARRAY.push(qt);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* a temporary vector object to be reused
|
|
54
|
+
* @ignore
|
|
55
|
+
*/
|
|
56
|
+
var QT_VECTOR = new Vector2d();
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* @classdesc
|
|
60
|
+
* a QuadTree implementation in JavaScript, a 2d spatial subdivision algorithm.
|
|
61
|
+
* @see game.world.broadphase
|
|
62
|
+
*/
|
|
63
|
+
class QuadTree {
|
|
64
|
+
/**
|
|
65
|
+
* @param {World} world - the physic world this QuadTree belongs to
|
|
66
|
+
* @param {Bounds} bounds - bounds of the node
|
|
67
|
+
* @param {number} [max_objects=4] - max objects a node can hold before splitting into 4 subnodes
|
|
68
|
+
* @param {number} [max_levels=4] - total max levels inside root Quadtree
|
|
69
|
+
* @param {number} [level] - deepth level, required for subnodes
|
|
70
|
+
*/
|
|
71
|
+
constructor(world, bounds, max_objects = 4, max_levels = 4, level = 0) {
|
|
72
|
+
|
|
73
|
+
this.world = world;
|
|
74
|
+
this.bounds = bounds;
|
|
75
|
+
|
|
76
|
+
this.max_objects = max_objects;
|
|
77
|
+
this.max_levels = max_levels;
|
|
78
|
+
|
|
79
|
+
this.level = level;
|
|
80
|
+
this.bounds = bounds;
|
|
81
|
+
|
|
82
|
+
this.objects = [];
|
|
83
|
+
this.nodes = [];
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/*
|
|
87
|
+
* Split the node into 4 subnodes
|
|
88
|
+
*/
|
|
89
|
+
split() {
|
|
90
|
+
this.level + 1;
|
|
91
|
+
var subWidth = this.bounds.width / 2,
|
|
92
|
+
subHeight = this.bounds.height / 2,
|
|
93
|
+
left = this.bounds.left,
|
|
94
|
+
top = this.bounds.top;
|
|
95
|
+
|
|
96
|
+
//top right node
|
|
97
|
+
this.nodes[0] = QT_ARRAY_POP(
|
|
98
|
+
this.world,
|
|
99
|
+
this.bounds, {
|
|
100
|
+
left : left + subWidth,
|
|
101
|
+
top : top,
|
|
102
|
+
width : subWidth,
|
|
103
|
+
height : subHeight
|
|
104
|
+
},
|
|
105
|
+
this.max_objects,
|
|
106
|
+
this.max_levels);
|
|
107
|
+
|
|
108
|
+
//top left node
|
|
109
|
+
this.nodes[1] = QT_ARRAY_POP(
|
|
110
|
+
this.world,
|
|
111
|
+
this.bounds, {
|
|
112
|
+
left : left,
|
|
113
|
+
top: top,
|
|
114
|
+
width : subWidth,
|
|
115
|
+
height : subHeight
|
|
116
|
+
},
|
|
117
|
+
this.max_objects,
|
|
118
|
+
this.max_levels);
|
|
119
|
+
|
|
120
|
+
//bottom left node
|
|
121
|
+
this.nodes[2] = QT_ARRAY_POP(
|
|
122
|
+
this.world,
|
|
123
|
+
this.bounds, {
|
|
124
|
+
left : left,
|
|
125
|
+
top : top + subHeight,
|
|
126
|
+
width : subWidth,
|
|
127
|
+
height : subHeight
|
|
128
|
+
},
|
|
129
|
+
this.max_objects,
|
|
130
|
+
this.max_levels);
|
|
131
|
+
|
|
132
|
+
//bottom right node
|
|
133
|
+
this.nodes[3] = QT_ARRAY_POP(
|
|
134
|
+
this.world,
|
|
135
|
+
this.bounds, {
|
|
136
|
+
left : left + subWidth,
|
|
137
|
+
top : top + subHeight,
|
|
138
|
+
width : subWidth,
|
|
139
|
+
height : subHeight
|
|
140
|
+
},
|
|
141
|
+
this.max_objects,
|
|
142
|
+
this.max_levels);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/*
|
|
146
|
+
* Determine which node the object belongs to
|
|
147
|
+
* @param {Rect} rect bounds of the area to be checked
|
|
148
|
+
* @returns Integer index of the subnode (0-3), or -1 if rect cannot completely fit within a subnode and is part of the parent node
|
|
149
|
+
*/
|
|
150
|
+
getIndex(item) {
|
|
151
|
+
var pos;
|
|
152
|
+
var bounds = item.getBounds();
|
|
153
|
+
|
|
154
|
+
// use game world coordinates for floating items
|
|
155
|
+
if (item.isFloating === true) {
|
|
156
|
+
pos = this.world.app.viewport.localToWorld(bounds.left, bounds.top, QT_VECTOR);
|
|
157
|
+
} else {
|
|
158
|
+
pos = QT_VECTOR.set(bounds.left, bounds.top);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
var index = -1,
|
|
162
|
+
rx = pos.x,
|
|
163
|
+
ry = pos.y,
|
|
164
|
+
rw = bounds.width,
|
|
165
|
+
rh = bounds.height,
|
|
166
|
+
verticalMidpoint = this.bounds.left + (this.bounds.width / 2),
|
|
167
|
+
horizontalMidpoint = this.bounds.top + (this.bounds.height / 2),
|
|
168
|
+
//rect can completely fit within the top quadrants
|
|
169
|
+
topQuadrant = (ry < horizontalMidpoint && ry + rh < horizontalMidpoint),
|
|
170
|
+
//rect can completely fit within the bottom quadrants
|
|
171
|
+
bottomQuadrant = (ry > horizontalMidpoint);
|
|
172
|
+
|
|
173
|
+
//rect can completely fit within the left quadrants
|
|
174
|
+
if (rx < verticalMidpoint && rx + rw < verticalMidpoint) {
|
|
175
|
+
if (topQuadrant) {
|
|
176
|
+
index = 1;
|
|
177
|
+
} else if (bottomQuadrant) {
|
|
178
|
+
index = 2;
|
|
179
|
+
}
|
|
180
|
+
} else if (rx > verticalMidpoint) {
|
|
181
|
+
//rect can completely fit within the right quadrants
|
|
182
|
+
if (topQuadrant) {
|
|
183
|
+
index = 0;
|
|
184
|
+
} else if (bottomQuadrant) {
|
|
185
|
+
index = 3;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
return index;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Insert the given object container into the node.
|
|
194
|
+
* @name insertContainer
|
|
195
|
+
* @memberof QuadTree
|
|
196
|
+
* @param {Container} container - group of objects to be added
|
|
197
|
+
*/
|
|
198
|
+
insertContainer(container) {
|
|
199
|
+
for (var i = container.children.length, child; i--, (child = container.children[i]);) {
|
|
200
|
+
if (child.isKinematic !== true) {
|
|
201
|
+
if (child instanceof Container) {
|
|
202
|
+
if (child.name !== "rootContainer") {
|
|
203
|
+
this.insert(child);
|
|
204
|
+
}
|
|
205
|
+
// recursivly insert all childs
|
|
206
|
+
this.insertContainer(child);
|
|
207
|
+
} else {
|
|
208
|
+
// only insert object with a bounding box
|
|
209
|
+
// Probably redundant with `isKinematic`
|
|
210
|
+
if (typeof (child.getBounds) === "function") {
|
|
211
|
+
this.insert(child);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Insert the given object into the node. If the node
|
|
220
|
+
* exceeds the capacity, it will split and add all
|
|
221
|
+
* objects to their corresponding subnodes.
|
|
222
|
+
* @name insert
|
|
223
|
+
* @memberof QuadTree
|
|
224
|
+
* @param {object} item - object to be added
|
|
225
|
+
*/
|
|
226
|
+
insert(item) {
|
|
227
|
+
var index = -1;
|
|
228
|
+
|
|
229
|
+
//if we have subnodes ...
|
|
230
|
+
if (this.nodes.length > 0) {
|
|
231
|
+
index = this.getIndex(item);
|
|
232
|
+
|
|
233
|
+
if (index !== -1) {
|
|
234
|
+
this.nodes[index].insert(item);
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
this.objects.push(item);
|
|
240
|
+
|
|
241
|
+
if (this.objects.length > this.max_objects && this.level < this.max_levels) {
|
|
242
|
+
|
|
243
|
+
//split if we don't already have subnodes
|
|
244
|
+
if (this.nodes.length === 0) {
|
|
245
|
+
this.split();
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
var i = 0;
|
|
249
|
+
|
|
250
|
+
//add all objects to there corresponding subnodes
|
|
251
|
+
while (i < this.objects.length) {
|
|
252
|
+
|
|
253
|
+
index = this.getIndex(this.objects[i]);
|
|
254
|
+
|
|
255
|
+
if (index !== -1) {
|
|
256
|
+
this.nodes[index].insert(this.objects.splice(i, 1)[0]);
|
|
257
|
+
} else {
|
|
258
|
+
i = i + 1;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Return all objects that could collide with the given object
|
|
266
|
+
* @name retrieve
|
|
267
|
+
* @memberof QuadTree
|
|
268
|
+
* @param {object} item - object to be checked against
|
|
269
|
+
* @param {object} [fn] - a sorting function for the returned array
|
|
270
|
+
* @returns {object[]} array with all detected objects
|
|
271
|
+
*/
|
|
272
|
+
retrieve(item, fn) {
|
|
273
|
+
var returnObjects = this.objects;
|
|
274
|
+
|
|
275
|
+
//if we have subnodes ...
|
|
276
|
+
if (this.nodes.length > 0) {
|
|
277
|
+
|
|
278
|
+
var index = this.getIndex(item);
|
|
279
|
+
|
|
280
|
+
//if rect fits into a subnode ..
|
|
281
|
+
if (index !== -1) {
|
|
282
|
+
returnObjects = returnObjects.concat(this.nodes[index].retrieve(item));
|
|
283
|
+
} else {
|
|
284
|
+
//if rect does not fit into a subnode, check it against all subnodes
|
|
285
|
+
for (var i = 0; i < this.nodes.length; i = i + 1) {
|
|
286
|
+
returnObjects = returnObjects.concat(this.nodes[i].retrieve(item));
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
if (typeof(fn) === "function") {
|
|
292
|
+
returnObjects.sort(fn);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
return returnObjects;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* Remove the given item from the quadtree.
|
|
300
|
+
* (this function won't recalculate the impacted node)
|
|
301
|
+
* @name remove
|
|
302
|
+
* @memberof QuadTree
|
|
303
|
+
* @param {object} item - object to be removed
|
|
304
|
+
* @returns {boolean} true if the item was found and removed.
|
|
305
|
+
*/
|
|
306
|
+
remove(item) {
|
|
307
|
+
var found = false;
|
|
308
|
+
|
|
309
|
+
if (typeof (item.getBounds) === "undefined") {
|
|
310
|
+
// ignore object that cannot be added in the first place
|
|
311
|
+
return false;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
//if we have subnodes ...
|
|
315
|
+
if (this.nodes.length > 0) {
|
|
316
|
+
// determine to which node the item belongs to
|
|
317
|
+
var index = this.getIndex(item);
|
|
318
|
+
|
|
319
|
+
if (index !== -1) {
|
|
320
|
+
found = remove(this.nodes[index], item);
|
|
321
|
+
// trim node if empty
|
|
322
|
+
if (found && this.nodes[index].isPrunable()) {
|
|
323
|
+
this.nodes.splice(index, 1);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
if (found === false) {
|
|
329
|
+
// try and remove the item from the list of items in this node
|
|
330
|
+
if (this.objects.indexOf(item) !== -1) {
|
|
331
|
+
remove(this.objects, item);
|
|
332
|
+
found = true;
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
return found;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* return true if the node is prunable
|
|
341
|
+
* @name isPrunable
|
|
342
|
+
* @memberof QuadTree
|
|
343
|
+
* @returns {boolean} true if the node is prunable
|
|
344
|
+
*/
|
|
345
|
+
isPrunable() {
|
|
346
|
+
return !(this.hasChildren() || (this.objects.length > 0));
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
/**
|
|
350
|
+
* return true if the node has any children
|
|
351
|
+
* @name hasChildren
|
|
352
|
+
* @memberof QuadTree
|
|
353
|
+
* @returns {boolean} true if the node has any children
|
|
354
|
+
*/
|
|
355
|
+
hasChildren() {
|
|
356
|
+
for (var i = 0; i < this.nodes.length; i = i + 1) {
|
|
357
|
+
var subnode = this.nodes[i];
|
|
358
|
+
if (subnode.length > 0 || subnode.objects.length > 0) {
|
|
359
|
+
return true;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
return false;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
/**
|
|
366
|
+
* clear the quadtree
|
|
367
|
+
* @name clear
|
|
368
|
+
* @memberof QuadTree
|
|
369
|
+
* @param {Bounds} [bounds=this.bounds] - the bounds to be cleared
|
|
370
|
+
*/
|
|
371
|
+
clear(bounds) {
|
|
372
|
+
this.objects.length = 0;
|
|
373
|
+
|
|
374
|
+
for (var i = 0; i < this.nodes.length; i++) {
|
|
375
|
+
this.nodes[i].clear();
|
|
376
|
+
// recycle the quadTree object
|
|
377
|
+
QT_ARRAY_PUSH(this.nodes[i]);
|
|
378
|
+
}
|
|
379
|
+
// empty the array
|
|
380
|
+
this.nodes.length = 0;
|
|
381
|
+
|
|
382
|
+
// resize the root bounds if required
|
|
383
|
+
if (typeof bounds !== "undefined") {
|
|
384
|
+
this.bounds.setMinMax(bounds.min.x, bounds.min.y, bounds.max.x, bounds.max.y);
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
var QuadTree$1 = QuadTree;
|
|
390
|
+
|
|
391
|
+
export { QuadTree$1 as default };
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* melonJS Game Engine - v14.1.0
|
|
3
|
+
* http://www.melonjs.org
|
|
4
|
+
* melonjs is licensed under the MIT License.
|
|
5
|
+
* http://www.opensource.org/licenses/mit-license
|
|
6
|
+
* @copyright (C) 2011 - 2022 Olivier Biot (AltByte Pte Ltd)
|
|
7
|
+
*/
|
|
8
|
+
import Vector2d from '../math/vector2.js';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @classdesc
|
|
12
|
+
* An object representing the result of an intersection.
|
|
13
|
+
* @property {Renderable} a The first object participating in the intersection
|
|
14
|
+
* @property {Renderable} b The second object participating in the intersection
|
|
15
|
+
* @property {number} overlap Magnitude of the overlap on the shortest colliding axis
|
|
16
|
+
* @property {Vector2d} overlapV The overlap vector (i.e. `overlapN.scale(overlap, overlap)`). If this vector is subtracted from the position of a, a and b will no longer be colliding
|
|
17
|
+
* @property {Vector2d} overlapN The shortest colliding axis (unit-vector)
|
|
18
|
+
* @property {boolean} aInB Whether the first object is entirely inside the second
|
|
19
|
+
* @property {boolean} bInA Whether the second object is entirely inside the first
|
|
20
|
+
* @property {number} indexShapeA The index of the colliding shape for the object a body
|
|
21
|
+
* @property {number} indexShapeB The index of the colliding shape for the object b body
|
|
22
|
+
* @name ResponseObject
|
|
23
|
+
* @public
|
|
24
|
+
*/
|
|
25
|
+
class ResponseObject {
|
|
26
|
+
constructor() {
|
|
27
|
+
this.a = null;
|
|
28
|
+
this.b = null;
|
|
29
|
+
this.overlapN = new Vector2d();
|
|
30
|
+
this.overlapV = new Vector2d();
|
|
31
|
+
this.aInB = true;
|
|
32
|
+
this.bInA = true;
|
|
33
|
+
this.indexShapeA = -1;
|
|
34
|
+
this.indexShapeB = -1;
|
|
35
|
+
this.overlap = Number.MAX_VALUE;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Set some values of the response back to their defaults. <br>
|
|
40
|
+
* Call this between tests if you are going to reuse a single <br>
|
|
41
|
+
* Response object for multiple intersection tests <br>
|
|
42
|
+
* (recommended as it will avoid allocating extra memory) <br>
|
|
43
|
+
* @name clear
|
|
44
|
+
* @public
|
|
45
|
+
* @returns {object} this object for chaining
|
|
46
|
+
*/
|
|
47
|
+
clear () {
|
|
48
|
+
this.aInB = true;
|
|
49
|
+
this.bInA = true;
|
|
50
|
+
this.overlap = Number.MAX_VALUE;
|
|
51
|
+
this.indexShapeA = -1;
|
|
52
|
+
this.indexShapeB = -1;
|
|
53
|
+
return this;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export { ResponseObject as default };
|