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.
Files changed (208) hide show
  1. package/README.md +2198 -968
  2. package/dist/types/index.d.ts +75 -32
  3. package/dist/types/src/Animator.d.ts +50 -0
  4. package/dist/types/{BitmapText.d.ts → src/BitmapText.d.ts} +19 -21
  5. package/dist/types/src/Camera.d.ts +122 -0
  6. package/dist/types/src/CameraController.d.ts +107 -0
  7. package/dist/types/src/CanvasText.d.ts +91 -0
  8. package/dist/types/src/CollisionLayers.d.ts +58 -0
  9. package/dist/types/{Color.d.ts → src/Color.d.ts} +6 -6
  10. package/dist/types/src/Coroutine.d.ts +111 -0
  11. package/dist/types/src/DebugOverlay.d.ts +86 -0
  12. package/dist/types/src/Drawable.d.ts +271 -0
  13. package/dist/types/src/Easing.d.ts +22 -0
  14. package/dist/types/src/Emerald.d.ts +420 -0
  15. package/dist/types/src/EmeraldDB.d.ts +159 -0
  16. package/dist/types/{FPSCounter.d.ts → src/FPSCounter.d.ts} +1 -3
  17. package/dist/types/src/GLUtils.d.ts +4 -0
  18. package/dist/types/{Instance.d.ts → src/Instance.d.ts} +37 -15
  19. package/dist/types/{InstancedTexture.d.ts → src/InstancedTexture.d.ts} +75 -23
  20. package/dist/types/src/Interpolator.d.ts +66 -0
  21. package/dist/types/src/Material.d.ts +87 -0
  22. package/dist/types/src/MathUtils.d.ts +81 -0
  23. package/dist/types/src/ParticleEmitter.d.ts +131 -0
  24. package/dist/types/src/Physics.d.ts +337 -0
  25. package/dist/types/src/Pool.d.ts +53 -0
  26. package/dist/types/src/PostEffects.d.ts +68 -0
  27. package/dist/types/src/PostProcessor.d.ts +124 -0
  28. package/dist/types/src/RenderTarget.d.ts +56 -0
  29. package/dist/types/src/Scene.d.ts +62 -0
  30. package/dist/types/src/ScreenEffects.d.ts +111 -0
  31. package/dist/types/src/Serializer.d.ts +86 -0
  32. package/dist/types/src/Shaders.d.ts +2 -0
  33. package/dist/types/{Shapes.d.ts → src/Shapes.d.ts} +4 -6
  34. package/dist/types/src/SpatialGrid.d.ts +50 -0
  35. package/dist/types/src/SpriteBatch.d.ts +89 -0
  36. package/dist/types/src/StateMachine.d.ts +59 -0
  37. package/dist/types/src/Storage.d.ts +89 -0
  38. package/dist/types/{Texture.d.ts → src/Texture.d.ts} +3 -4
  39. package/dist/types/src/TextureAtlas.d.ts +55 -0
  40. package/dist/types/src/Tilemap.d.ts +91 -0
  41. package/dist/types/src/Time.d.ts +53 -0
  42. package/dist/types/src/Timer.d.ts +54 -0
  43. package/dist/types/src/Transform.d.ts +94 -0
  44. package/dist/types/src/Tween.d.ts +81 -0
  45. package/dist/types/src/UI.d.ts +121 -0
  46. package/dist/types/src/components/Behaviour.d.ts +71 -0
  47. package/dist/types/{components → src/components}/BoxCollider.d.ts +14 -14
  48. package/dist/types/src/components/BoxColliderDebug.d.ts +15 -0
  49. package/dist/types/{components → src/components}/CircleCollider.d.ts +14 -12
  50. package/dist/types/src/components/CircleColliderDebug.d.ts +15 -0
  51. package/dist/types/src/components/Collider.d.ts +102 -0
  52. package/dist/types/src/components/GameObject.d.ts +135 -0
  53. package/dist/types/src/components/PolygonCollider.d.ts +33 -0
  54. package/dist/types/src/components/RigidBody.d.ts +456 -0
  55. package/dist/types/src/importers/Aseprite.d.ts +79 -0
  56. package/dist/types/src/importers/ForgeLevel.d.ts +97 -0
  57. package/dist/types/src/importers/TiledMap.d.ts +62 -0
  58. package/dist/types/{lights → src/lights}/DirectionalLight.d.ts +7 -9
  59. package/dist/types/{lights → src/lights}/PointLight.d.ts +6 -9
  60. package/dist/types/src/managers/AssetManager.d.ts +116 -0
  61. package/dist/types/src/managers/AudioManager.d.ts +259 -0
  62. package/dist/types/{managers → src/managers}/CameraManager.d.ts +8 -8
  63. package/dist/types/{managers → src/managers}/EventManager.d.ts +46 -32
  64. package/dist/types/src/managers/GLManager.d.ts +84 -0
  65. package/dist/types/src/managers/GLState.d.ts +37 -0
  66. package/dist/types/src/managers/Gamepad.d.ts +102 -0
  67. package/dist/types/src/managers/IDManager.d.ts +31 -0
  68. package/dist/types/src/managers/InputManager.d.ts +381 -0
  69. package/dist/types/src/managers/NetworkManager.d.ts +93 -0
  70. package/dist/types/src/managers/RenderStats.d.ts +34 -0
  71. package/dist/types/src/managers/SceneManager.d.ts +44 -0
  72. package/dist/types/src/managers/ShaderManager.d.ts +55 -0
  73. package/dist/types/src/managers/TextureManager.d.ts +102 -0
  74. package/dist/types/src/particlesystem/Particle.d.ts +64 -0
  75. package/dist/types/{particlesystem → src/particlesystem}/ParticleSettings.d.ts +32 -24
  76. package/dist/types/{particlesystem → src/particlesystem}/Particles.d.ts +20 -12
  77. package/dist/types/src/physics/AABB.d.ts +92 -0
  78. package/dist/types/src/physics/Body.d.ts +435 -0
  79. package/dist/types/src/physics/BodyType.d.ts +6 -0
  80. package/dist/types/src/physics/BroadPhase.d.ts +210 -0
  81. package/dist/types/src/physics/Collision.d.ts +102 -0
  82. package/dist/types/src/physics/Contact.d.ts +206 -0
  83. package/dist/types/src/physics/ContactSolver.d.ts +108 -0
  84. package/dist/types/src/physics/Distance.d.ts +54 -0
  85. package/dist/types/src/physics/DistanceJoint.d.ts +90 -0
  86. package/dist/types/src/physics/Fixture.d.ts +221 -0
  87. package/dist/types/src/physics/Island.d.ts +52 -0
  88. package/dist/types/src/physics/Joint.d.ts +59 -0
  89. package/dist/types/src/physics/Math2D.d.ts +371 -0
  90. package/dist/types/src/physics/RevoluteJoint.d.ts +119 -0
  91. package/dist/types/src/physics/Settings.d.ts +22 -0
  92. package/dist/types/src/physics/Shapes.d.ts +207 -0
  93. package/dist/types/src/physics/TimeOfImpact.d.ts +22 -0
  94. package/dist/types/src/physics/World.d.ts +274 -0
  95. package/dist/types/src/physics/index.d.ts +34 -0
  96. package/index.js +78 -0
  97. package/package.json +73 -60
  98. package/src/Animator.js +95 -0
  99. package/src/BitmapText.js +6 -5
  100. package/src/Camera.js +183 -0
  101. package/src/CameraController.js +192 -0
  102. package/src/CanvasText.js +281 -0
  103. package/src/CollisionLayers.js +86 -0
  104. package/src/Color.js +26 -18
  105. package/src/Coroutine.js +259 -0
  106. package/src/DebugOverlay.js +246 -0
  107. package/src/Drawable.js +842 -582
  108. package/src/Easing.js +57 -0
  109. package/src/Emerald.js +1150 -459
  110. package/src/EmeraldDB.js +328 -0
  111. package/src/FPSCounter.js +43 -43
  112. package/src/GLUtils.js +60 -67
  113. package/src/Instance.js +41 -5
  114. package/src/InstancedTexture.js +308 -127
  115. package/src/Interpolator.js +124 -0
  116. package/src/Material.js +202 -0
  117. package/src/MathUtils.js +134 -0
  118. package/src/ParticleEmitter.js +284 -0
  119. package/src/Physics.js +431 -40
  120. package/src/Pool.js +85 -0
  121. package/src/PostEffects.js +296 -0
  122. package/src/PostProcessor.js +304 -0
  123. package/src/RenderTarget.js +134 -0
  124. package/src/Scene.js +115 -83
  125. package/src/ScreenEffects.js +266 -0
  126. package/src/Serializer.js +131 -0
  127. package/src/Shaders.js +150 -165
  128. package/src/Shapes.js +118 -129
  129. package/src/SpatialGrid.js +111 -0
  130. package/src/SpriteBatch.js +299 -0
  131. package/src/StateMachine.js +82 -0
  132. package/src/Storage.js +175 -47
  133. package/src/Texture.js +58 -67
  134. package/src/TextureAtlas.js +96 -0
  135. package/src/Tilemap.js +274 -0
  136. package/src/Time.js +51 -6
  137. package/src/Timer.js +99 -0
  138. package/src/Transform.js +100 -7
  139. package/src/Tween.js +160 -0
  140. package/src/UI.js +394 -0
  141. package/src/components/Behaviour.js +90 -0
  142. package/src/components/BoxCollider.js +29 -12
  143. package/src/components/BoxColliderDebug.js +3 -4
  144. package/src/components/CircleCollider.js +26 -12
  145. package/src/components/CircleColliderDebug.js +25 -24
  146. package/src/components/Collider.js +150 -34
  147. package/src/components/GameObject.js +130 -21
  148. package/src/components/PolygonCollider.js +55 -0
  149. package/src/components/RigidBody.js +556 -8
  150. package/src/importers/Aseprite.js +142 -0
  151. package/src/importers/ForgeLevel.js +581 -0
  152. package/src/importers/TiledMap.js +158 -0
  153. package/src/lights/DirectionalLight.js +6 -15
  154. package/src/lights/PointLight.js +4 -4
  155. package/src/managers/AssetManager.js +239 -0
  156. package/src/managers/AudioManager.js +565 -146
  157. package/src/managers/EventManager.js +488 -477
  158. package/src/managers/GLManager.js +57 -0
  159. package/src/managers/GLState.js +70 -0
  160. package/src/managers/Gamepad.js +126 -0
  161. package/src/managers/IDManager.js +24 -2
  162. package/src/managers/InputManager.js +905 -0
  163. package/src/managers/NetworkManager.js +178 -0
  164. package/src/managers/RenderStats.js +34 -0
  165. package/src/managers/SceneManager.js +30 -0
  166. package/src/managers/ShaderManager.js +0 -2
  167. package/src/managers/TextureManager.js +218 -0
  168. package/src/particlesystem/Particle.js +82 -7
  169. package/src/particlesystem/ParticleSettings.js +21 -3
  170. package/src/particlesystem/Particles.js +80 -31
  171. package/src/physics/AABB.js +207 -0
  172. package/src/physics/Body.js +862 -0
  173. package/src/physics/BodyType.js +16 -0
  174. package/src/physics/BroadPhase.js +641 -0
  175. package/src/physics/Collision.js +534 -0
  176. package/src/physics/Contact.js +500 -0
  177. package/src/physics/ContactSolver.js +526 -0
  178. package/src/physics/Distance.js +403 -0
  179. package/src/physics/DistanceJoint.js +227 -0
  180. package/src/physics/Fixture.js +346 -0
  181. package/src/physics/Island.js +203 -0
  182. package/src/physics/Joint.js +78 -0
  183. package/src/physics/Math2D.js +573 -0
  184. package/src/physics/RevoluteJoint.js +278 -0
  185. package/src/physics/Settings.js +78 -0
  186. package/src/physics/Shapes.js +549 -0
  187. package/src/physics/TimeOfImpact.js +87 -0
  188. package/src/physics/World.js +731 -0
  189. package/src/physics/index.js +79 -0
  190. package/dist/types/Drawable.d.ts +0 -157
  191. package/dist/types/Emerald.d.ts +0 -73
  192. package/dist/types/GLUtils.d.ts +0 -6
  193. package/dist/types/Physics.d.ts +0 -139
  194. package/dist/types/Scene.d.ts +0 -39
  195. package/dist/types/Shaders.d.ts +0 -4
  196. package/dist/types/Storage.d.ts +0 -46
  197. package/dist/types/Time.d.ts +0 -22
  198. package/dist/types/Transform.d.ts +0 -41
  199. package/dist/types/components/BoxColliderDebug.d.ts +0 -19
  200. package/dist/types/components/CircleColliderDebug.d.ts +0 -19
  201. package/dist/types/components/Collider.d.ts +0 -53
  202. package/dist/types/components/GameObject.d.ts +0 -72
  203. package/dist/types/components/RigidBody.d.ts +0 -104
  204. package/dist/types/managers/AudioManager.d.ts +0 -60
  205. package/dist/types/managers/GLManager.d.ts +0 -47
  206. package/dist/types/managers/IDManager.d.ts +0 -21
  207. package/dist/types/managers/SceneManager.d.ts +0 -22
  208. package/dist/types/particlesystem/Particle.d.ts +0 -42
