@needle-tools/engine 2.36.0-pre → 2.38.0-pre

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 (143) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/dist/needle-engine.d.ts +248 -151
  3. package/dist/needle-engine.js +451 -437
  4. package/dist/needle-engine.js.map +4 -4
  5. package/dist/needle-engine.min.js +82 -82
  6. package/dist/needle-engine.min.js.map +4 -4
  7. package/lib/engine/api.d.ts +1 -0
  8. package/lib/engine/api.js +1 -0
  9. package/lib/engine/api.js.map +1 -1
  10. package/lib/engine/debug/debug.d.ts +1 -0
  11. package/lib/engine/debug/debug.js +3 -0
  12. package/lib/engine/debug/debug.js.map +1 -1
  13. package/lib/engine/engine_addressables.d.ts +3 -1
  14. package/lib/engine/engine_addressables.js +12 -5
  15. package/lib/engine/engine_addressables.js.map +1 -1
  16. package/lib/engine/engine_element.js +3 -2
  17. package/lib/engine/engine_element.js.map +1 -1
  18. package/lib/engine/engine_element_overlay.js +4 -3
  19. package/lib/engine/engine_element_overlay.js.map +1 -1
  20. package/lib/engine/engine_gameobject.js +2 -1
  21. package/lib/engine/engine_gameobject.js.map +1 -1
  22. package/lib/engine/engine_input.d.ts +2 -0
  23. package/lib/engine/engine_input.js +14 -3
  24. package/lib/engine/engine_input.js.map +1 -1
  25. package/lib/engine/engine_physics.d.ts +35 -46
  26. package/lib/engine/engine_physics.js +479 -386
  27. package/lib/engine/engine_physics.js.map +1 -1
  28. package/lib/engine/engine_physics.types.d.ts +23 -0
  29. package/lib/engine/engine_physics.types.js +27 -0
  30. package/lib/engine/engine_physics.types.js.map +1 -0
  31. package/lib/engine/engine_serialization_core.d.ts +3 -0
  32. package/lib/engine/engine_serialization_core.js +5 -0
  33. package/lib/engine/engine_serialization_core.js.map +1 -1
  34. package/lib/engine/engine_setup.d.ts +7 -1
  35. package/lib/engine/engine_setup.js +13 -3
  36. package/lib/engine/engine_setup.js.map +1 -1
  37. package/lib/engine/engine_types.d.ts +45 -26
  38. package/lib/engine/engine_types.js +24 -37
  39. package/lib/engine/engine_types.js.map +1 -1
  40. package/lib/engine/engine_util_decorator.d.ts +6 -0
  41. package/lib/engine/engine_util_decorator.js +54 -0
  42. package/lib/engine/engine_util_decorator.js.map +1 -0
  43. package/lib/engine/engine_utils.d.ts +1 -1
  44. package/lib/engine/engine_utils.js +1 -1
  45. package/lib/engine/engine_utils.js.map +1 -1
  46. package/lib/engine/extensions/NEEDLE_gameobject_data.js +2 -0
  47. package/lib/engine/extensions/NEEDLE_gameobject_data.js.map +1 -1
  48. package/lib/engine-components/Animation.d.ts +7 -5
  49. package/lib/engine-components/Animation.js +7 -7
  50. package/lib/engine-components/Animation.js.map +1 -1
  51. package/lib/engine-components/AnimatorController.js +14 -7
  52. package/lib/engine-components/AnimatorController.js.map +1 -1
  53. package/lib/engine-components/BoxHelperComponent.js +1 -0
  54. package/lib/engine-components/BoxHelperComponent.js.map +1 -1
  55. package/lib/engine-components/Camera.d.ts +1 -0
  56. package/lib/engine-components/Camera.js +20 -5
  57. package/lib/engine-components/Camera.js.map +1 -1
  58. package/lib/engine-components/CharacterController.d.ts +31 -0
  59. package/lib/engine-components/CharacterController.js +167 -0
  60. package/lib/engine-components/CharacterController.js.map +1 -0
  61. package/lib/engine-components/Collider.d.ts +16 -5
  62. package/lib/engine-components/Collider.js +45 -23
  63. package/lib/engine-components/Collider.js.map +1 -1
  64. package/lib/engine-components/Component.d.ts +6 -15
  65. package/lib/engine-components/Component.js +7 -112
  66. package/lib/engine-components/Component.js.map +1 -1
  67. package/lib/engine-components/DragControls.js +9 -6
  68. package/lib/engine-components/DragControls.js.map +1 -1
  69. package/lib/engine-components/Light.d.ts +2 -0
  70. package/lib/engine-components/Light.js +13 -2
  71. package/lib/engine-components/Light.js.map +1 -1
  72. package/lib/engine-components/NavMesh.d.ts +0 -5
  73. package/lib/engine-components/NavMesh.js +100 -10
  74. package/lib/engine-components/NavMesh.js.map +1 -1
  75. package/lib/engine-components/NestedGltf.js +2 -0
  76. package/lib/engine-components/NestedGltf.js.map +1 -1
  77. package/lib/engine-components/Renderer.js +4 -0
  78. package/lib/engine-components/Renderer.js.map +1 -1
  79. package/lib/engine-components/RigidBody.d.ts +45 -25
  80. package/lib/engine-components/RigidBody.js +290 -142
  81. package/lib/engine-components/RigidBody.js.map +1 -1
  82. package/lib/engine-components/SmoothFollow.d.ts +2 -1
  83. package/lib/engine-components/SmoothFollow.js +25 -17
  84. package/lib/engine-components/SmoothFollow.js.map +1 -1
  85. package/lib/engine-components/SpatialTrigger.js +1 -1
  86. package/lib/engine-components/SpatialTrigger.js.map +1 -1
  87. package/lib/engine-components/SpectatorCamera.d.ts +1 -0
  88. package/lib/engine-components/SpectatorCamera.js +9 -2
  89. package/lib/engine-components/SpectatorCamera.js.map +1 -1
  90. package/lib/engine-components/SpringJoint.d.ts +0 -13
  91. package/lib/engine-components/SpringJoint.js +42 -41
  92. package/lib/engine-components/SpringJoint.js.map +1 -1
  93. package/lib/engine-components/VideoPlayer.js.map +1 -1
  94. package/lib/engine-components/WebXR.d.ts +1 -0
  95. package/lib/engine-components/WebXR.js +13 -6
  96. package/lib/engine-components/WebXR.js.map +1 -1
  97. package/lib/engine-components/WebXRController.js +12 -6
  98. package/lib/engine-components/WebXRController.js.map +1 -1
  99. package/lib/engine-components/codegen/components.d.ts +4 -3
  100. package/lib/engine-components/codegen/components.js +4 -3
  101. package/lib/engine-components/codegen/components.js.map +1 -1
  102. package/package.json +3 -4
  103. package/src/engine/api.ts +2 -1
  104. package/src/engine/codegen/register_types.js +16 -12
  105. package/src/engine/debug/debug.ts +4 -0
  106. package/src/engine/dist/engine_physics.js +739 -0
  107. package/src/engine/dist/engine_setup.js +777 -0
  108. package/src/engine/engine_addressables.ts +18 -8
  109. package/src/engine/engine_element.ts +3 -2
  110. package/src/engine/engine_element_overlay.ts +4 -3
  111. package/src/engine/engine_gameobject.ts +4 -4
  112. package/src/engine/engine_input.ts +12 -3
  113. package/src/engine/engine_physics.ts +492 -418
  114. package/src/engine/engine_physics.types.ts +28 -0
  115. package/src/engine/engine_serialization_core.ts +8 -1
  116. package/src/engine/engine_setup.ts +31 -18
  117. package/src/engine/engine_types.ts +83 -56
  118. package/src/engine/engine_util_decorator.ts +69 -0
  119. package/src/engine/engine_utils.ts +3 -3
  120. package/src/engine/extensions/NEEDLE_gameobject_data.ts +2 -0
  121. package/src/engine-components/Animation.ts +18 -12
  122. package/src/engine-components/AnimatorController.ts +16 -11
  123. package/src/engine-components/BoxHelperComponent.ts +1 -0
  124. package/src/engine-components/Camera.ts +21 -4
  125. package/src/engine-components/CharacterController.ts +171 -0
  126. package/src/engine-components/Collider.ts +49 -39
  127. package/src/engine-components/Component.ts +15 -130
  128. package/src/engine-components/DragControls.ts +9 -5
  129. package/src/engine-components/Light.ts +17 -3
  130. package/src/engine-components/NavMesh.ts +114 -115
  131. package/src/engine-components/NestedGltf.ts +2 -0
  132. package/src/engine-components/Renderer.ts +5 -1
  133. package/src/engine-components/RigidBody.ts +292 -149
  134. package/src/engine-components/SmoothFollow.ts +21 -18
  135. package/src/engine-components/SpatialTrigger.ts +1 -1
  136. package/src/engine-components/SpectatorCamera.ts +10 -2
  137. package/src/engine-components/SpringJoint.ts +41 -41
  138. package/src/engine-components/VideoPlayer.ts +1 -2
  139. package/src/engine-components/WebXR.ts +15 -6
  140. package/src/engine-components/WebXRController.ts +16 -7
  141. package/src/engine-components/codegen/components.ts +4 -3
  142. package/src/engine-components/dist/CharacterController.js +123 -0
  143. package/src/engine-components/dist/RigidBody.js +458 -0
