emeraldengine 3.0.0 → 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.
Files changed (103) hide show
  1. package/README.md +1498 -1659
  2. package/dist/types/index.d.ts +4 -1
  3. package/dist/types/src/Animator.d.ts +1 -1
  4. package/dist/types/src/CollisionLayers.d.ts +2 -2
  5. package/dist/types/src/Color.d.ts +1 -0
  6. package/dist/types/src/Drawable.d.ts +1 -1
  7. package/dist/types/src/EmeraldDB.d.ts +2 -2
  8. package/dist/types/src/InstancedTexture.d.ts +17 -2
  9. package/dist/types/src/Material.d.ts +2 -2
  10. package/dist/types/src/MathUtils.d.ts +2 -1
  11. package/dist/types/src/ParticleEmitter.d.ts +1 -1
  12. package/dist/types/src/Physics.d.ts +148 -18
  13. package/dist/types/src/Scene.d.ts +1 -1
  14. package/dist/types/src/Shaders.d.ts +2 -2
  15. package/dist/types/src/Tilemap.d.ts +1 -1
  16. package/dist/types/src/UI.d.ts +1 -1
  17. package/dist/types/src/components/Behaviour.d.ts +2 -2
  18. package/dist/types/src/components/Collider.d.ts +7 -1
  19. package/dist/types/src/components/GameObject.d.ts +2 -2
  20. package/dist/types/src/components/PolygonCollider.d.ts +33 -0
  21. package/dist/types/src/components/RigidBody.d.ts +281 -8
  22. package/dist/types/src/importers/Aseprite.d.ts +2 -2
  23. package/dist/types/src/importers/ForgeLevel.d.ts +97 -0
  24. package/dist/types/src/importers/TiledMap.d.ts +1 -1
  25. package/dist/types/src/managers/EventManager.d.ts +1 -1
  26. package/dist/types/src/managers/Gamepad.d.ts +102 -0
  27. package/dist/types/src/managers/InputManager.d.ts +93 -2
  28. package/dist/types/src/managers/NetworkManager.d.ts +2 -2
  29. package/dist/types/src/managers/RenderStats.d.ts +1 -1
  30. package/dist/types/src/managers/TextureManager.d.ts +1 -1
  31. package/dist/types/src/physics/AABB.d.ts +92 -0
  32. package/dist/types/src/physics/Body.d.ts +435 -0
  33. package/dist/types/src/physics/BodyType.d.ts +6 -0
  34. package/dist/types/src/physics/BroadPhase.d.ts +210 -0
  35. package/dist/types/src/physics/Collision.d.ts +102 -0
  36. package/dist/types/src/physics/Contact.d.ts +206 -0
  37. package/dist/types/src/physics/ContactSolver.d.ts +108 -0
  38. package/dist/types/src/physics/Distance.d.ts +54 -0
  39. package/dist/types/src/physics/DistanceJoint.d.ts +90 -0
  40. package/dist/types/src/physics/Fixture.d.ts +221 -0
  41. package/dist/types/src/physics/Island.d.ts +52 -0
  42. package/dist/types/src/physics/Joint.d.ts +59 -0
  43. package/dist/types/src/physics/Math2D.d.ts +371 -0
  44. package/dist/types/src/physics/RevoluteJoint.d.ts +119 -0
  45. package/dist/types/src/physics/Settings.d.ts +22 -0
  46. package/dist/types/src/physics/Shapes.d.ts +207 -0
  47. package/dist/types/src/physics/TimeOfImpact.d.ts +22 -0
  48. package/dist/types/src/physics/World.d.ts +274 -0
  49. package/dist/types/src/physics/index.d.ts +34 -0
  50. package/index.js +6 -0
  51. package/package.json +2 -3
  52. package/src/Animator.js +1 -1
  53. package/src/CollisionLayers.js +3 -3
  54. package/src/Color.js +8 -0
  55. package/src/Drawable.js +1 -1
  56. package/src/Emerald.js +1 -1
  57. package/src/EmeraldDB.js +2 -2
  58. package/src/InstancedTexture.js +57 -9
  59. package/src/Material.js +2 -2
  60. package/src/MathUtils.js +2 -1
  61. package/src/ParticleEmitter.js +1 -1
  62. package/src/Physics.js +270 -60
  63. package/src/Scene.js +1 -1
  64. package/src/Shaders.js +20 -20
  65. package/src/Tilemap.js +1 -1
  66. package/src/UI.js +1 -1
  67. package/src/components/Behaviour.js +2 -2
  68. package/src/components/BoxCollider.js +7 -9
  69. package/src/components/BoxColliderDebug.js +3 -4
  70. package/src/components/CircleCollider.js +7 -9
  71. package/src/components/CircleColliderDebug.js +3 -2
  72. package/src/components/Collider.js +13 -3
  73. package/src/components/GameObject.js +2 -2
  74. package/src/components/PolygonCollider.js +55 -0
  75. package/src/components/RigidBody.js +441 -14
  76. package/src/importers/Aseprite.js +2 -2
  77. package/src/importers/ForgeLevel.js +581 -0
  78. package/src/importers/TiledMap.js +1 -1
  79. package/src/managers/EventManager.js +1 -1
  80. package/src/managers/Gamepad.js +126 -0
  81. package/src/managers/InputManager.js +129 -3
  82. package/src/managers/NetworkManager.js +2 -2
  83. package/src/managers/RenderStats.js +1 -1
  84. package/src/managers/TextureManager.js +1 -1
  85. package/src/physics/AABB.js +207 -0
  86. package/src/physics/Body.js +862 -0
  87. package/src/physics/BodyType.js +16 -0
  88. package/src/physics/BroadPhase.js +641 -0
  89. package/src/physics/Collision.js +534 -0
  90. package/src/physics/Contact.js +500 -0
  91. package/src/physics/ContactSolver.js +526 -0
  92. package/src/physics/Distance.js +403 -0
  93. package/src/physics/DistanceJoint.js +227 -0
  94. package/src/physics/Fixture.js +346 -0
  95. package/src/physics/Island.js +203 -0
  96. package/src/physics/Joint.js +78 -0
  97. package/src/physics/Math2D.js +573 -0
  98. package/src/physics/RevoluteJoint.js +278 -0
  99. package/src/physics/Settings.js +78 -0
  100. package/src/physics/Shapes.js +549 -0
  101. package/src/physics/TimeOfImpact.js +87 -0
  102. package/src/physics/World.js +731 -0
  103. package/src/physics/index.js +79 -0