@@ -14,13 +14,12 @@ class BoxColliderDebug {
14
14
  this.physics = this.rigidbody.physics;
15
15
  this.scale = this.physics.getScale();
16
16
  this.color = color || new Color(255, 0, 0, 255);
17
+ const body = this.rigidbody.getBody();
17
18
  this.gameObject = new GameObject(
18
19
  "BoxColliderDebug",
19
20
  new Vector3(
20
- this.rigidbody.getBody().getPosition().x *
21
- this.rigidbody.getPhysics().getScale(),
22
- this.rigidbody.getBody().getPosition().y *
23
- this.rigidbody.getPhysics().getScale(),
21
+ body.getPosition().x * this.scale,
22
+ body.getPosition().y * this.scale,
24
23
  100
25
24
  ),
26
25
  this.rigidbody.getAngle(),
@@ -1,4 +1,4 @@
1
- import * as planck from "planck";
1
+ import { Circle } from "../physics/index.js";
2
2
  import SceneManager from "../managers/SceneManager.js";
3
3
  import CircleColliderDebug from "./CircleColliderDebug.js";
4
4
  import Collider from "./Collider.js";
@@ -22,21 +22,34 @@ class CircleCollider extends Collider {
22
22
  friction,
23
23
  restitution,
24
24
  isSensor = false,
25
- parentObject = null
25
+ parentObject = null,
26
+ filter = null
26
27
  ) {
27
28
  super(rigidbody, isSensor, parentObject);
28
- this.collider = rigidbody
29
- .getBody()
30
- .createFixture(new planck.Circle(radius), {
31
- density: density,
32
- friction: friction,
33
- restitution: restitution,
34
- isSensor: isSensor,
35
- });
29
+ this.collider = rigidbody.createFixture(Circle(radius), {
30
+ density: density,
31
+ friction: friction,
32
+ restitution: restitution,
33
+ isSensor: isSensor,
34
+ });
36
35
  this.radius = radius;
37
36
  this.rigidbody.setCollider(this);
38
37
  this.name = "CircleCollider" + this.id;
39
- this.debugShape = new CircleColliderDebug(this.rigidbody);
38
+ this._applyFilterSpec(filter);
39
+ }
40
+
41
+ /**
42
+ * @method debugShape
43
+ * @description Lazily builds the debug visualization on first access, so a
44
+ * collider stays free of any GameObject/GL allocation until it is debugged.
45
+ * @returns {CircleColliderDebug} - The debug shape
46
+ */
47
+ get debugShape() {
48
+ if (!this._debugShape) {
49
+ /** @private */
50
+ this._debugShape = new CircleColliderDebug(this.rigidbody);
51
+ }
52
+ return this._debugShape;
40
53
  }
41
54
 
42
55
  /**
@@ -55,9 +68,10 @@ class CircleCollider extends Collider {
55
68
  * @description Hides the debug shape of the collider
56
69
  */
57
70
  hideDebugShape() {
71
+ if (!this._debugShape) return;
58
72
  var scene = SceneManager.getScene();
59
73
  if (scene) {
60
- scene.remove(this.debugShape.gameObject);
74
+ scene.remove(this._debugShape.gameObject);
61
75
  }
62
76
  }
63
77
 
@@ -1,4 +1,4 @@
1
- import Color from "../Color.js";
1
+ import Color from "../Color.js";
2
2
  import { Vector2, Vector3 } from "../Physics.js";
3
3
  import { Circle2D } from "../Shapes.js";
4
4
  import GameObject from "./GameObject.js";
@@ -9,28 +9,29 @@ import GameObject from "./GameObject.js";
9
9
  * @param {Color} color - The color of the collider
10
10
  */
11
11
  class CircleColliderDebug {
12
- constructor(rigidbody, color = null) {
13
- this.rigidbody = rigidbody;
14
- this.physics = this.rigidbody.physics;
15
- this.scale = this.physics.getScale();
16
- this.color = color || new Color(255, 0, 0, 255);
17
- this.gameObject = new GameObject(
18
- "CircleColliderDebug",
19
- new Vector3(
20
- this.rigidbody.getBody().getPosition().x * this.scale,
21
- this.rigidbody.getBody().getPosition().y * this.scale,
22
- 100
23
- ),
24
- this.rigidbody.getAngle(),
25
- new Vector2(
26
- this.rigidbody.getCollider().getRadius() * this.scale,
27
- this.rigidbody.getCollider().getRadius() * this.scale
28
- )
29
- );
30
- this.gameObject.addComponent(new Circle2D());
31
- this.gameObject.getComponent(Circle2D).setColor(this.color);
32
- this.gameObject.setOpacity(0.3);
33
- }
12
+ constructor(rigidbody, color = null) {
13
+ this.rigidbody = rigidbody;
14
+ this.physics = this.rigidbody.physics;
15
+ this.scale = this.physics.getScale();
16
+ this.color = color || new Color(255, 0, 0, 255);
17
+ const body = this.rigidbody.getBody();
18
+ this.gameObject = new GameObject(
19
+ "CircleColliderDebug",
20
+ new Vector3(
21
+ body.getPosition().x * this.scale,
22
+ body.getPosition().y * this.scale,
23
+ 100
24
+ ),
25
+ this.rigidbody.getAngle(),
26
+ new Vector2(
27
+ this.rigidbody.getCollider().getRadius() * this.scale,
28
+ this.rigidbody.getCollider().getRadius() * this.scale
29
+ )
30
+ );
31
+ this.gameObject.addComponent(new Circle2D());
32
+ this.gameObject.getComponent(Circle2D).setColor(this.color);
33
+ this.gameObject.setOpacity(0.3);
34
+ }
34
35
  }
35
36
 
36
- export default CircleColliderDebug;
37
+ export default CircleColliderDebug;
@@ -1,4 +1,5 @@
1
1
  import IDManager from "../managers/IDManager.js";
2
+ import CollisionLayers from "../CollisionLayers.js";
2
3
 
3
4
  /**
4
5
  * @class Collider
@@ -7,45 +8,160 @@ import IDManager from "../managers/IDManager.js";
7
8
  * @param {GameObject} parentObject - The parent object of the collider
8
9
  */
9
10
  class Collider {
10
- constructor(rigidbody, isSensor = false, parentObject = null) {
11
- this.rigidbody = rigidbody;
12
- this.parentObject = parentObject;
13
- this.isSensor = isSensor;
14
- this.id = IDManager.generateUniqueID();
15
- this.name = "Collider" + this.id;
16
- }
11
+ constructor(rigidbody, isSensor = false, parentObject = null) {
12
+ this.rigidbody = rigidbody;
13
+ this.parentObject = parentObject;
14
+ this.isSensor = isSensor;
15
+ this.id = IDManager.generateUniqueID();
16
+ this.name = "Collider" + this.id;
17
17
 
18
- /**
19
- * @method getRigidBody
20
- * @description Returns the rigidbody of the collider
21
- */
22
- getRigidBody() {
23
- return this.rigidbody;
24
- }
18
+ /** @private */
19
+ this._debugShape = null;
20
+ }
25
21
 
26
- /**
27
- * @method getCollider
28
- * @description Returns the collider
29
- */
30
- getCollider() {
31
- return this.collider;
32
- }
22
+ /**
23
+ * @method syncDebugShape
24
+ * @description Mirrors a transform onto the debug shape, but only if one has
25
+ * already been created. Never forces lazy creation.
26
+ *
27
+ * The rigidbody's spawn offset is added back, because the collider sits at
28
+ * `transform + offset` while the transform tracks the renderable. Without it
29
+ * the debug shape would drift away from the collider it is supposed to be
30
+ * showing on any body built with an offset.
31
+ *
32
+ * @param {Transform} transform - The source transform
33
+ */
34
+ syncDebugShape(transform) {
35
+ if (!this._debugShape) return;
36
+ const t = this._debugShape.gameObject.transform;
37
+ const offset =
38
+ this.rigidbody && typeof this.rigidbody.getOffset === "function"
39
+ ? this.rigidbody.getOffset()
40
+ : null;
41
+ t.position.x = transform.position.x + (offset ? offset.x : 0);
42
+ t.position.y = transform.position.y + (offset ? offset.y : 0);
43
+ t.rotation = transform.rotation;
44
+ }
33
45
 
34
- /**
35
- * @method setParent
36
- * @description Sets the parent object of the collider
37
- */
38
- setParent(parent) {
39
- this.parentObject = parent;
46
+ /**
47
+ * @method setFilter
48
+ * @description Sets the raw collision filter on this collider's
49
+ * fixture. Two fixtures collide only when each one's category bit is present
50
+ * in the other's mask. Subclasses must have created `this.collider`
51
+ * (the fixture) first.
52
+ * @param {Object} filter - { category, mask, group }
53
+ * @param {number} [filter.category=0x0001] - This fixture's category bits
54
+ * @param {number} [filter.mask=0xFFFF] - Bits this fixture collides with
55
+ * @param {number} [filter.group=0] - Group index (>0 always collide, <0 never)
56
+ * @returns {Collider} - this
57
+ */
58
+ setFilter({ category = 0x0001, mask = 0xffff, group = 0 } = {}) {
59
+ if (this.collider && typeof this.collider.setFilterData === "function") {
60
+ this.collider.setFilterData({
61
+ categoryBits: category,
62
+ maskBits: mask,
63
+ groupIndex: group,
64
+ });
65
+ /** @private */
66
+ this._filter = { category, mask, group };
40
67
  }
68
+ return this;
69
+ }
70
+
71
+ /**
72
+ * @method setCategory
73
+ * @description Sets which named layer this collider belongs to (its category
74
+ * bits), preserving the current mask/group. See {@link CollisionLayers}.
75
+ * @param {string|number} layer - Layer name or raw category bits
76
+ * @returns {Collider} - this
77
+ */
78
+ setCategory(layer) {
79
+ const category =
80
+ typeof layer === "number" ? layer : CollisionLayers.bit(layer);
81
+ const current = this._filter || {};
82
+ return this.setFilter({
83
+ category,
84
+ mask: current.mask ?? 0xffff,
85
+ group: current.group ?? 0,
86
+ });
87
+ }
88
+
89
+ /**
90
+ * @method setCollidesWith
91
+ * @description Sets which layers this collider can collide with (its mask),
92
+ * preserving the current category/group.
93
+ * @param {string|string[]|number} layers - Layer name(s) or raw mask bits
94
+ * @returns {Collider} - this
95
+ */
96
+ setCollidesWith(layers) {
97
+ const current = this._filter || {};
98
+ return this.setFilter({
99
+ category: current.category ?? 0x0001,
100
+ mask: CollisionLayers.mask(layers),
101
+ group: current.group ?? 0,
102
+ });
103
+ }
41
104
 
42
- /**
43
- * @method getParent
44
- * @description Returns the parent object of the collider
45
- */
46
- getParent() {
47
- return this.parentObject;
105
+ /**
106
+ * @method getFilter
107
+ * @description Returns the last applied filter, or null if none was set.
108
+ * @returns {{category:number, mask:number, group:number}|null}
109
+ */
110
+ getFilter() {
111
+ return this._filter || null;
112
+ }
113
+
114
+ /**
115
+ * @method _applyFilterSpec
116
+ * @description Applies a friendly filter spec from a constructor, accepting
117
+ * layer names or raw bits. Spec: { category, collidesWith, group }.
118
+ * @private
119
+ */
120
+ _applyFilterSpec(spec) {
121
+ if (!spec) return;
122
+ if (spec.category != null) this.setCategory(spec.category);
123
+ if (spec.collidesWith != null) this.setCollidesWith(spec.collidesWith);
124
+ if (spec.group != null) {
125
+ const f = this._filter || {};
126
+ this.setFilter({
127
+ category: f.category ?? 0x0001,
128
+ mask: f.mask ?? 0xffff,
129
+ group: spec.group,
130
+ });
48
131
  }
132
+ }
133
+
134
+ /**
135
+ * @method getRigidBody
136
+ * @description Returns the rigidbody of the collider
137
+ */
138
+ getRigidBody() {
139
+ return this.rigidbody;
140
+ }
141
+
142
+ /**
143
+ * @method getCollider
144
+ * @description Returns the collider
145
+ */
146
+ getCollider() {
147
+ return this.collider;
148
+ }
149
+
150
+ /**
151
+ * @method setParent
152
+ * @description Sets the parent object of the collider
153
+ */
154
+ setParent(parent) {
155
+ this.parentObject = parent;
156
+ }
157
+
158
+ /**
159
+ * @method getParent
160
+ * @description Returns the parent object of the collider
161
+ */
162
+ getParent() {
163
+ return this.parentObject;
164
+ }
49
165
  }
50
166
 
51
- export default Collider;
167
+ export default Collider;
@@ -4,6 +4,7 @@ import Transform from "../Transform.js";
4
4
  import RigidBody from "./RigidBody.js";
5
5
  import Collider from "./Collider.js";
6
6
  import Drawable from "../Drawable.js";
7
+ import Behaviour from "./Behaviour.js";
7
8
 
8
9
  /**
9
10
  * @class GameObject
@@ -24,7 +25,35 @@ class GameObject {
24
25
  this.id = IDManager.generateUniqueID();
25
26
  this.isActive = false;
26
27
  this.transform = new Transform(position, rotation, scale);
27
- this.opacity = 1.0; // 0..1 opacity multiplier for this GameObject
28
+ this.opacity = 1.0;
29
+
30
+ this.layer = 0;
31
+ this.screenSpace = false;
32
+ }
33
+
34
+ /**
35
+ * @method setLayer
36
+ * @description Sets the render layer. Objects are drawn by layer first, then
37
+ * by z within a layer.
38
+ * @param {number} layer - The layer index
39
+ * @returns {GameObject} - this
40
+ */
41
+ setLayer(layer) {
42
+ this.layer = layer;
43
+ return this;
44
+ }
45
+
46
+ /**
47
+ * @method setScreenSpace
48
+ * @description When true, the object ignores the camera (fixed on screen),
49
+ * useful for HUD/UI. Position is then in pixels from the viewport center.
50
+ * Note: not supported for InstancedTexture-based objects.
51
+ * @param {boolean} value
52
+ * @returns {GameObject} - this
53
+ */
54
+ setScreenSpace(value) {
55
+ this.screenSpace = value;
56
+ return this;
28
57
  }
29
58
 
30
59
  /**
@@ -55,11 +84,57 @@ class GameObject {
55
84
  if (component instanceof RigidBody) {
56
85
  component.destroy();
57
86
  }
87
+ if (component instanceof Behaviour) {
88
+ component.onDestroy();
89
+ }
58
90
  this.components = this.components.filter(
59
91
  (comp) => comp.id !== component.id
60
92
  );
61
93
  }
62
94
 
95
+ /**
96
+ * @method update
97
+ * @description Ticks the lifecycle of Behaviour components on this object.
98
+ * Only Behaviours are ticked here so component types with their own update
99
+ * signature (e.g. InstancedTexture) are left untouched.
100
+ * @param {number} deltaTime - Seconds since the previous frame (time-scaled)
101
+ */
102
+ update(deltaTime) {
103
+ for (const comp of this.components) {
104
+ if (comp instanceof Behaviour && comp.enabled) {
105
+ if (!comp._started) {
106
+ comp._started = true;
107
+ comp.start();
108
+ }
109
+ comp.update(deltaTime);
110
+ }
111
+ }
112
+ }
113
+
114
+ /**
115
+ * @method setParent
116
+ * @description Parents this object to another GameObject (or detaches with
117
+ * null). The object's transform then composes on top of the parent's, so
118
+ * moving/rotating/scaling the parent moves its children.
119
+ * @param {GameObject|null} parent - The parent GameObject, or null
120
+ * @returns {GameObject} - this
121
+ */
122
+ setParent(parent) {
123
+ this.transform.setParent(parent ? parent.transform : null);
124
+ return this;
125
+ }
126
+
127
+ /**
128
+ * @method addChild
129
+ * @description Parents another GameObject to this one.
130
+ * @param {GameObject} child - The child GameObject
131
+ * @returns {GameObject} - this
132
+ */
133
+ addChild(child) {
134
+ child.setParent(this);
135
+ return this;
136
+ }
137
+
63
138
  /**
64
139
  * @method setIsActive
65
140
  * @description Sets the active state of the game object
@@ -118,6 +193,56 @@ class GameObject {
118
193
  return null;
119
194
  }
120
195
 
196
+ /**
197
+ * @method syncPhysics
198
+ * @description Copies simulation state (position + rotation) from this
199
+ * object's dynamic rigidbody onto its transform, and mirrors it onto any
200
+ * visible collider debug shape. Called once per frame from the render loop so
201
+ * draw() stays read-only and physics isn't re-applied per camera. Also
202
+ * forwards to components that own their own physics-driven content (e.g.
203
+ * InstancedTexture).
204
+ */
205
+ syncPhysics() {
206
+ const rigidBody = this.getComponent(RigidBody);
207
+ if (rigidBody && rigidBody.getType() === "dynamic") {
208
+ rigidBody.syncTransform(this.transform);
209
+ const collider = rigidBody.getCollider() || this.getComponent(Collider);
210
+ if (collider && typeof collider.syncDebugShape === "function") {
211
+ collider.syncDebugShape(this.transform);
212
+ }
213
+ }
214
+ for (const comp of this.components) {
215
+ if (comp !== rigidBody && typeof comp.syncPhysics === "function") {
216
+ comp.syncPhysics();
217
+ }
218
+ }
219
+ }
220
+
221
+ /**
222
+ * @method destroy
223
+ * @description Permanently tears the object down: disposes every Drawable's
224
+ * GPU resources, destroys physics bodies, and runs Behaviour.onDestroy().
225
+ * Use it (or Scene.remove(obj, { dispose: true })) when an object will not
226
+ * be re-added: plain Scene.remove() keeps GPU resources alive for re-use.
227
+ * Safe to call twice.
228
+ */
229
+ destroy() {
230
+ if (this._destroyed) return;
231
+ /** @private */
232
+ this._destroyed = true;
233
+ this.isActive = false;
234
+ for (const comp of this.components) {
235
+ if (comp instanceof Drawable && typeof comp.dispose === "function") {
236
+ comp.dispose();
237
+ } else if (comp instanceof RigidBody) {
238
+ comp.destroy();
239
+ } else if (comp instanceof Behaviour) {
240
+ comp.onDestroy();
241
+ }
242
+ }
243
+ this.components = [];
244
+ }
245
+
121
246
  /**
122
247
  * @method draw
123
248
  * @description Draws the game object
@@ -127,31 +252,15 @@ class GameObject {
127
252
  */
128
253
  draw(globalViewMatrix, uniformLocation, currentTime) {
129
254
  const drawable = this.getComponent(Drawable);
130
- const rigidBody = this.getComponent(RigidBody);
131
- const collider = this.getComponent(Collider);
132
- if (rigidBody && rigidBody.getType() === "dynamic") {
133
- const updatedPos = rigidBody.getBody().getPosition();
134
- const rigidBodyOffset = rigidBody.getOffset();
135
- const physicsScale = rigidBody.getPhysics().getScale();
136
-
137
- this.transform.position.x =
138
- updatedPos.x * physicsScale - rigidBodyOffset.x;
139
- this.transform.position.y =
140
- updatedPos.y * physicsScale - rigidBodyOffset.y;
141
-
142
- if (collider) {
143
- collider.debugShape.gameObject.transform.position.x =
144
- this.transform.position.x;
145
- collider.debugShape.gameObject.transform.position.y =
146
- this.transform.position.y;
147
- }
148
- }
149
255
  if (drawable) {
256
+ const worldTransform = this.transform.parent
257
+ ? this.transform.getWorldTransform()
258
+ : this.transform;
150
259
  drawable.draw(
151
260
  globalViewMatrix,
152
261
  uniformLocation,
153
262
  currentTime,
154
- this.transform
263
+ worldTransform
155
264
  );
156
265
  }
157
266
  }
@@ -0,0 +1,55 @@
1
+ import { PolygonShape } from "../physics/index.js";
2
+ import Collider from "./Collider.js";
3
+
4
+ /**
5
+ * @class PolygonCollider
6
+ * @extends Collider
7
+ * @description A convex-polygon fixture, for collision shapes a box or
8
+ * circle can't approximate, like ramps, wedges, or arbitrary tile outlines (see
9
+ * {@link ForgeLevel}). Points outside the convex hull of what you pass are
10
+ * dropped automatically; a concave shape needs more than one collider.
11
+ * @param {Rigidbody} rigidbody - The rigidbody to attach the collider to
12
+ * @param {Array<{x:number,y:number}>} points - Local-space points, in
13
+ * physics units, in any order
14
+ * @param {number} density - The density of the collider
15
+ * @param {number} friction - The friction of the collider
16
+ * @param {number} restitution - The restitution of the collider
17
+ * @param {boolean} [isSensor=false] - Whether the collider is a sensor
18
+ * @param {GameObject} [parentObject=null] - The parent object of the collider
19
+ * @param {Object} [filter=null] - Collision filter spec, see {@link Collider#setFilter}
20
+ */
21
+ class PolygonCollider extends Collider {
22
+ constructor(
23
+ rigidbody,
24
+ points,
25
+ density,
26
+ friction,
27
+ restitution,
28
+ isSensor = false,
29
+ parentObject = null,
30
+ filter = null
31
+ ) {
32
+ super(rigidbody, isSensor, parentObject);
33
+ this.collider = rigidbody.createFixture(new PolygonShape(points), {
34
+ density: density,
35
+ friction: friction,
36
+ restitution: restitution,
37
+ isSensor: isSensor,
38
+ });
39
+ this.points = points;
40
+ this.rigidbody.setCollider(this);
41
+ this.name = "PolygonCollider" + this.id;
42
+ this._applyFilterSpec(filter);
43
+ }
44
+
45
+ /**
46
+ * @method getPoints
47
+ * @description Returns the local-space points this collider was built from
48
+ * @returns {Array<{x:number,y:number}>}
49
+ */
50
+ getPoints() {
51
+ return this.points;
52
+ }
53
+ }
54
+
55
+ export default PolygonCollider;