@@ -0,0 +1,28 @@
1
+
2
+
3
+ export enum CollisionDetectionMode {
4
+ Discrete = 0,
5
+ Continuous = 1,
6
+ }
7
+
8
+ export enum RigidbodyConstraints {
9
+ None = 0,
10
+ FreezePositionX = 2,
11
+ FreezePositionY = 4,
12
+ FreezePositionZ = 8,
13
+ FreezePosition = 14,
14
+ FreezeRotationX = 16,
15
+ FreezeRotationY = 32,
16
+ FreezeRotationZ = 64,
17
+ FreezeRotation = 112,
18
+ FreezeAll = 126,
19
+ }
20
+
21
+
22
+ export enum Axes {
23
+ None = 0,
24
+ X = 2,
25
+ Y = 4,
26
+ Z = 8,
27
+ All = ~0,
28
+ }
@@ -3,7 +3,7 @@ import { getParam } from "./engine_utils";
3
3
  import { Object3D } from "three";
4
4
  import { Context } from "./engine_setup";
5
5
  import { isPersistentAsset } from "./extensions/NEEDLE_persistent_assets";
6
- import { SourceIdentifier } from "./engine_types";
6
+ import { IComponent, SourceIdentifier } from "./engine_types";
7
7
  import { debugExtension } from "../engine/engine_default_parameters";