@@ -0,0 +1,278 @@
1
+ import { Vec2, Rot, clamp } from "./Math2D.js";
2
+ import { Joint, JointType } from "./Joint.js";
3
+ import PhysicsSettings from "./Settings.js";
4
+
5
+ /**
6
+ * @function solve22
7
+ * @description Solves the symmetric 2x2 system `K * x = b` for `x`.
8
+ * @param {{k11:number, k12:number, k22:number}} K
9
+ * @param {Vec2} b
10
+ * @returns {Vec2}
11
+ * @private
12
+ */
13
+ function solve22(K, b) {
14
+ const det = K.k11 * K.k22 - K.k12 * K.k12;
15
+ const invDet = det !== 0 ? 1 / det : 0;
16
+ return new Vec2(
17
+ invDet * (K.k22 * b.x - K.k12 * b.y),
18
+ invDet * (K.k11 * b.y - K.k12 * b.x)
19
+ );
20
+ }
21
+
22
+ /**
23
+ * @class RevoluteJoint
24
+ * @extends Joint
25
+ * @description Pins two bodies together at a shared point while leaving
26
+ * rotation free, like a door hinge or a pendulum arm. Optionally driven by a
27
+ * motor that spins the joint toward a target angular speed, up to a torque
28
+ * limit; set `enableMotor` for a turntable, a windmill blade, or a wheel.
29
+ * @param {Object} def - `{ bodyA, bodyB, localAnchorA, localAnchorB,
30
+ * enableMotor, motorSpeed, maxMotorTorque, collideConnected, userData }`
31
+ */
32
+ class RevoluteJoint extends Joint {
33
+ constructor(def) {
34
+ super({ ...def, type: JointType.REVOLUTE });
35
+ this.localAnchorA = new Vec2(def.localAnchorA || { x: 0, y: 0 });
36
+ this.localAnchorB = new Vec2(def.localAnchorB || { x: 0, y: 0 });
37
+ this.referenceAngle =
38
+ def.referenceAngle ?? def.bodyB.getAngle() - def.bodyA.getAngle();
39
+
40
+ this.enableMotor = !!def.enableMotor;
41
+ this.motorSpeed = def.motorSpeed ?? 0;
42
+ this.maxMotorTorque = def.maxMotorTorque ?? 0;
43
+
44
+ this.impulse = new Vec2();
45
+ this.motorImpulse = 0;
46
+ this.axialMass = 0;
47
+ this.motorMass = 0;
48
+ this.K = { k11: 0, k12: 0, k22: 0 };
49
+ this.rA = new Vec2();
50
+ this.rB = new Vec2();
51
+ /** @private */
52
+ this.indexA = 0;
53
+ /** @private */
54
+ this.indexB = 0;
55
+ }
56
+
57
+ /**
58
+ * @method getAnchorA
59
+ * @returns {Vec2}
60
+ */
61
+ getAnchorA() {
62
+ return this.bodyA.getWorldPoint(this.localAnchorA);
63
+ }
64
+
65
+ /**
66
+ * @method getAnchorB
67
+ * @returns {Vec2}
68
+ */
69
+ getAnchorB() {
70
+ return this.bodyB.getWorldPoint(this.localAnchorB);
71
+ }
72
+
73
+ /**
74
+ * @method getReactionForce
75
+ * @param {number} invDt
76
+ * @returns {Vec2}
77
+ */
78
+ getReactionForce(invDt) {
79
+ return Vec2.mul(invDt, this.impulse);
80
+ }
81
+
82
+ /**
83
+ * @method getReactionTorque
84
+ * @param {number} invDt
85
+ * @returns {number}
86
+ */
87
+ getReactionTorque(invDt) {
88
+ return invDt * this.motorImpulse;
89
+ }
90
+
91
+ /**
92
+ * @method getJointAngle
93
+ * @description Current angle of body B relative to body A, minus the angle
94
+ * they started at.
95
+ * @returns {number}
96
+ */
97
+ getJointAngle() {
98
+ return this.bodyB.getAngle() - this.bodyA.getAngle() - this.referenceAngle;
99
+ }
100
+
101
+ /**
102
+ * @method setMotorSpeed
103
+ * @param {number} speed
104
+ */
105
+ setMotorSpeed(speed) {
106
+ this.motorSpeed = speed;
107
+ }
108
+
109
+ /**
110
+ * @method getMotorSpeed
111
+ * @returns {number}
112
+ */
113
+ getMotorSpeed() {
114
+ return this.motorSpeed;
115
+ }
116
+
117
+ /**
118
+ * @method setMaxMotorTorque
119
+ * @param {number} torque
120
+ */
121
+ setMaxMotorTorque(torque) {
122
+ this.maxMotorTorque = torque;
123
+ }
124
+
125
+ /**
126
+ * @method setEnableMotor
127
+ * @param {boolean} flag
128
+ */
129
+ setEnableMotor(flag) {
130
+ this.enableMotor = !!flag;
131
+ }
132
+
133
+ /**
134
+ * @method isMotorEnabled
135
+ * @returns {boolean}
136
+ */
137
+ isMotorEnabled() {
138
+ return this.enableMotor;
139
+ }
140
+
141
+ /**
142
+ * @method getMotorTorque
143
+ * @param {number} invDt
144
+ * @returns {number}
145
+ */
146
+ getMotorTorque(invDt) {
147
+ return invDt * this.motorImpulse;
148
+ }
149
+
150
+ /**
151
+ * @method initVelocityConstraints
152
+ * @param {Object} step - `{ dt, warmStarting }`
153
+ * @param {Array<Object>} positions
154
+ * @param {Array<Object>} velocities
155
+ */
156
+ initVelocityConstraints(step, positions, velocities) {
157
+ this.indexA = this.bodyA.islandIndex;
158
+ this.indexB = this.bodyB.islandIndex;
159
+ this.invMassA = this.bodyA.invMass;
160
+ this.invMassB = this.bodyB.invMass;
161
+ this.invIA = this.bodyA.invI;
162
+ this.invIB = this.bodyB.invI;
163
+ const localCenterA = this.bodyA.sweep.localCenter;
164
+ const localCenterB = this.bodyB.sweep.localCenter;
165
+
166
+ const posA = positions[this.indexA];
167
+ const posB = positions[this.indexB];
168
+ const velA = velocities[this.indexA];
169
+ const velB = velocities[this.indexB];
170
+
171
+ const qA = new Rot(posA.a);
172
+ const qB = new Rot(posB.a);
173
+ this.rA = Rot.mulVec(qA, Vec2.sub(this.localAnchorA, localCenterA));
174
+ this.rB = Rot.mulVec(qB, Vec2.sub(this.localAnchorB, localCenterB));
175
+
176
+ const mA = this.invMassA;
177
+ const mB = this.invMassB;
178
+ const iA = this.invIA;
179
+ const iB = this.invIB;
180
+
181
+ this.axialMass = iA + iB;
182
+ this.motorMass = this.axialMass > 0 ? 1 / this.axialMass : 0;
183
+ if (!this.enableMotor || this.axialMass === 0) this.motorImpulse = 0;
184
+
185
+ this.K.k11 =
186
+ mA + mB + iA * this.rA.y * this.rA.y + iB * this.rB.y * this.rB.y;
187
+ this.K.k12 = -iA * this.rA.x * this.rA.y - iB * this.rB.x * this.rB.y;
188
+ this.K.k22 =
189
+ mA + mB + iA * this.rA.x * this.rA.x + iB * this.rB.x * this.rB.x;
190
+
191
+ if (step.warmStarting) {
192
+ velA.v.subMul(mA, this.impulse);
193
+ velA.w -= iA * (Vec2.cross(this.rA, this.impulse) + this.motorImpulse);
194
+ velB.v.addMul(mB, this.impulse);
195
+ velB.w += iB * (Vec2.cross(this.rB, this.impulse) + this.motorImpulse);
196
+ } else {
197
+ this.impulse.setZero();
198
+ this.motorImpulse = 0;
199
+ }
200
+ }
201
+
202
+ /**
203
+ * @method solveVelocityConstraints
204
+ * @param {Object} step - `{ dt }`
205
+ * @param {Array<Object>} velocities
206
+ */
207
+ solveVelocityConstraints(step, velocities) {
208
+ const velA = velocities[this.indexA];
209
+ const velB = velocities[this.indexB];
210
+ const mA = this.invMassA;
211
+ const mB = this.invMassB;
212
+ const iA = this.invIA;
213
+ const iB = this.invIB;
214
+
215
+ if (this.enableMotor) {
216
+ const Cdot = velB.w - velA.w - this.motorSpeed;
217
+ let impulse = -this.motorMass * Cdot;
218
+ const oldImpulse = this.motorImpulse;
219
+ const maxImpulse = this.maxMotorTorque * step.dt;
220
+ this.motorImpulse = clamp(oldImpulse + impulse, -maxImpulse, maxImpulse);
221
+ impulse = this.motorImpulse - oldImpulse;
222
+ velA.w -= iA * impulse;
223
+ velB.w += iB * impulse;
224
+ }
225
+
226
+ const vpA = Vec2.add(velA.v, Vec2.crossSV(velA.w, this.rA));
227
+ const vpB = Vec2.add(velB.v, Vec2.crossSV(velB.w, this.rB));
228
+ const Cdot = Vec2.sub(vpB, vpA);
229
+ const impulse = solve22(this.K, Vec2.neg(Cdot));
230
+
231
+ this.impulse.add(impulse);
232
+
233
+ velA.v.subMul(mA, impulse);
234
+ velA.w -= iA * Vec2.cross(this.rA, impulse);
235
+ velB.v.addMul(mB, impulse);
236
+ velB.w += iB * Vec2.cross(this.rB, impulse);
237
+ }
238
+
239
+ /**
240
+ * @method solvePositionConstraints
241
+ * @param {Array<Object>} positions
242
+ * @returns {boolean}
243
+ */
244
+ solvePositionConstraints(positions) {
245
+ const posA = positions[this.indexA];
246
+ const posB = positions[this.indexB];
247
+ const mA = this.invMassA;
248
+ const mB = this.invMassB;
249
+ const iA = this.invIA;
250
+ const iB = this.invIB;
251
+ const localCenterA = this.bodyA.sweep.localCenter;
252
+ const localCenterB = this.bodyB.sweep.localCenter;
253
+
254
+ const qA = new Rot(posA.a);
255
+ const qB = new Rot(posB.a);
256
+ const rA = Rot.mulVec(qA, Vec2.sub(this.localAnchorA, localCenterA));
257
+ const rB = Rot.mulVec(qB, Vec2.sub(this.localAnchorB, localCenterB));
258
+
259
+ const C = Vec2.sub(Vec2.add(posB.c, rB), Vec2.add(posA.c, rA));
260
+ const positionError = C.length();
261
+
262
+ const K = {
263
+ k11: mA + mB + iA * rA.y * rA.y + iB * rB.y * rB.y,
264
+ k12: -iA * rA.x * rA.y - iB * rB.x * rB.y,
265
+ k22: mA + mB + iA * rA.x * rA.x + iB * rB.x * rB.x,
266
+ };
267
+ const impulse = solve22(K, Vec2.neg(C));
268
+
269
+ posA.c.subMul(mA, impulse);
270
+ posA.a -= iA * Vec2.cross(rA, impulse);
271
+ posB.c.addMul(mB, impulse);
272
+ posB.a += iB * Vec2.cross(rB, impulse);
273
+
274
+ return positionError <= PhysicsSettings.linearSlop;
275
+ }
276
+ }
277
+
278
+ export default RevoluteJoint;
@@ -0,0 +1,78 @@
1
+ /**
2
+ * @namespace Settings
3
+ * @description Global tunables for the physics engine, in physics units
4
+ * (meters/radians/seconds). The defaults are tuned for bodies roughly 0.1m to
5
+ * 10m in size, that's what the `scale` argument of {@link Physics} is for:
6
+ * pick a scale that puts your sprites in that range and these never need
7
+ * touching.
8
+ *
9
+ * `velocityThreshold` is the one value commonly overridden per game; the
10
+ * {@link Physics} constructor forwards its third argument to
11
+ * `world.velocityThreshold`, which shadows the value here for that world.
12
+ */
13
+ const Settings = {
14
+ /** Collision tolerance. Bodies are allowed to overlap this much. */
15
+ linearSlop: 0.005,
16
+
17
+ /** Angular tolerance used by the position solver. */
18
+ angularSlop: (2 / 180) * Math.PI,
19
+
20
+ /**
21
+ * Polygons are inflated by this radius for collision, which keeps
22
+ * face-to-face contacts stable instead of flickering on and off.
23
+ */
24
+ polygonRadius: 2 * 0.005,
25
+
26
+ /** Max overlap the position solver may fix in a single iteration. */
27
+ maxLinearCorrection: 0.2,
28
+
29
+ /** Max angle the position solver may fix in a single iteration. */
30
+ maxAngularCorrection: (8 / 180) * Math.PI,
31
+
32
+ /** A body may not move further than this in one step (stability clamp). */
33
+ maxTranslation: 2,
34
+
35
+ /** A body may not rotate further than this in one step. */
36
+ maxRotation: 0.5 * Math.PI,
37
+
38
+ /** Position-correction rate for the discrete solver (0..1). */
39
+ baumgarte: 0.2,
40
+
41
+ /** Position-correction rate for the continuous (TOI) solver. */
42
+ toiBaumgarte: 0.75,
43
+
44
+ /**
45
+ * Relative normal speed below which a collision is treated as inelastic.
46
+ * Without it, resting bodies would jitter forever on their restitution.
47
+ */
48
+ velocityThreshold: 1,
49
+
50
+ /** How long a body must be nearly still before it is allowed to sleep. */
51
+ timeToSleep: 0.5,
52
+
53
+ /** Linear speed under which a body counts as "still". */
54
+ linearSleepTolerance: 0.01,
55
+
56
+ /** Angular speed under which a body counts as "still". */
57
+ angularSleepTolerance: (2 / 180) * Math.PI,
58
+
59
+ /** Broadphase AABBs are fattened by this much to avoid constant re-inserts. */
60
+ aabbExtension: 0.1,
61
+
62
+ /** Fat AABBs also lead the body's motion by this multiple of its travel. */
63
+ aabbMultiplier: 4,
64
+
65
+ /** Default velocity iterations per step. */
66
+ velocityIterations: 8,
67
+
68
+ /** Default position iterations per step. */
69
+ positionIterations: 3,
70
+
71
+ /** Max continuous-collision advancement iterations per body pair. */
72
+ maxTOIIterations: 20,
73
+
74
+ /** Max continuous-collision passes per body per step. */
75
+ maxTOIPasses: 8,
76
+ };
77
+
78
+ export default Settings;