emeraldengine 2.2.1 → 3.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 +2198 -968
- package/dist/types/index.d.ts +75 -32
- package/dist/types/src/Animator.d.ts +50 -0
- package/dist/types/{BitmapText.d.ts → src/BitmapText.d.ts} +19 -21
- package/dist/types/src/Camera.d.ts +122 -0
- package/dist/types/src/CameraController.d.ts +107 -0
- package/dist/types/src/CanvasText.d.ts +91 -0
- package/dist/types/src/CollisionLayers.d.ts +58 -0
- package/dist/types/{Color.d.ts → src/Color.d.ts} +6 -6
- package/dist/types/src/Coroutine.d.ts +111 -0
- package/dist/types/src/DebugOverlay.d.ts +86 -0
- package/dist/types/src/Drawable.d.ts +271 -0
- package/dist/types/src/Easing.d.ts +22 -0
- package/dist/types/src/Emerald.d.ts +420 -0
- package/dist/types/src/EmeraldDB.d.ts +159 -0
- package/dist/types/{FPSCounter.d.ts → src/FPSCounter.d.ts} +1 -3
- package/dist/types/src/GLUtils.d.ts +4 -0
- package/dist/types/{Instance.d.ts → src/Instance.d.ts} +37 -15
- package/dist/types/{InstancedTexture.d.ts → src/InstancedTexture.d.ts} +75 -23
- package/dist/types/src/Interpolator.d.ts +66 -0
- package/dist/types/src/Material.d.ts +87 -0
- package/dist/types/src/MathUtils.d.ts +81 -0
- package/dist/types/src/ParticleEmitter.d.ts +131 -0
- package/dist/types/src/Physics.d.ts +337 -0
- package/dist/types/src/Pool.d.ts +53 -0
- package/dist/types/src/PostEffects.d.ts +68 -0
- package/dist/types/src/PostProcessor.d.ts +124 -0
- package/dist/types/src/RenderTarget.d.ts +56 -0
- package/dist/types/src/Scene.d.ts +62 -0
- package/dist/types/src/ScreenEffects.d.ts +111 -0
- package/dist/types/src/Serializer.d.ts +86 -0
- package/dist/types/src/Shaders.d.ts +2 -0
- package/dist/types/{Shapes.d.ts → src/Shapes.d.ts} +4 -6
- package/dist/types/src/SpatialGrid.d.ts +50 -0
- package/dist/types/src/SpriteBatch.d.ts +89 -0
- package/dist/types/src/StateMachine.d.ts +59 -0
- package/dist/types/src/Storage.d.ts +89 -0
- package/dist/types/{Texture.d.ts → src/Texture.d.ts} +3 -4
- package/dist/types/src/TextureAtlas.d.ts +55 -0
- package/dist/types/src/Tilemap.d.ts +91 -0
- package/dist/types/src/Time.d.ts +53 -0
- package/dist/types/src/Timer.d.ts +54 -0
- package/dist/types/src/Transform.d.ts +94 -0
- package/dist/types/src/Tween.d.ts +81 -0
- package/dist/types/src/UI.d.ts +121 -0
- package/dist/types/src/components/Behaviour.d.ts +71 -0
- package/dist/types/{components → src/components}/BoxCollider.d.ts +14 -14
- package/dist/types/src/components/BoxColliderDebug.d.ts +15 -0
- package/dist/types/{components → src/components}/CircleCollider.d.ts +14 -12
- package/dist/types/src/components/CircleColliderDebug.d.ts +15 -0
- package/dist/types/src/components/Collider.d.ts +102 -0
- package/dist/types/src/components/GameObject.d.ts +135 -0
- package/dist/types/src/components/PolygonCollider.d.ts +33 -0
- package/dist/types/src/components/RigidBody.d.ts +456 -0
- package/dist/types/src/importers/Aseprite.d.ts +79 -0
- package/dist/types/src/importers/ForgeLevel.d.ts +97 -0
- package/dist/types/src/importers/TiledMap.d.ts +62 -0
- package/dist/types/{lights → src/lights}/DirectionalLight.d.ts +7 -9
- package/dist/types/{lights → src/lights}/PointLight.d.ts +6 -9
- package/dist/types/src/managers/AssetManager.d.ts +116 -0
- package/dist/types/src/managers/AudioManager.d.ts +259 -0
- package/dist/types/{managers → src/managers}/CameraManager.d.ts +8 -8
- package/dist/types/{managers → src/managers}/EventManager.d.ts +46 -32
- package/dist/types/src/managers/GLManager.d.ts +84 -0
- package/dist/types/src/managers/GLState.d.ts +37 -0
- package/dist/types/src/managers/Gamepad.d.ts +102 -0
- package/dist/types/src/managers/IDManager.d.ts +31 -0
- package/dist/types/src/managers/InputManager.d.ts +381 -0
- package/dist/types/src/managers/NetworkManager.d.ts +93 -0
- package/dist/types/src/managers/RenderStats.d.ts +34 -0
- package/dist/types/src/managers/SceneManager.d.ts +44 -0
- package/dist/types/src/managers/ShaderManager.d.ts +55 -0
- package/dist/types/src/managers/TextureManager.d.ts +102 -0
- package/dist/types/src/particlesystem/Particle.d.ts +64 -0
- package/dist/types/{particlesystem → src/particlesystem}/ParticleSettings.d.ts +32 -24
- package/dist/types/{particlesystem → src/particlesystem}/Particles.d.ts +20 -12
- package/dist/types/src/physics/AABB.d.ts +92 -0
- package/dist/types/src/physics/Body.d.ts +435 -0
- package/dist/types/src/physics/BodyType.d.ts +6 -0
- package/dist/types/src/physics/BroadPhase.d.ts +210 -0
- package/dist/types/src/physics/Collision.d.ts +102 -0
- package/dist/types/src/physics/Contact.d.ts +206 -0
- package/dist/types/src/physics/ContactSolver.d.ts +108 -0
- package/dist/types/src/physics/Distance.d.ts +54 -0
- package/dist/types/src/physics/DistanceJoint.d.ts +90 -0
- package/dist/types/src/physics/Fixture.d.ts +221 -0
- package/dist/types/src/physics/Island.d.ts +52 -0
- package/dist/types/src/physics/Joint.d.ts +59 -0
- package/dist/types/src/physics/Math2D.d.ts +371 -0
- package/dist/types/src/physics/RevoluteJoint.d.ts +119 -0
- package/dist/types/src/physics/Settings.d.ts +22 -0
- package/dist/types/src/physics/Shapes.d.ts +207 -0
- package/dist/types/src/physics/TimeOfImpact.d.ts +22 -0
- package/dist/types/src/physics/World.d.ts +274 -0
- package/dist/types/src/physics/index.d.ts +34 -0
- package/index.js +78 -0
- package/package.json +73 -60
- package/src/Animator.js +95 -0
- package/src/BitmapText.js +6 -5
- package/src/Camera.js +183 -0
- package/src/CameraController.js +192 -0
- package/src/CanvasText.js +281 -0
- package/src/CollisionLayers.js +86 -0
- package/src/Color.js +26 -18
- package/src/Coroutine.js +259 -0
- package/src/DebugOverlay.js +246 -0
- package/src/Drawable.js +842 -582
- package/src/Easing.js +57 -0
- package/src/Emerald.js +1150 -459
- package/src/EmeraldDB.js +328 -0
- package/src/FPSCounter.js +43 -43
- package/src/GLUtils.js +60 -67
- package/src/Instance.js +41 -5
- package/src/InstancedTexture.js +308 -127
- package/src/Interpolator.js +124 -0
- package/src/Material.js +202 -0
- package/src/MathUtils.js +134 -0
- package/src/ParticleEmitter.js +284 -0
- package/src/Physics.js +431 -40
- package/src/Pool.js +85 -0
- package/src/PostEffects.js +296 -0
- package/src/PostProcessor.js +304 -0
- package/src/RenderTarget.js +134 -0
- package/src/Scene.js +115 -83
- package/src/ScreenEffects.js +266 -0
- package/src/Serializer.js +131 -0
- package/src/Shaders.js +150 -165
- package/src/Shapes.js +118 -129
- package/src/SpatialGrid.js +111 -0
- package/src/SpriteBatch.js +299 -0
- package/src/StateMachine.js +82 -0
- package/src/Storage.js +175 -47
- package/src/Texture.js +58 -67
- package/src/TextureAtlas.js +96 -0
- package/src/Tilemap.js +274 -0
- package/src/Time.js +51 -6
- package/src/Timer.js +99 -0
- package/src/Transform.js +100 -7
- package/src/Tween.js +160 -0
- package/src/UI.js +394 -0
- package/src/components/Behaviour.js +90 -0
- package/src/components/BoxCollider.js +29 -12
- package/src/components/BoxColliderDebug.js +3 -4
- package/src/components/CircleCollider.js +26 -12
- package/src/components/CircleColliderDebug.js +25 -24
- package/src/components/Collider.js +150 -34
- package/src/components/GameObject.js +130 -21
- package/src/components/PolygonCollider.js +55 -0
- package/src/components/RigidBody.js +556 -8
- package/src/importers/Aseprite.js +142 -0
- package/src/importers/ForgeLevel.js +581 -0
- package/src/importers/TiledMap.js +158 -0
- package/src/lights/DirectionalLight.js +6 -15
- package/src/lights/PointLight.js +4 -4
- package/src/managers/AssetManager.js +239 -0
- package/src/managers/AudioManager.js +565 -146
- package/src/managers/EventManager.js +488 -477
- package/src/managers/GLManager.js +57 -0
- package/src/managers/GLState.js +70 -0
- package/src/managers/Gamepad.js +126 -0
- package/src/managers/IDManager.js +24 -2
- package/src/managers/InputManager.js +905 -0
- package/src/managers/NetworkManager.js +178 -0
- package/src/managers/RenderStats.js +34 -0
- package/src/managers/SceneManager.js +30 -0
- package/src/managers/ShaderManager.js +0 -2
- package/src/managers/TextureManager.js +218 -0
- package/src/particlesystem/Particle.js +82 -7
- package/src/particlesystem/ParticleSettings.js +21 -3
- package/src/particlesystem/Particles.js +80 -31
- package/src/physics/AABB.js +207 -0
- package/src/physics/Body.js +862 -0
- package/src/physics/BodyType.js +16 -0
- package/src/physics/BroadPhase.js +641 -0
- package/src/physics/Collision.js +534 -0
- package/src/physics/Contact.js +500 -0
- package/src/physics/ContactSolver.js +526 -0
- package/src/physics/Distance.js +403 -0
- package/src/physics/DistanceJoint.js +227 -0
- package/src/physics/Fixture.js +346 -0
- package/src/physics/Island.js +203 -0
- package/src/physics/Joint.js +78 -0
- package/src/physics/Math2D.js +573 -0
- package/src/physics/RevoluteJoint.js +278 -0
- package/src/physics/Settings.js +78 -0
- package/src/physics/Shapes.js +549 -0
- package/src/physics/TimeOfImpact.js +87 -0
- package/src/physics/World.js +731 -0
- package/src/physics/index.js +79 -0
- package/dist/types/Drawable.d.ts +0 -157
- package/dist/types/Emerald.d.ts +0 -73
- package/dist/types/GLUtils.d.ts +0 -6
- package/dist/types/Physics.d.ts +0 -139
- package/dist/types/Scene.d.ts +0 -39
- package/dist/types/Shaders.d.ts +0 -4
- package/dist/types/Storage.d.ts +0 -46
- package/dist/types/Time.d.ts +0 -22
- package/dist/types/Transform.d.ts +0 -41
- package/dist/types/components/BoxColliderDebug.d.ts +0 -19
- package/dist/types/components/CircleColliderDebug.d.ts +0 -19
- package/dist/types/components/Collider.d.ts +0 -53
- package/dist/types/components/GameObject.d.ts +0 -72
- package/dist/types/components/RigidBody.d.ts +0 -104
- package/dist/types/managers/AudioManager.d.ts +0 -60
- package/dist/types/managers/GLManager.d.ts +0 -47
- package/dist/types/managers/IDManager.d.ts +0 -21
- package/dist/types/managers/SceneManager.d.ts +0 -22
- package/dist/types/particlesystem/Particle.d.ts +0 -42
|
@@ -0,0 +1,534 @@
|
|
|
1
|
+
import { Vec2, Rot, Transform2, EPSILON } from "./Math2D.js";
|
|
2
|
+
import Settings from "./Settings.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @enum ManifoldType
|
|
6
|
+
* @description How a manifold's reference frame is stored: either two circle
|
|
7
|
+
* centers, or a reference face on body A or on body B.
|
|
8
|
+
*/
|
|
9
|
+
const ManifoldType = {
|
|
10
|
+
CIRCLES: 0,
|
|
11
|
+
FACE_A: 1,
|
|
12
|
+
FACE_B: 2,
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @enum ContactFeature
|
|
17
|
+
* @description Whether a contact point came from a vertex or a face, used to
|
|
18
|
+
* build the stable per-point id that carries impulses across steps.
|
|
19
|
+
* @private
|
|
20
|
+
*/
|
|
21
|
+
const ContactFeature = {
|
|
22
|
+
VERTEX: 0,
|
|
23
|
+
FACE: 1,
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @function featureKey
|
|
28
|
+
* @description Packs a contact feature into a single integer so warm starting
|
|
29
|
+
* can match this step's points against the previous step's.
|
|
30
|
+
* @private
|
|
31
|
+
*/
|
|
32
|
+
function featureKey(indexA, indexB, typeA, typeB) {
|
|
33
|
+
return (
|
|
34
|
+
(indexA & 0xff) | ((indexB & 0xff) << 8) | (typeA << 16) | (typeB << 17)
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* @class ManifoldPoint
|
|
40
|
+
* @description A single contact point, stored in the reference body's local
|
|
41
|
+
* frame so it stays valid as the bodies move within a step.
|
|
42
|
+
*/
|
|
43
|
+
class ManifoldPoint {
|
|
44
|
+
constructor() {
|
|
45
|
+
this.localPoint = new Vec2();
|
|
46
|
+
this.normalImpulse = 0;
|
|
47
|
+
this.tangentImpulse = 0;
|
|
48
|
+
this.id = 0;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* @class Manifold
|
|
54
|
+
* @description Up to two contact points plus the frame they are expressed in.
|
|
55
|
+
* Two points is all a 2D convex-convex overlap can produce, and it is exactly
|
|
56
|
+
* what a stable resting contact (a box on the ground) needs.
|
|
57
|
+
*/
|
|
58
|
+
class Manifold {
|
|
59
|
+
constructor() {
|
|
60
|
+
this.type = ManifoldType.CIRCLES;
|
|
61
|
+
this.localNormal = new Vec2();
|
|
62
|
+
this.localPoint = new Vec2();
|
|
63
|
+
this.points = [new ManifoldPoint(), new ManifoldPoint()];
|
|
64
|
+
this.pointCount = 0;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* @method reset
|
|
69
|
+
* @description Empties the manifold.
|
|
70
|
+
*/
|
|
71
|
+
reset() {
|
|
72
|
+
this.pointCount = 0;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* @class WorldManifold
|
|
78
|
+
* @description A manifold converted into world space: the collision normal
|
|
79
|
+
* (always pointing from body A to body B), the contact points, and how deeply
|
|
80
|
+
* each one is penetrating (negative means overlapping).
|
|
81
|
+
*/
|
|
82
|
+
class WorldManifold {
|
|
83
|
+
constructor() {
|
|
84
|
+
this.normal = new Vec2();
|
|
85
|
+
this.points = [new Vec2(), new Vec2()];
|
|
86
|
+
this.separations = [0, 0];
|
|
87
|
+
this.pointCount = 0;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* @method initialize
|
|
92
|
+
* @description Fills this world manifold from a local manifold.
|
|
93
|
+
* @param {Manifold} manifold
|
|
94
|
+
* @param {Transform2} xfA
|
|
95
|
+
* @param {number} radiusA
|
|
96
|
+
* @param {Transform2} xfB
|
|
97
|
+
* @param {number} radiusB
|
|
98
|
+
* @returns {WorldManifold} - this
|
|
99
|
+
*/
|
|
100
|
+
initialize(manifold, xfA, radiusA, xfB, radiusB) {
|
|
101
|
+
this.pointCount = manifold.pointCount;
|
|
102
|
+
if (manifold.pointCount === 0) return this;
|
|
103
|
+
|
|
104
|
+
switch (manifold.type) {
|
|
105
|
+
case ManifoldType.CIRCLES: {
|
|
106
|
+
this.normal.set(1, 0);
|
|
107
|
+
const pointA = Transform2.mulVec(xfA, manifold.localPoint);
|
|
108
|
+
const pointB = Transform2.mulVec(xfB, manifold.points[0].localPoint);
|
|
109
|
+
if (Vec2.distanceSquared(pointA, pointB) > EPSILON * EPSILON) {
|
|
110
|
+
this.normal.set(pointB.x - pointA.x, pointB.y - pointA.y);
|
|
111
|
+
this.normal.normalize();
|
|
112
|
+
}
|
|
113
|
+
const cAx = pointA.x + radiusA * this.normal.x;
|
|
114
|
+
const cAy = pointA.y + radiusA * this.normal.y;
|
|
115
|
+
const cBx = pointB.x - radiusB * this.normal.x;
|
|
116
|
+
const cBy = pointB.y - radiusB * this.normal.y;
|
|
117
|
+
this.points[0].set(0.5 * (cAx + cBx), 0.5 * (cAy + cBy));
|
|
118
|
+
this.separations[0] =
|
|
119
|
+
(cBx - cAx) * this.normal.x + (cBy - cAy) * this.normal.y;
|
|
120
|
+
break;
|
|
121
|
+
}
|
|
122
|
+
case ManifoldType.FACE_A: {
|
|
123
|
+
this.normal.copy(Rot.mulVec(xfA.q, manifold.localNormal));
|
|
124
|
+
const planePoint = Transform2.mulVec(xfA, manifold.localPoint);
|
|
125
|
+
for (let i = 0; i < manifold.pointCount; i++) {
|
|
126
|
+
const clip = Transform2.mulVec(xfB, manifold.points[i].localPoint);
|
|
127
|
+
const s =
|
|
128
|
+
radiusA -
|
|
129
|
+
((clip.x - planePoint.x) * this.normal.x +
|
|
130
|
+
(clip.y - planePoint.y) * this.normal.y);
|
|
131
|
+
const cAx = clip.x + s * this.normal.x;
|
|
132
|
+
const cAy = clip.y + s * this.normal.y;
|
|
133
|
+
const cBx = clip.x - radiusB * this.normal.x;
|
|
134
|
+
const cBy = clip.y - radiusB * this.normal.y;
|
|
135
|
+
this.points[i].set(0.5 * (cAx + cBx), 0.5 * (cAy + cBy));
|
|
136
|
+
this.separations[i] =
|
|
137
|
+
(cBx - cAx) * this.normal.x + (cBy - cAy) * this.normal.y;
|
|
138
|
+
}
|
|
139
|
+
break;
|
|
140
|
+
}
|
|
141
|
+
case ManifoldType.FACE_B: {
|
|
142
|
+
this.normal.copy(Rot.mulVec(xfB.q, manifold.localNormal));
|
|
143
|
+
const planePoint = Transform2.mulVec(xfB, manifold.localPoint);
|
|
144
|
+
for (let i = 0; i < manifold.pointCount; i++) {
|
|
145
|
+
const clip = Transform2.mulVec(xfA, manifold.points[i].localPoint);
|
|
146
|
+
const s =
|
|
147
|
+
radiusB -
|
|
148
|
+
((clip.x - planePoint.x) * this.normal.x +
|
|
149
|
+
(clip.y - planePoint.y) * this.normal.y);
|
|
150
|
+
const cBx = clip.x + s * this.normal.x;
|
|
151
|
+
const cBy = clip.y + s * this.normal.y;
|
|
152
|
+
const cAx = clip.x - radiusA * this.normal.x;
|
|
153
|
+
const cAy = clip.y - radiusA * this.normal.y;
|
|
154
|
+
this.points[i].set(0.5 * (cAx + cBx), 0.5 * (cAy + cBy));
|
|
155
|
+
this.separations[i] =
|
|
156
|
+
(cAx - cBx) * this.normal.x + (cAy - cBy) * this.normal.y;
|
|
157
|
+
}
|
|
158
|
+
this.normal.neg();
|
|
159
|
+
break;
|
|
160
|
+
}
|
|
161
|
+
default:
|
|
162
|
+
break;
|
|
163
|
+
}
|
|
164
|
+
return this;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* @function mulTXf
|
|
170
|
+
* @description Composes transforms: returns the transform of `B` expressed in
|
|
171
|
+
* `A`'s frame.
|
|
172
|
+
* @private
|
|
173
|
+
*/
|
|
174
|
+
function mulTXf(A, B) {
|
|
175
|
+
const out = new Transform2();
|
|
176
|
+
out.q.s = A.q.c * B.q.s - A.q.s * B.q.c;
|
|
177
|
+
out.q.c = A.q.c * B.q.c + A.q.s * B.q.s;
|
|
178
|
+
const px = B.p.x - A.p.x;
|
|
179
|
+
const py = B.p.y - A.p.y;
|
|
180
|
+
out.p.set(A.q.c * px + A.q.s * py, -A.q.s * px + A.q.c * py);
|
|
181
|
+
return out;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* @function collideCircles
|
|
186
|
+
* @description Builds the manifold for two circles.
|
|
187
|
+
* @param {Manifold} manifold - Output manifold
|
|
188
|
+
* @param {CircleShape} circleA
|
|
189
|
+
* @param {Transform2} xfA
|
|
190
|
+
* @param {CircleShape} circleB
|
|
191
|
+
* @param {Transform2} xfB
|
|
192
|
+
*/
|
|
193
|
+
function collideCircles(manifold, circleA, xfA, circleB, xfB) {
|
|
194
|
+
manifold.pointCount = 0;
|
|
195
|
+
|
|
196
|
+
const pA = Transform2.mulVec(xfA, circleA.p);
|
|
197
|
+
const pB = Transform2.mulVec(xfB, circleB.p);
|
|
198
|
+
const distSqr = Vec2.distanceSquared(pA, pB);
|
|
199
|
+
const radius = circleA.radius + circleB.radius;
|
|
200
|
+
if (distSqr > radius * radius) return;
|
|
201
|
+
|
|
202
|
+
manifold.type = ManifoldType.CIRCLES;
|
|
203
|
+
manifold.localPoint.copy(circleA.p);
|
|
204
|
+
manifold.localNormal.setZero();
|
|
205
|
+
manifold.pointCount = 1;
|
|
206
|
+
manifold.points[0].localPoint.copy(circleB.p);
|
|
207
|
+
manifold.points[0].id = 0;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* @function collidePolygonAndCircle
|
|
212
|
+
* @description Builds the manifold for a polygon against a circle. The circle
|
|
213
|
+
* is pushed into the polygon's frame, then tested against the closest face,
|
|
214
|
+
* falling back to the nearest corner when it sits past the face's edge.
|
|
215
|
+
* @param {Manifold} manifold - Output manifold
|
|
216
|
+
* @param {PolygonShape} polygonA
|
|
217
|
+
* @param {Transform2} xfA
|
|
218
|
+
* @param {CircleShape} circleB
|
|
219
|
+
* @param {Transform2} xfB
|
|
220
|
+
*/
|
|
221
|
+
function collidePolygonAndCircle(manifold, polygonA, xfA, circleB, xfB) {
|
|
222
|
+
manifold.pointCount = 0;
|
|
223
|
+
|
|
224
|
+
const c = Transform2.mulVec(xfB, circleB.p);
|
|
225
|
+
const cLocal = Transform2.mulTVec(xfA, c);
|
|
226
|
+
|
|
227
|
+
let normalIndex = 0;
|
|
228
|
+
let separation = -Number.MAX_VALUE;
|
|
229
|
+
const radius = polygonA.radius + circleB.radius;
|
|
230
|
+
const vertexCount = polygonA.vertices.length;
|
|
231
|
+
const vertices = polygonA.vertices;
|
|
232
|
+
const normals = polygonA.normals;
|
|
233
|
+
|
|
234
|
+
for (let i = 0; i < vertexCount; i++) {
|
|
235
|
+
const s =
|
|
236
|
+
normals[i].x * (cLocal.x - vertices[i].x) +
|
|
237
|
+
normals[i].y * (cLocal.y - vertices[i].y);
|
|
238
|
+
if (s > radius) return;
|
|
239
|
+
if (s > separation) {
|
|
240
|
+
separation = s;
|
|
241
|
+
normalIndex = i;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
const vertIndex1 = normalIndex;
|
|
246
|
+
const vertIndex2 = vertIndex1 + 1 < vertexCount ? vertIndex1 + 1 : 0;
|
|
247
|
+
const v1 = vertices[vertIndex1];
|
|
248
|
+
const v2 = vertices[vertIndex2];
|
|
249
|
+
|
|
250
|
+
if (separation < EPSILON) {
|
|
251
|
+
manifold.pointCount = 1;
|
|
252
|
+
manifold.type = ManifoldType.FACE_A;
|
|
253
|
+
manifold.localNormal.copy(normals[normalIndex]);
|
|
254
|
+
manifold.localPoint.set(0.5 * (v1.x + v2.x), 0.5 * (v1.y + v2.y));
|
|
255
|
+
manifold.points[0].localPoint.copy(circleB.p);
|
|
256
|
+
manifold.points[0].id = 0;
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
const u1 =
|
|
261
|
+
(cLocal.x - v1.x) * (v2.x - v1.x) + (cLocal.y - v1.y) * (v2.y - v1.y);
|
|
262
|
+
const u2 =
|
|
263
|
+
(cLocal.x - v2.x) * (v1.x - v2.x) + (cLocal.y - v2.y) * (v1.y - v2.y);
|
|
264
|
+
|
|
265
|
+
if (u1 <= 0) {
|
|
266
|
+
if (Vec2.distanceSquared(cLocal, v1) > radius * radius) return;
|
|
267
|
+
manifold.pointCount = 1;
|
|
268
|
+
manifold.type = ManifoldType.FACE_A;
|
|
269
|
+
manifold.localNormal.set(cLocal.x - v1.x, cLocal.y - v1.y);
|
|
270
|
+
manifold.localNormal.normalize();
|
|
271
|
+
manifold.localPoint.copy(v1);
|
|
272
|
+
} else if (u2 <= 0) {
|
|
273
|
+
if (Vec2.distanceSquared(cLocal, v2) > radius * radius) return;
|
|
274
|
+
manifold.pointCount = 1;
|
|
275
|
+
manifold.type = ManifoldType.FACE_A;
|
|
276
|
+
manifold.localNormal.set(cLocal.x - v2.x, cLocal.y - v2.y);
|
|
277
|
+
manifold.localNormal.normalize();
|
|
278
|
+
manifold.localPoint.copy(v2);
|
|
279
|
+
} else {
|
|
280
|
+
const faceCenterX = 0.5 * (v1.x + v2.x);
|
|
281
|
+
const faceCenterY = 0.5 * (v1.y + v2.y);
|
|
282
|
+
const s =
|
|
283
|
+
(cLocal.x - faceCenterX) * normals[vertIndex1].x +
|
|
284
|
+
(cLocal.y - faceCenterY) * normals[vertIndex1].y;
|
|
285
|
+
if (s > radius) return;
|
|
286
|
+
manifold.pointCount = 1;
|
|
287
|
+
manifold.type = ManifoldType.FACE_A;
|
|
288
|
+
manifold.localNormal.copy(normals[vertIndex1]);
|
|
289
|
+
manifold.localPoint.set(faceCenterX, faceCenterY);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
manifold.points[0].localPoint.copy(circleB.p);
|
|
293
|
+
manifold.points[0].id = 0;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* @function findMaxSeparation
|
|
298
|
+
* @description Separating-axis test: finds the face of `poly1` that pushes
|
|
299
|
+
* `poly2` furthest away, and how far.
|
|
300
|
+
* @returns {{separation:number, edgeIndex:number}}
|
|
301
|
+
* @private
|
|
302
|
+
*/
|
|
303
|
+
function findMaxSeparation(poly1, xf1, poly2, xf2) {
|
|
304
|
+
const count1 = poly1.vertices.length;
|
|
305
|
+
const count2 = poly2.vertices.length;
|
|
306
|
+
const n1s = poly1.normals;
|
|
307
|
+
const v1s = poly1.vertices;
|
|
308
|
+
const v2s = poly2.vertices;
|
|
309
|
+
const xf = mulTXf(xf2, xf1);
|
|
310
|
+
|
|
311
|
+
let bestIndex = 0;
|
|
312
|
+
let maxSeparation = -Number.MAX_VALUE;
|
|
313
|
+
|
|
314
|
+
for (let i = 0; i < count1; i++) {
|
|
315
|
+
const n = Rot.mulVec(xf.q, n1s[i]);
|
|
316
|
+
const v1 = Transform2.mulVec(xf, v1s[i]);
|
|
317
|
+
|
|
318
|
+
let si = Number.MAX_VALUE;
|
|
319
|
+
for (let j = 0; j < count2; j++) {
|
|
320
|
+
const sij = n.x * (v2s[j].x - v1.x) + n.y * (v2s[j].y - v1.y);
|
|
321
|
+
if (sij < si) si = sij;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
if (si > maxSeparation) {
|
|
325
|
+
maxSeparation = si;
|
|
326
|
+
bestIndex = i;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
return { separation: maxSeparation, edgeIndex: bestIndex };
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
/**
|
|
334
|
+
* @function findIncidentEdge
|
|
335
|
+
* @description Picks the edge of `poly2` most anti-parallel to the reference
|
|
336
|
+
* face: the edge that is actually being pressed into it.
|
|
337
|
+
* @private
|
|
338
|
+
*/
|
|
339
|
+
function findIncidentEdge(poly1, xf1, edge1, poly2, xf2) {
|
|
340
|
+
const normals1 = poly1.normals;
|
|
341
|
+
const count2 = poly2.vertices.length;
|
|
342
|
+
const vertices2 = poly2.vertices;
|
|
343
|
+
const normals2 = poly2.normals;
|
|
344
|
+
|
|
345
|
+
const normal1World = Rot.mulVec(xf1.q, normals1[edge1]);
|
|
346
|
+
const normal1 = Rot.mulTVec(xf2.q, normal1World);
|
|
347
|
+
|
|
348
|
+
let index = 0;
|
|
349
|
+
let minDot = Number.MAX_VALUE;
|
|
350
|
+
for (let i = 0; i < count2; i++) {
|
|
351
|
+
const dot = normal1.x * normals2[i].x + normal1.y * normals2[i].y;
|
|
352
|
+
if (dot < minDot) {
|
|
353
|
+
minDot = dot;
|
|
354
|
+
index = i;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
const i1 = index;
|
|
359
|
+
const i2 = i1 + 1 < count2 ? i1 + 1 : 0;
|
|
360
|
+
|
|
361
|
+
return [
|
|
362
|
+
{
|
|
363
|
+
v: Transform2.mulVec(xf2, vertices2[i1]),
|
|
364
|
+
indexA: edge1,
|
|
365
|
+
indexB: i1,
|
|
366
|
+
typeA: ContactFeature.FACE,
|
|
367
|
+
typeB: ContactFeature.VERTEX,
|
|
368
|
+
},
|
|
369
|
+
{
|
|
370
|
+
v: Transform2.mulVec(xf2, vertices2[i2]),
|
|
371
|
+
indexA: edge1,
|
|
372
|
+
indexB: i2,
|
|
373
|
+
typeA: ContactFeature.FACE,
|
|
374
|
+
typeB: ContactFeature.VERTEX,
|
|
375
|
+
},
|
|
376
|
+
];
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
/**
|
|
380
|
+
* @function clipSegmentToLine
|
|
381
|
+
* @description Sutherland-Hodgman clip of the incident edge against one side
|
|
382
|
+
* plane of the reference face.
|
|
383
|
+
* @returns {Array} - The surviving 0..2 clip vertices
|
|
384
|
+
* @private
|
|
385
|
+
*/
|
|
386
|
+
function clipSegmentToLine(vIn, normal, offset, vertexIndexA) {
|
|
387
|
+
const vOut = [];
|
|
388
|
+
|
|
389
|
+
const d0 = normal.x * vIn[0].v.x + normal.y * vIn[0].v.y - offset;
|
|
390
|
+
const d1 = normal.x * vIn[1].v.x + normal.y * vIn[1].v.y - offset;
|
|
391
|
+
|
|
392
|
+
if (d0 <= 0) vOut.push(vIn[0]);
|
|
393
|
+
if (d1 <= 0) vOut.push(vIn[1]);
|
|
394
|
+
|
|
395
|
+
if (d0 * d1 < 0) {
|
|
396
|
+
const interp = d0 / (d0 - d1);
|
|
397
|
+
vOut.push({
|
|
398
|
+
v: new Vec2(
|
|
399
|
+
vIn[0].v.x + interp * (vIn[1].v.x - vIn[0].v.x),
|
|
400
|
+
vIn[0].v.y + interp * (vIn[1].v.y - vIn[0].v.y)
|
|
401
|
+
),
|
|
402
|
+
indexA: vertexIndexA,
|
|
403
|
+
indexB: vIn[0].indexB,
|
|
404
|
+
typeA: ContactFeature.VERTEX,
|
|
405
|
+
typeB: ContactFeature.FACE,
|
|
406
|
+
});
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
return vOut;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
/**
|
|
413
|
+
* @function collidePolygons
|
|
414
|
+
* @description Builds the manifold for two convex polygons using the
|
|
415
|
+
* separating-axis test to pick a reference face, then clipping the opposing
|
|
416
|
+
* (incident) edge against it. The result is the one- or two-point contact patch
|
|
417
|
+
* that makes boxes rest flat instead of rocking.
|
|
418
|
+
* @param {Manifold} manifold - Output manifold
|
|
419
|
+
* @param {PolygonShape} polyA
|
|
420
|
+
* @param {Transform2} xfA
|
|
421
|
+
* @param {PolygonShape} polyB
|
|
422
|
+
* @param {Transform2} xfB
|
|
423
|
+
*/
|
|
424
|
+
function collidePolygons(manifold, polyA, xfA, polyB, xfB) {
|
|
425
|
+
manifold.pointCount = 0;
|
|
426
|
+
const totalRadius = polyA.radius + polyB.radius;
|
|
427
|
+
|
|
428
|
+
const edgeA = findMaxSeparation(polyA, xfA, polyB, xfB);
|
|
429
|
+
if (edgeA.separation > totalRadius) return;
|
|
430
|
+
|
|
431
|
+
const edgeB = findMaxSeparation(polyB, xfB, polyA, xfA);
|
|
432
|
+
if (edgeB.separation > totalRadius) return;
|
|
433
|
+
|
|
434
|
+
let poly1;
|
|
435
|
+
let poly2;
|
|
436
|
+
let xf1;
|
|
437
|
+
let xf2;
|
|
438
|
+
let edge1;
|
|
439
|
+
let flip;
|
|
440
|
+
|
|
441
|
+
const tol = 0.1 * Settings.linearSlop;
|
|
442
|
+
if (edgeB.separation > edgeA.separation + tol) {
|
|
443
|
+
poly1 = polyB;
|
|
444
|
+
poly2 = polyA;
|
|
445
|
+
xf1 = xfB;
|
|
446
|
+
xf2 = xfA;
|
|
447
|
+
edge1 = edgeB.edgeIndex;
|
|
448
|
+
manifold.type = ManifoldType.FACE_B;
|
|
449
|
+
flip = true;
|
|
450
|
+
} else {
|
|
451
|
+
poly1 = polyA;
|
|
452
|
+
poly2 = polyB;
|
|
453
|
+
xf1 = xfA;
|
|
454
|
+
xf2 = xfB;
|
|
455
|
+
edge1 = edgeA.edgeIndex;
|
|
456
|
+
manifold.type = ManifoldType.FACE_A;
|
|
457
|
+
flip = false;
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
const incidentEdge = findIncidentEdge(poly1, xf1, edge1, poly2, xf2);
|
|
461
|
+
|
|
462
|
+
const count1 = poly1.vertices.length;
|
|
463
|
+
const iv1 = edge1;
|
|
464
|
+
const iv2 = edge1 + 1 < count1 ? edge1 + 1 : 0;
|
|
465
|
+
|
|
466
|
+
let v11 = poly1.vertices[iv1];
|
|
467
|
+
let v12 = poly1.vertices[iv2];
|
|
468
|
+
|
|
469
|
+
const localTangent = Vec2.sub(v12, v11);
|
|
470
|
+
localTangent.normalize();
|
|
471
|
+
const localNormal = new Vec2(localTangent.y, -localTangent.x);
|
|
472
|
+
const planePoint = new Vec2(0.5 * (v11.x + v12.x), 0.5 * (v11.y + v12.y));
|
|
473
|
+
|
|
474
|
+
const tangent = Rot.mulVec(xf1.q, localTangent);
|
|
475
|
+
const normal = new Vec2(tangent.y, -tangent.x);
|
|
476
|
+
|
|
477
|
+
v11 = Transform2.mulVec(xf1, v11);
|
|
478
|
+
v12 = Transform2.mulVec(xf1, v12);
|
|
479
|
+
|
|
480
|
+
const frontOffset = normal.x * v11.x + normal.y * v11.y;
|
|
481
|
+
const sideOffset1 = -(tangent.x * v11.x + tangent.y * v11.y) + totalRadius;
|
|
482
|
+
const sideOffset2 = tangent.x * v12.x + tangent.y * v12.y + totalRadius;
|
|
483
|
+
|
|
484
|
+
const clip1 = clipSegmentToLine(
|
|
485
|
+
incidentEdge,
|
|
486
|
+
Vec2.neg(tangent),
|
|
487
|
+
sideOffset1,
|
|
488
|
+
iv1
|
|
489
|
+
);
|
|
490
|
+
if (clip1.length < 2) return;
|
|
491
|
+
|
|
492
|
+
const clip2 = clipSegmentToLine(clip1, tangent, sideOffset2, iv2);
|
|
493
|
+
if (clip2.length < 2) return;
|
|
494
|
+
|
|
495
|
+
manifold.localNormal.copy(localNormal);
|
|
496
|
+
manifold.localPoint.copy(planePoint);
|
|
497
|
+
|
|
498
|
+
let pointCount = 0;
|
|
499
|
+
for (let i = 0; i < 2; i++) {
|
|
500
|
+
const separation =
|
|
501
|
+
normal.x * clip2[i].v.x + normal.y * clip2[i].v.y - frontOffset;
|
|
502
|
+
if (separation <= totalRadius) {
|
|
503
|
+
const cp = manifold.points[pointCount];
|
|
504
|
+
cp.localPoint.copy(Transform2.mulTVec(xf2, clip2[i].v));
|
|
505
|
+
cp.id = flip
|
|
506
|
+
? featureKey(
|
|
507
|
+
clip2[i].indexB,
|
|
508
|
+
clip2[i].indexA,
|
|
509
|
+
clip2[i].typeB,
|
|
510
|
+
clip2[i].typeA
|
|
511
|
+
)
|
|
512
|
+
: featureKey(
|
|
513
|
+
clip2[i].indexA,
|
|
514
|
+
clip2[i].indexB,
|
|
515
|
+
clip2[i].typeA,
|
|
516
|
+
clip2[i].typeB
|
|
517
|
+
);
|
|
518
|
+
pointCount++;
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
manifold.pointCount = pointCount;
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
export {
|
|
526
|
+
Manifold,
|
|
527
|
+
ManifoldPoint,
|
|
528
|
+
ManifoldType,
|
|
529
|
+
WorldManifold,
|
|
530
|
+
collideCircles,
|
|
531
|
+
collidePolygonAndCircle,
|
|
532
|
+
collidePolygons,
|
|
533
|
+
mulTXf,
|
|
534
|
+
};
|