8
8
  import { LogType, showBalloonMessage } from "./debug/debug";
9
9
  import { isLocalNetwork } from "./engine_networking_utils";
@@ -11,6 +11,7 @@ import { $BuiltInTypeFlag } from "./engine_typestore";
11
11
 
12
12
  const debug = getParam("debugserializer");
13
13
 
14
+
14
15
  export type Constructor<T> = { new(...args: any[]): T };
15
16
  export declare type NodeToObjectMap = { [nodeId: string]: Object3D };
16
17
  export declare type ObjectToNodeMap = { [uuid: string]: number };
@@ -516,6 +517,10 @@ function setBuffer(value): Array<any> {
516
517
  }
517
518
 
518
519
 
520
+ /** set to true while assigning properties during instantiation.
521
+ * Used for validate decorator to not invoke callbacks on components that are currently in the process of being built */
522
+ export const $isAssigningProperties = Symbol("assigned component properties");
523
+
519
524
  // const developmentMode = getParam("dev")
520
525
 
521
526
  /** Object.assign behaviour but check if property is writeable (e.g. getter only properties are skipped) */
@@ -540,6 +545,7 @@ export function assign(target: any, source: any) {
540
545
  // if (developmentMode)
541
546
  // onlyDeclared = false;
542
547
 
548
+ target[$isAssigningProperties] = true;
543
549
  for (const key of Object.keys(source)) {
544
550
  const desc = getPropertyDescriptor(target, key);
545
551
  if (onlyDeclared && desc === undefined) continue;
@@ -550,6 +556,7 @@ export function assign(target: any, source: any) {
550
556
  target[key] = source[key];
551
557
  }
552
558
  }
559
+ delete target[$isAssigningProperties];
553
560
  }
554
561
 
555
562
  // we need to recurse because the property might be defined in a base class
@@ -58,6 +58,7 @@ export class ContextArgs {
58
58
  alias: string | undefined | null = undefined;
59
59
  domElement: HTMLElement | null;
60
60
  renderer?: THREE.WebGLRenderer = undefined;
61
+ hash?: string;
61
62
 
62
63
  constructor(domElement: HTMLElement | null) {
63
64
  this.domElement = domElement ?? document.body;
@@ -70,7 +71,8 @@ export enum FrameEvent {
70
71
  LateUpdate = 2,
71
72
  OnBeforeRender = 3,
72
73
  OnAfterRender = 4,
73
- PhysicsStep = 10,
74
+ PrePhysicsStep = 9,
75
+ PostPhysicsStep = 10,
74
76
  }
75
77
 
76
78
  export enum XRSessionMode {
@@ -81,12 +83,12 @@ export enum XRSessionMode {
81
83
  export declare type OnBeforeRenderCallback = (renderer: THREE.WebGLRenderer, scene: THREE.Scene, camera: THREE.Camera, geometry: THREE.BufferGeometry, material: THREE.Material, group: THREE.Group) => void
82
84
 
83
85
 
84
- export function registerComponent(script : IComponent, context?: Context) {
85
- if (!script) return;
86
- const new_scripts = context?.new_scripts ?? Context.Current.new_scripts;
87
- if (!new_scripts.includes(script)) {
88
- new_scripts.push(script);
89
- }
86
+ export function registerComponent(script: IComponent, context?: Context) {
87
+ if (!script) return;
88
+ const new_scripts = context?.new_scripts ?? Context.Current.new_scripts;
89
+ if (!new_scripts.includes(script)) {
90
+ new_scripts.push(script);
91
+ }
90
92
  }
91
93
 
92
94
  export class Context {
@@ -105,13 +107,16 @@ export class Context {
105
107
  alias: string | undefined | null;
106
108
  isManagedExternally: boolean = false;
107
109
 
110
+ /** used to append to loaded assets */
111
+ hash?: string;
112
+
108
113
  domElement: HTMLElement;
109
114
  get resolutionScaleFactor() { return this._resolutionScaleFactor; }
110
115
  /** use to scale the resolution up or down of the renderer. default is 1 */
111
- set resolutionScaleFactor(val: number) {
112
- if(val === this._resolutionScaleFactor) return;
113
- if(typeof val !== "number") return;
114
- if(val <= 0) {
116
+ set resolutionScaleFactor(val: number) {
117
+ if (val === this._resolutionScaleFactor) return;
118
+ if (typeof val !== "number") return;
119
+ if (val <= 0) {
115
120
  console.error("Invalid resolution scale factor", val);
116
121
  return;
117
122
  }
@@ -124,7 +129,9 @@ export class Context {
124
129
  get domX(): number { return this.domElement.offsetLeft; }
125
130
  get domY(): number { return this.domElement.offsetTop; }
126
131
  get isInXR() { return this.renderer.xr?.isPresenting || false; }
127
- xrSessionMode : XRSessionMode | undefined = undefined;
132
+ xrSessionMode: XRSessionMode | undefined = undefined;
133
+ get isInVR() { return this.xrSessionMode === XRSessionMode.ImmersiveVR; }
134
+ get isInAR() { return this.xrSessionMode === XRSessionMode.ImmersiveAR; }
128
135
  get xrSession() { return this.renderer.xr?.getSession(); }
129
136
  get arOverlayElement(): HTMLElement {
130
137
  const el = this.domElement as any;
@@ -182,7 +189,7 @@ export class Context {
182
189
  rendererData: RendererData;
183
190
  addressables: Addressables;
184
191
  lightmaps: ILightDataRegistry;
185
- players : PlayerViewManager;
192
+ players: PlayerViewManager;
186
193
 
187
194
  private _sizeChanged: boolean = false;
188
195
  private _isCreated: boolean = false;
@@ -193,6 +200,7 @@ export class Context {
193
200
  this.name = args?.name || "";
194
201
  this.alias = args?.alias;
195
202
  this.domElement = args?.domElement || document.body;
203
+ this.hash = args?.hash;
196
204
  if (args?.renderer) {
197
205
  this.renderer = args.renderer;
198
206
  this.isManagedExternally = true;
@@ -232,7 +240,7 @@ export class Context {
232
240
  this.lightmaps = new LightDataRegistry(this);
233
241
  this.players = new PlayerViewManager(this);
234
242
 
235
- window.addEventListener('resize', () => this._sizeChanged = true );
243
+ window.addEventListener('resize', () => this._sizeChanged = true);
236
244
  const ro = new ResizeObserver(_ => this._sizeChanged = true);
237
245
  ro.observe(this.domElement);
238
246
  }
@@ -335,13 +343,13 @@ export class Context {
335
343
  }
336
344
 
337
345
  removeCamera(cam?: Camera | null) {
338
- if(!cam) return;
346
+ if (!cam) return;
339
347
  const index = this._cameraStack.indexOf(cam);
340
348
  if (index >= 0) this._cameraStack.splice(index, 1);
341
349
 
342
350
  if (this.mainCameraComponent === cam) {
343
351
  this.mainCameraComponent = undefined;
344
-
352
+
345
353
  if (this._cameraStack.length > 0) {
346
354
  const last = this._cameraStack[this._cameraStack.length - 1];
347
355
  this.setCurrentCamera(last);
@@ -400,6 +408,10 @@ export class Context {
400
408
  }
401
409
 
402
410
  private async internalOnCreate(buildScene: (context: Context, opts?: LoadingOptions) => Promise<void>, opts?: LoadingOptions) {
411
+
412
+ // TODO: we could configure if we need physics
413
+ await this.physics.createWorld();
414
+
403
415
  // load and create scene
404
416
  let prepare_succeeded = true;
405
417
  try {
@@ -562,11 +574,12 @@ export class Context {
562
574
  this.executeCoroutines(FrameEvent.LateUpdate);
563
575
 
564
576
  try {
565
- const physicsSteps = 2;
577
+ const physicsSteps = 1;
566
578
  const dt = this.time.deltaTime / physicsSteps;
567
579
  for (let i = 0; i < physicsSteps; i++) {
580
+ this.executeCoroutines(FrameEvent.PrePhysicsStep);
568
581
  this.physics.step(dt);
569
- this.executeCoroutines(FrameEvent.PhysicsStep);
582
+ this.executeCoroutines(FrameEvent.PostPhysicsStep);
570
583
  }
571
584
  }
572
585
  catch (err) {
@@ -1,6 +1,6 @@
1
- import { Camera, Color, Material, Object3D, Vector3 } from "three";
2
- import { Body, ContactEquation } from "cannon-es";
1
+ import { Camera, Color, Material, Object3D, Vector3, Quaternion } from "three";
3
2
  import { RGBAColor } from "../engine-components/js-extensions/RGBAColor";
3
+ import { CollisionDetectionMode, RigidbodyConstraints } from "./engine_physics.types";
4
4
 
5
5
  /** used to find data registered via gltf files e.g. find lightmaps for a Renderer component that were shipped inside a gltf */
6
6
  export declare type SourceIdentifier = string;
@@ -58,9 +58,10 @@ export interface IComponent {
58
58
  onDisable();
59
59
  onDestroy();
60
60
 
61
+ /** called for properties decorated with the @validate decorator */
62
+ onValidate?(property?: string);
63
+
61
64
  start?(): void;
62
- // available update loop events:
63
- // earlyUpdate, update, lateUpdate, onBeforeRender, onAfterRender
64
65
  earlyUpdate?(): void;
65
66
  update?(): void;
66
67
  lateUpdate?(): void;
@@ -69,17 +70,15 @@ export interface IComponent {
69
70
 
70
71
  onCollisionEnter?(col: Collision);
71
72
  onCollisionExit?(col: Collision);
72
- onCollisionExitRaw?(col: Collision);
73
73
  onCollisionStay?(col: Collision);
74
74
 
75
- onTriggerEnter?(col: Collision);
76
- onTriggerStay?(col: Collision);
77
- onTriggerExit?(col: Collision);
78
-
79
- __internalHandleCollision(col: Collision, isTriggerCollision: boolean);
80
- __internalHandleExitCollisionEvent(obj: Object3D, isTriggerCollision: boolean);
75
+ onTriggerEnter?(col: ICollider);
76
+ onTriggerStay?(col: ICollider);
77
+ onTriggerExit?(col: ICollider);
81
78
 
82
79
  get forward(): Vector3;
80
+ get worldPosition(): Vector3;
81
+ get worldQuaternion(): Quaternion;
83
82
  }
84
83
 
85
84
 
@@ -101,8 +100,8 @@ export declare interface ILight extends IComponent {
101
100
  }
102
101
 
103
102
  export declare interface ISharedMaterials {
104
- [num:number] : Material;
105
- get length() : number;
103
+ [num: number]: Material;
104
+ get length(): number;
106
105
  }
107
106
 
108
107
  export declare interface IRenderer extends IComponent {
@@ -110,6 +109,10 @@ export declare interface IRenderer extends IComponent {
110
109
  get sharedMaterials(): ISharedMaterials;
111
110
  }
112
111
 
112
+ // export declare interface IPhysicsComponent extends IComponent {
113
+ // get type() : string;
114
+ // }
115
+
113
116
  export declare interface ICollider extends IComponent {
114
117
  get isCollider();
115
118
  attachedRigidbody: IRigidbody | null;
@@ -117,67 +120,99 @@ export declare interface ICollider extends IComponent {
117
120
  }
118
121
 
119
122
  export declare interface IRigidbody extends IComponent {
120
- initialize(): void;
121
- body;
123
+ constraints: RigidbodyConstraints;
124
+ isKinematic: boolean;
125
+ mass: number;
126
+ drag: number;
127
+ angularDrag: number;
128
+ useGravity: boolean;
129
+ collisionDetectionMode: CollisionDetectionMode;
130
+
131
+ lockPositionX: boolean;
132
+ lockPositionY: boolean;
133
+ lockPositionZ: boolean;
134
+ lockRotationX: boolean;
135
+ lockRotationY: boolean;
136
+ lockRotationZ: boolean;
122
137
  }
123
138
 
124
139
 
140
+ export const $physicsKey = Symbol("object");
125
141
 
126
142
 
143
+ export declare type ICollisionContext = {
144
+ getCollider(obj: Object3D): ICollider;
145
+ }
127
146
 
128
147
 
129
-
130
- export const $physicsKey = Symbol("object");
131
-
132
- export declare type CannonCollision = {
133
- body: Body;
134
- contact: ContactEquation;
135
- target: Body;
136
- type: string;
148
+ export type Vec3 = {
149
+ x: number,
150
+ y: number,
151
+ z: number
137
152
  }
138
153
 
139
- export declare type ICollisionContext = {
140
- getCollider(obj: Object3D): ICollider;
154
+ export type Vec2 = {
155
+ x: number,
156
+ y: number
141
157
  }
142
158
 
143
- export class Collision {
159
+ export class ContactPoint {
144
160
 
145
- get __internalCollision(): CannonCollision {
146
- return this.collision;
147
- }
161
+ readonly localPoint: Vec3;
162
+ readonly distance: number;
163
+ readonly normal: Vec3;
148
164
 
149
- get __internalInvertedSourceReceiver(): boolean {
150
- return this.invert;
165
+ constructor(localPt: Vec3, dist: number, normal: Vec3) {
166
+ this.localPoint = localPt;
167
+ this.distance = dist;
168
+ this.normal = normal;
151
169
  }
152
170
 
153
- private readonly invert: boolean;
154
- private readonly collision: CannonCollision;
155
- private readonly targetBody: Body;
156
- private readonly context: ICollisionContext;
171
+ }
157
172
 
158
- readonly me: Object3D;
173
+ /// all info in here must be readonly because the object is only created once per started collision
174
+ export class Collision {
175
+
176
+ readonly contacts: ContactPoint[];
159
177
 
160
- private _normal?: Vector3;
161
- get normal(): Vector3 {
162
- if (!this._normal) {
163
- const vec = this.collision.contact.ni;
164
- this._normal = new Vector3(vec.x, vec.y, vec.z);
165
- }
166
- return this._normal;
178
+ constructor(obj: Object3D, otherCollider: ICollider, contacts: ContactPoint[]) {
179
+ this.me = obj;
180
+ this._collider = otherCollider;
181
+ this._gameObject = otherCollider.gameObject;
182
+ this.contacts = contacts;
167
183
  }
168
184
 
169
- private _collider?: ICollider;
185
+ readonly me: Object3D;
186
+ private _collider: ICollider;
187
+
188
+ /** the collider the collision happened with */
170
189
  get collider(): ICollider {
171
- if (!this._collider) {
172
- this._collider = this.context.getCollider(this.gameObject);
173
- }
174
190
  return this._collider;
175
191
  }
176
192
 
193
+ /** the object the collision happened with */
194
+ private _gameObject: Object3D;
177
195
  get gameObject(): Object3D {
178
- return this.targetBody[$physicsKey];
196
+ return this._gameObject;
197
+ }
198
+
199
+ /** the rigidbody we hit, null if none attached */
200
+ get rigidBody(): IRigidbody | null {
201
+ return this.collider?.attachedRigidbody;
179
202
  }
180
203
 
204
+
205
+
206
+ // private _normal?: Vector3;
207
+ // get normal(): Vector3 {
208
+ // if (!this._normal) {
209
+ // const vec = this.collision.contact.ni;
210
+ // this._normal = new Vector3(vec.x, vec.y, vec.z);
211
+ // }
212
+ // return this._normal;
213
+ // }
214
+
215
+
181
216
  // private _point?: Vector3;
182
217
  // get point(): Vector3 {
183
218
  // if (!this._point) {
@@ -187,12 +222,4 @@ export class Collision {
187
222
  // }
188
223
  // return this._point;
189
224
  // }
190
-
191
- constructor(obj: Object3D, collision: CannonCollision, context: ICollisionContext, invert: boolean = false) {
192
- this.me = obj;
193
- this.collision = collision;
194
- this.context = context;
195
- this.targetBody = invert ? collision.target : collision.body;
196
- this.invert = invert;
197
- }
198
225
  }
@@ -0,0 +1,69 @@
1
+ import { $isAssigningProperties } from "./engine_serialization_core";
2
+ import { LogType, showBalloonMessage } from "./debug/debug";
3
+ import { IComponent } from "./engine_types";
4
+
5
+
6
+ declare type setter = (v: any) => void;
7
+ declare type getter = () => any;
8
+
9
+ /** create accessor callbacks for a field */
10
+ export const validate = function (set?: setter, get?: getter) {
11
+ // "descriptor : undefined" prevents @validate() to be added to property getters or setters
12
+ return function (target: IComponent | any, propertyKey: string, descriptor?: undefined) {
13
+ createPropertyWrapper(target, propertyKey, descriptor, set, get);
14
+ }
15
+ }
16
+
17
+
18
+ function createPropertyWrapper(target: IComponent | any, propertyKey: string, descriptor?: PropertyDescriptor,
19
+ set?: setter,
20
+ get?: getter) {
21
+
22
+ if (!get && !set && !target.onValidate) return;
23
+
24
+ // this is not undefined when its a property getter or setter already and not just a field
25
+ // we currently only support validation of fields
26
+ if (descriptor !== undefined) {
27
+ console.error("Invalid usage of validate decorator. Only fields can be validated.", target, propertyKey, descriptor);
28
+ showBalloonMessage("Invalid usage of validate decorator. Only fields can be validated. Property: " + propertyKey, LogType.Error);
29
+ return;
30
+ }
31
+
32
+ if (target.__internalAwake) {
33
+ // this is the hidden key we save the original property to
34
+ const $prop = Symbol(propertyKey);
35
+ // save the original awake method
36
+ // we need to delay decoration until the object has been created
37
+ const awake = target.__internalAwake;
38
+ target.__internalAwake = function () {
39
+
40
+ // only build wrapper once per type
41
+ if (this[$prop] === undefined) {
42
+
43
+ // make sure the field is initialized in a hidden property
44
+ this[$prop] = this[propertyKey];
45
+
46
+ Object.defineProperty(this, propertyKey, {
47
+ set: function (v) {
48
+ if (this[$isAssigningProperties] === true) {
49
+ this[$prop] = v;
50
+ }
51
+ else {
52
+ set?.call(this, v);
53
+ const oldValue = this[$prop];
54
+ this[$prop] = v;
55
+ this.onValidate?.call(this, propertyKey, oldValue);
56
+ }
57
+ },
58
+ get: function () {
59
+ get?.call(this);
60
+ return this[$prop];
61
+ },
62
+ });
63
+ }
64
+
65
+ // call the original awake method
66
+ awake.call(this);
67
+ };
68
+ }
69
+ }
@@ -217,7 +217,7 @@ export function getPath(source: SourceIdentifier | undefined, uri: string): stri
217
217
  // }
218
218
 
219
219
 
220
- export type WriteCallback = (data: any) => void;
220
+ export type WriteCallback = (data: any, prop: string) => void;
221
221
 
222
222
  export interface IWatch {
223
223
  subscribeWrite(callback: WriteCallback);
@@ -268,7 +268,7 @@ class WatchImpl implements IWatch {
268
268
  const setter = (value) => {
269
269
  object[this._wrapperProp] = value;
270
270
  for (const write of this.writeCallbacks) {
271
- write(value);
271
+ write(value, this._prop);
272
272
  }
273
273
  }
274
274
  // add the wrapper to the object
@@ -321,7 +321,7 @@ export class Watch implements IWatch {
321
321
  apply() {
322
322
  for (const w of this._watches) {
323
323
  w.apply();
324
- }
324
+ }
325
325
  }
326
326
 
327
327
  revoke() {
@@ -66,6 +66,8 @@ export class NEEDLE_gameobject_data implements GLTFLoaderPlugin {
66
66
 
67
67
  private applyExtensionData(node: Object3D, ext: GameObjectData) {
68
68
  node.userData.layer = ext.layers;
69
+ node.layers.disableAll();
70
+ node.layers.set(ext.layers);
69
71
  node.userData.tag = ext.tag;
70
72
  node.userData.hideFlags = ext.hideFlags;
71
73
  node.userData.static = ext.static;
@@ -5,6 +5,7 @@ import { MixerEvent } from "./Animator";
5
5
  import { serializeable } from "../engine/engine_serialization_decorator";
6
6
  import { InstancingUtil } from "../engine/engine_instancing";
7
7
  import { Mathf } from "../engine/engine_math";
8
+ import { Vec2 } from "../engine/engine_types";
8
9
 
9
10
  export declare class PlayOptions {
10
11
  fadeDuration?: number;
@@ -13,8 +14,8 @@ export declare class PlayOptions {
13
14
  startTime?: number;
14
15
  endTime?: number;
15
16
  clampWhenFinished?: boolean;
16
- minMaxSpeed?: Vector2;
17
- minMaxOffsetNormalized?: Vector2;
17
+ minMaxSpeed?: Vec2;
18
+ minMaxOffsetNormalized?: Vec2;
18
19
  }
19
20
 
20
21
  export class Animation extends Behaviour {
@@ -24,11 +25,8 @@ export class Animation extends Behaviour {
24
25
  @serializeable()
25
26
  randomStartTime: boolean = true;
26
27
 
27
- @serializeable(Vector2)
28
- minMaxSpeed?: Vector2;
29
-
30
- @serializeable(Vector2)
31
- minMaxOffsetNormalized?: Vector2;
28
+ minMaxSpeed?: Vec2;
29
+ minMaxOffsetNormalized?: Vec2;
32
30
 
33
31
  private _tempAnimationClipBeforeGameObjectExisted: AnimationClip | null = null;
34
32
  get clip(): AnimationClip | null {
@@ -114,6 +112,14 @@ export class Animation extends Behaviour {
114
112
  return this.actions?.find(a => a.getClip().name === name);
115
113
  }
116
114
 
115
+ get isPlaying() {
116
+ for (let i = 0; i < this._currentActions.length; i++) {
117
+ if (this._currentActions[i].isRunning())
118
+ return true;
119
+ }
120
+ return false;
121
+ }
122
+
117
123
  play(clipOrNumber: AnimationClip | number | string, options?: PlayOptions): Promise<AnimationAction> | void {
118
124
  this.init();
119
125
  if (!this.mixer) return;
@@ -129,9 +135,9 @@ export class Animation extends Behaviour {
129
135
  console.error("Could not find clip", clipOrNumber)
130
136
  return;
131
137
  }
132
- if(!options) options = {};
133
- if(!options.minMaxOffsetNormalized) options.minMaxOffsetNormalized = this.minMaxOffsetNormalized;
134
- if(!options.minMaxSpeed) options.minMaxSpeed = this.minMaxSpeed;
138
+ if (!options) options = {};
139
+ if (!options.minMaxOffsetNormalized) options.minMaxOffsetNormalized = this.minMaxOffsetNormalized;
140
+ if (!options.minMaxSpeed) options.minMaxSpeed = this.minMaxSpeed;
135
141
  for (const act of this.actions) {
136
142
  if (act.getClip() === clip) {
137
143
  return this.internalOnPlay(act, options);
@@ -163,8 +169,8 @@ export class Animation extends Behaviour {
163
169
  action.time = 0;
164
170
  action.timeScale = 1;
165
171
  const clip = action.getClip();
166
- if(options?.minMaxOffsetNormalized) action.time = Mathf.lerp(options.minMaxOffsetNormalized.x, options.minMaxOffsetNormalized.y, Math.random()) * clip.duration;
167
- if(options?.minMaxSpeed) action.timeScale = Mathf.lerp(options.minMaxSpeed.x, options.minMaxSpeed.y, Math.random());
172
+ if (options?.minMaxOffsetNormalized) action.time = Mathf.lerp(options.minMaxOffsetNormalized.x, options.minMaxOffsetNormalized.y, Math.random()) * clip.duration;
173
+ if (options?.minMaxSpeed) action.timeScale = Mathf.lerp(options.minMaxSpeed.x, options.minMaxSpeed.y, Math.random());
168
174
  if (options?.clampWhenFinished) action.clampWhenFinished = true;
169
175
  if (options?.startTime !== undefined) action.time = options.startTime;
170
176
 
@@ -218,7 +218,7 @@ export class AnimatorController {
218
218
  if (!allConditionsAreMet) continue;
219
219
 
220
220
  if (debug && allConditionsAreMet) {
221
- console.log("All conditions are met", transition);
221
+ // console.log("All conditions are met", transition);
222
222
  }
223
223
 
224
224
  // disable triggers
@@ -232,16 +232,16 @@ export class AnimatorController {
232
232
  if (action) {
233
233
  const dur = state.motion.clip!.duration;
234
234
  const normalizedTime = dur <= 0 ? 1 : action.time / dur;
235
- if (!transition.hasExitTime
236
- || (normalizedTime >= transition.exitTime && action.time >= action.getClip().duration
237
- )
238
- ) {
235
+ const makeTransition = transition.hasExitTime ? normalizedTime >= transition.exitTime : true;
236
+ // console.log(state.name, makeTransition, transition.hasExitTime, normalizedTime, transition.exitTime)
237
+ if (makeTransition) {
239
238
  // if (transition.hasExitTime && transition.exitTime >= .9999)
240
239
  action.clampWhenFinished = true;
241
240
  // else action.clampWhenFinished = false;
242
- if (debug) {
243
- console.log("transition to " + transition.destinationState, transition);
244
- console.log(action.time, transition.exitTime);
241
+ if (debug)
242
+ {
243
+ console.log("transition to " + transition.destinationState, transition, normalizedTime, transition.exitTime, transition.hasExitTime);
244
+ // console.log(action.time, transition.exitTime);
245
245
  }
246
246
  this.transitionTo(transition.destinationState as State, transition.duration, transition.offset);
247
247
  // use the first transition that matches all conditions and make the transition as soon as in range
@@ -252,7 +252,7 @@ export class AnimatorController {
252
252
  this.transitionTo(transition.destinationState as State, transition.duration, transition.offset);
253
253
  return;
254
254
  }
255
- break;
255
+ // if none of the transitions can be made continue searching for another transition meeting the conditions
256
256
  }
257
257
 
258
258
  let didTriggerLooping = false;
@@ -376,7 +376,13 @@ export class AnimatorController {
376
376
  }
377
377
 
378
378
  private createAction(clip: AnimationClip) {
379
- this._mixer.uncacheClip(clip);
379
+
380
+ // uncache clip causes issues when multiple states use the same clip
381
+ // this._mixer.uncacheClip(clip);
382
+ // instead only uncache the action when one already exists to make sure
383
+ // we get unique actions per state
384
+ const existing = this._mixer.existingAction(clip);
385
+ if (existing) this._mixer.uncacheAction(clip, this.animator?.gameObject);
380
386
 
381
387
  if (this.animator?.applyRootMotion) {
382
388
  if (!this.rootMotionHandler) {
@@ -387,7 +393,6 @@ export class AnimatorController {
387
393
  return this.rootMotionHandler.createClip(this._mixer, root, clip);
388
394
  }
389
395
  else {
390
-
391
396
  const action = this._mixer.clipAction(clip);
392
397
  return action;
393
398
  }
@@ -55,6 +55,7 @@ export class BoxHelperComponent extends Behaviour {
55
55
  // this.tp.applyMatrix4(obj.matrixWorld);
56
56
  // console.log(this.tp);
57
57
  // console.log(this.box?.min, this.box?.max, this.tp.min, this.tp.max);
58
+ this.updateBox();
58
59
  return this.box?.intersectsBox(BoxHelperComponent.testBox);
59
60
  }
60
61