@needle-tools/engine 2.31.1-pre → 2.33.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 (65) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/dist/needle-engine.d.ts +129 -122
  3. package/dist/needle-engine.js +346 -346
  4. package/dist/needle-engine.js.map +4 -4
  5. package/dist/needle-engine.min.js +19 -19
  6. package/dist/needle-engine.min.js.map +4 -4
  7. package/lib/engine/debug/error_overlay.js +4 -4
  8. package/lib/engine/debug/error_overlay.js.map +1 -1
  9. package/lib/engine/engine_input.d.ts +87 -102
  10. package/lib/engine/engine_input.js +173 -99
  11. package/lib/engine/engine_input.js.map +1 -1
  12. package/lib/engine/engine_mainloop_utils.d.ts +2 -1
  13. package/lib/engine/engine_mainloop_utils.js +5 -2
  14. package/lib/engine/engine_mainloop_utils.js.map +1 -1
  15. package/lib/engine/engine_physics.d.ts +5 -1
  16. package/lib/engine/engine_physics.js +72 -22
  17. package/lib/engine/engine_physics.js.map +1 -1
  18. package/lib/engine/engine_setup.js +7 -3
  19. package/lib/engine/engine_setup.js.map +1 -1
  20. package/lib/engine/extensions/NEEDLE_components.js +2 -0
  21. package/lib/engine/extensions/NEEDLE_components.js.map +1 -1
  22. package/lib/engine/extensions/NEEDLE_techniques_webgl.d.ts +1 -0
  23. package/lib/engine/extensions/NEEDLE_techniques_webgl.js +26 -0
  24. package/lib/engine/extensions/NEEDLE_techniques_webgl.js.map +1 -1
  25. package/lib/engine-components/Collider.js +2 -2
  26. package/lib/engine-components/Collider.js.map +1 -1
  27. package/lib/engine-components/Component.d.ts +10 -3
  28. package/lib/engine-components/Component.js +100 -90
  29. package/lib/engine-components/Component.js.map +1 -1
  30. package/lib/engine-components/Rigidbody.d.ts +7 -4
  31. package/lib/engine-components/Rigidbody.js +43 -26
  32. package/lib/engine-components/Rigidbody.js.map +1 -1
  33. package/lib/engine-components/ScreenCapture.d.ts +8 -4
  34. package/lib/engine-components/ScreenCapture.js +73 -18
  35. package/lib/engine-components/ScreenCapture.js.map +1 -1
  36. package/lib/engine-components/codegen/{exports.d.ts → components.d.ts} +2 -1
  37. package/lib/engine-components/codegen/{exports.js → components.js} +3 -2
  38. package/lib/engine-components/codegen/components.js.map +1 -0
  39. package/lib/engine-components/js-extensions/Object3D.d.ts +2 -0
  40. package/lib/engine-components/js-extensions/Object3D.js +75 -0
  41. package/lib/engine-components/js-extensions/Object3D.js.map +1 -0
  42. package/lib/needle-engine.d.ts +2 -1
  43. package/lib/needle-engine.js +3 -2
  44. package/lib/needle-engine.js.map +1 -1
  45. package/package.json +1 -1
  46. package/src/engine/codegen/register_types.js +4 -4
  47. package/src/engine/debug/error_overlay.ts +3 -3
  48. package/src/engine/engine_input.ts +179 -103
  49. package/src/engine/engine_mainloop_utils.ts +6 -2
  50. package/src/engine/engine_physics.ts +86 -24
  51. package/src/engine/engine_setup.ts +8 -3
  52. package/src/engine/extensions/NEEDLE_components.ts +3 -0
  53. package/src/engine/extensions/NEEDLE_techniques_webgl.ts +34 -2
  54. package/src/engine-components/Collider.ts +2 -2
  55. package/src/engine-components/Component.ts +111 -103
  56. package/src/engine-components/RigidBody.ts +51 -29
  57. package/src/engine-components/ScreenCapture.ts +73 -20
  58. package/src/engine-components/codegen/{exports.ts → components.ts} +1 -1
  59. package/src/engine-components/js-extensions/Object3D.ts +91 -0
  60. package/src/needle-engine.ts +3 -3
  61. package/lib/engine-components/ComponentExtensions.d.ts +0 -2
  62. package/lib/engine-components/ComponentExtensions.js +0 -3
  63. package/lib/engine-components/ComponentExtensions.js.map +0 -1
  64. package/lib/engine-components/codegen/exports.js.map +0 -1
  65. package/src/engine-components/ComponentExtensions.ts +0 -7
@@ -222,11 +222,13 @@ export class Context {
222
222
  this.lightmaps = new LightDataRegistry(this);
223
223
  this.players = new PlayerViewManager(this);
224
224
 
225
- window.addEventListener('resize', this.updateSize.bind(this));
225
+ window.addEventListener('resize', () => this._sizeChanged = true );
226
226
  const ro = new ResizeObserver(_ => this._sizeChanged = true);
227
227
  ro.observe(this.domElement);
228
228
  }
229
229
 
230
+ // private _requestSizeUpdate : boolean = false;
231
+
230
232
  private updateSize() {
231
233
  if (!this.isManagedExternally && !this.renderer.xr.isPresenting) {
232
234
  this._sizeChanged = false;
@@ -237,8 +239,11 @@ export class Context {
237
239
  this.updateAspect(camera);
238
240
  this.renderer.setSize(width, height);
239
241
  this.renderer.setPixelRatio(window.devicePixelRatio);
240
- this.renderer.domElement.style.width = this.domWidth + "px";
241
- this.renderer.domElement.style.height = this.domHeight + "px";
242
+ // avoid setting pixel values here since this can cause pingpong updates
243
+ // e.g. when system scale is set to 125%
244
+ // https://github.com/needle-tools/needle-engine-support/issues/69
245
+ this.renderer.domElement.style.width = "100%";
246
+ this.renderer.domElement.style.height = "100%";
242
247
  if (this.composer) {
243
248
  this.composer.setSize(width, height);
244
249
  this.composer.setPixelRatio(window.devicePixelRatio);
@@ -5,6 +5,7 @@ import { writeBuiltinComponentData } from "../engine_gltf_builtin_components";
5
5
  import { debugExtension } from "../engine_default_parameters";
6
6
  import { builtinComponentKeyName } from "../engine_constants";
7
7
  import { resolveReferences } from "./extension_utils";
8
+ import { apply } from "../../engine-components/js-extensions/Object3D";
8
9
 
9
10
  export const debug = debugExtension
10
11
  const componentsArrayExportKey = "$___Export_Components";
@@ -185,6 +186,8 @@ export class NEEDLE_components implements GLTFLoaderPlugin {
185
186
  continue;
186
187
  }
187
188
 
189
+ apply(obj);
190
+
188
191
  loadComponents.push(this.createComponents(obj, data));
189
192
  }
190
193
  }
@@ -62,6 +62,12 @@ export class CustomShader extends RawShaderMaterial {
62
62
  private identifier: SourceIdentifier;
63
63
  private onBeforeRenderSceneCallback = this.onBeforeRenderScene.bind(this);
64
64
 
65
+ clone() {
66
+ const clone = super.clone();
67
+ createUniformProperties(clone);
68
+ return clone;
69
+ }
70
+
65
71
  constructor(identifier: SourceIdentifier, ...args) {
66
72
  super(...args);
67
73
 
@@ -179,12 +185,12 @@ export class CustomShader extends RawShaderMaterial {
179
185
  CustomShader.viewProjection.copy(camera.projectionMatrix).multiply(camera.matrixWorldInverse);
180
186
  ToUnityMatrixArray(CustomShader.viewProjection, CustomShader._viewProjectionValues)
181
187
  }
182
-
188
+
183
189
  if (CustomShader.viewMatrix && this.uniforms[this._viewMatrixName]) {
184
190
  CustomShader.viewMatrix.copy(camera.matrixWorldInverse);
185
191
  ToUnityMatrixArray(CustomShader.viewMatrix, CustomShader._viewMatrixValues)
186
192
  }
187
-
193
+
188
194
  if (this.uniforms[CustomShader._worldSpaceCameraPosName]) {
189
195
  CustomShader._worldSpaceCameraPos.setFromMatrixPosition(camera.matrixWorld);
190
196
  }
@@ -475,8 +481,34 @@ export class NEEDLE_techniques_webgl implements GLTFLoaderPlugin {
475
481
  }
476
482
  if (debug)
477
483
  console.log(material.uuid, uniforms);
484
+
485
+
486
+ createUniformProperties(material);
487
+
478
488
  resolve(material);
479
489
  });
480
490
  }
481
491
 
482
492
  }
493
+
494
+
495
+ // when animating custom material properties (uniforms) the path resolver tries to access them via material._MyProperty.
496
+ // That doesnt exist by default for custom properties
497
+ // We could re-write the path in the khr path resolver but that would require it to know beforehand
498
+ // if the material uses as custom shader or not
499
+ // this way all properties of custom shaders are also accessible via material._MyProperty
500
+ function createUniformProperties(material: CustomShader) {
501
+ if (material.uniforms) {
502
+ for (const key in material.uniforms) {
503
+ if (!Object.getOwnPropertyDescriptor(material, key)) {
504
+ Object.defineProperty(material, key, {
505
+ get: () => material.uniforms[key].value,
506
+ set: (value) => {
507
+ material.uniforms[key].value = value
508
+ material.needsUpdate = true;
509
+ }
510
+ });
511
+ }
512
+ }
513
+ }
514
+ }
@@ -54,9 +54,9 @@ export class SphereCollider extends Collider {
54
54
  export class BoxCollider extends Collider {
55
55
 
56
56
  @serializeable(Vector3)
57
- size!: THREE.Vector3;
57
+ size: THREE.Vector3 = new Vector3(1, 1, 1);
58
58
  @serializeable(Vector3)
59
- center!: THREE.Vector3;
59
+ center: THREE.Vector3 = new Vector3(0, 0, 0);
60
60
 
61
61
  onEnable() {
62
62
  super.onEnable();
@@ -10,6 +10,7 @@ import { Object3D } from "three";
10
10
  import { InstantiateIdProvider, syncDestroy, syncInstantiate } from "../engine/engine_networking_instantiate";
11
11
  import { SourceIdentifier } from "../engine/engine_gltf";
12
12
  import { Collision } from "../engine/engine_physics";
13
+ import * as Object3DExtensions from "./js-extensions/Object3D";
13
14
 
14
15
  export interface UIDProvider {
15
16
  seed: number;
@@ -70,18 +71,17 @@ declare class NewGameObjectReferenceInfo {
70
71
  clone: THREE.Object3D;
71
72
  }
72
73
 
73
- THREE.Object3D.prototype["SetActive"] = function (active: boolean) {
74
- this.visible = active;
75
- }
76
-
77
74
 
78
75
  abstract class GameObject extends THREE.Object3D implements THREE.Object3D {
79
76
 
80
77
  guid: string | undefined;
81
78
 
82
- public static setActive(go: THREE.Object3D, active: boolean) {
79
+ public static setActive(go: THREE.Object3D, active: boolean, processStart: boolean = true) {
83
80
  if (!go) return;
84
81
  go.visible = active;
82
+ main.updateActiveInHierarchyWithoutEventCall(go);
83
+ if (active && processStart)
84
+ main.processStart(Context.Current, go);
85
85
  }
86
86
 
87
87
  public static isActiveSelf(go: THREE.Object3D): boolean {
@@ -214,6 +214,7 @@ abstract class GameObject extends THREE.Object3D implements THREE.Object3D {
214
214
  instance.children = [];
215
215
  let clone: THREE.Object3D | GameObject;
216
216
  clone = instance.clone(false);
217
+ Object3DExtensions.apply(clone);
217
218
  instance.userData = userData;
218
219
  instance.children = children;
219
220
 
@@ -681,65 +682,6 @@ abstract class GameObject extends THREE.Object3D implements THREE.Object3D {
681
682
  }
682
683
 
683
684
 
684
- // this is a fix to allow gameObject active animation be applied to a three object
685
- Object.defineProperty(THREE.Object3D.prototype, "activeSelf", {
686
- get: function () {
687
- return this.visible;
688
- },
689
- set: function (val: boolean | number) {
690
- const state = typeof val === "number" ? val > 0.5 : val;
691
- this.visible = state;
692
- }
693
- });
694
-
695
-
696
- THREE.Object3D.prototype["addNewComponent"] = function <T extends Behaviour>(type: ConstructorConcrete<T>) {
697
- return GameObject.addNewComponent(this, type);
698
- }
699
-
700
- THREE.Object3D.prototype["removeComponent"] = function (inst: Component) {
701
- return GameObject.removeComponent(inst);
702
- }
703
-
704
- THREE.Object3D.prototype["getOrAddComponent"] = function <T>(typeName: Constructor<T> | null): T {
705
- return GameObject.getOrAddComponent(this, typeName);
706
- }
707
-
708
- THREE.Object3D.prototype["getComponent"] = function <T>(type: Constructor<T>) {
709
- return GameObject.getComponent(this, type);
710
- }
711
-
712
- THREE.Object3D.prototype["getComponents"] = function <T>(type: Constructor<T>, arr?: []) {
713
- return GameObject.getComponents(this, type, arr);
714
- }
715
-
716
- THREE.Object3D.prototype["getComponentInChildren"] = function <T>(type: Constructor<T>) {
717
- return GameObject.getComponentInChildren(this, type);
718
- }
719
-
720
- THREE.Object3D.prototype["getComponentsInChildren"] = function <T>(type: Constructor<T>, arr?: []) {
721
- return GameObject.getComponentsInChildren(this, type, arr);
722
- }
723
-
724
- THREE.Object3D.prototype["getComponentInParent"] = function <T>(type: Constructor<T>) {
725
- return GameObject.getComponentInParent(this, type);
726
- }
727
-
728
- THREE.Object3D.prototype["getComponentsInParent"] = function <T>(type: Constructor<T>, arr?: []) {
729
- return GameObject.getComponentsInParent(this, type, arr);
730
- }
731
-
732
- // function patch_THREEObject3D() {
733
- // const props = Object.getOwnPropertyNames(GameObject.prototype);
734
- // for (const propName in props) {
735
- // const prop = props[propName];
736
- // if (prop === "constructor") continue;
737
- // const fn = GameObject.prototype[prop];
738
- // THREE.Object3D.prototype[prop] = fn;
739
- // }
740
- // }
741
- // patch_THREEObject3D();
742
-
743
685
 
744
686
  class Component implements EventTarget {
745
687
 
@@ -838,8 +780,13 @@ class Component implements EventTarget {
838
780
 
839
781
  onCollisionEnter?(col: Collision);
840
782
  onCollisionExit?(col: Collision);
783
+ onCollisionExitRaw?(col: Collision);
841
784
  onCollisionStay?(col: Collision);
842
785
 
786
+ onTriggerEnter?(col: Collision);
787
+ onTriggerStay?(col: Collision);
788
+ onTriggerExit?(col: Collision);
789
+
843
790
  startCoroutine(routine: Generator, evt: FrameEvent = FrameEvent.Update): Generator {
844
791
  return this.context.registerCoroutineUpdate(this, routine, evt);
845
792
  }
@@ -900,6 +847,7 @@ class Component implements EventTarget {
900
847
  this.__didEnable = false;
901
848
  this._collisionExitRoutine = undefined;
902
849
  this.onDisable();
850
+ this._collisions?.clear();
903
851
  }
904
852
 
905
853
  constructor() {
@@ -907,55 +855,115 @@ class Component implements EventTarget {
907
855
  }
908
856
 
909
857
  private _collisionExitRoutine: any;
910
- private _collisions: Map<Object3D, { col: Collision, frame: number }> | null = null;
858
+ private _collisions: Map<Object3D, { col: Collision, frame: number, exitFrame?: number }> | null = null;
859
+
860
+ private _triggerExitRoutine: any;
861
+ private _triggerCollisions: Map<Object3D, { col: Collision, frame: number, exitFrame?: number }> | null = null;
862
+
863
+ get collisionsCount() { return this._collisions?.size ?? 0; }
911
864
 
912
865
  private __internalResetsCachedPhysicsData() {
913
866
  this._collisionExitRoutine = null;
914
867
  this._collisions = null;
868
+ this._triggerExitRoutine = null;
869
+ this._triggerCollisions = null;
915
870
  }
916
871
 
917
- __internalHandleCollision(col: Collision) {
918
- if (this.onCollisionEnter || this.onCollisionExit || this.onCollisionStay) {
919
- const otherObject = col.gameObject;
920
- if (!this._collisions) this._collisions = new Map();
921
- if (this._collisions.has(otherObject)) {
922
- const cur = this._collisions.get(otherObject)!;
923
- cur.frame = this.context.time.frameCount;
924
- cur.col = col;
872
+ __internalHandleCollision(col: Collision, isTriggerCollision: boolean) {
873
+ if (isTriggerCollision) {
874
+ if (!this.onTriggerEnter && !this.onTriggerStay && !this.onTriggerExit) return;
875
+ }
876
+ else {
877
+ if (!this.onCollisionEnter && !this.onCollisionStay && !this.onCollisionExit) return;
878
+ }
879
+
880
+ const otherObject = col.gameObject;
881
+
882
+ // lazily create the maps
883
+ if (isTriggerCollision && !this._triggerCollisions) this._triggerCollisions = new Map();
884
+ else if (!this._collisions) this._collisions = new Map();
885
+
886
+ // select the correct map
887
+ const collection = isTriggerCollision ? this._triggerCollisions! : this._collisions!;
888
+
889
+ if (collection.has(otherObject)) {
890
+ const cur = collection.get(otherObject)!;
891
+ // console.log("STAY", this.name, this.context.time.frameCount)
892
+ // cur.exitFrame = undefined;
893
+ cur.frame = this.context.time.frameCount;
894
+ cur.col = col;
895
+ if (isTriggerCollision)
896
+ this.onTriggerStay?.(col);
897
+ else
925
898
  this.onCollisionStay?.call(this, col);
926
- }
927
- else {
928
- const entry = { col, frame: this.context.time.frameCount };
929
- this._collisions.set(otherObject, entry);
899
+ }
900
+ else {
901
+ // console.log("START", this.name);
902
+ const entry = { col, frame: this.context.time.frameCount };
903
+ collection.set(otherObject, entry);
904
+ if (isTriggerCollision)
905
+ this.onTriggerEnter?.(col);
906
+ else
930
907
  this.onCollisionEnter?.call(this, col);
931
- }
932
908
  }
933
909
  }
934
910
 
935
- sendExitCollisionEvent(obj : Object3D) {
936
- if(!this._collisions) return;
937
- const col = this._collisions.get(obj);
938
- if(!col) return;
939
- this.onCollisionExit?.call(this, col.col);
940
- this._collisions.delete(obj);
941
- }
942
-
943
- private __waitForCollisionExit() {
944
- if (this._collisionExitRoutine) return;
945
- // const self = this;
946
- // function* routine() {
947
- // while (self._collisions && self._collisions.size > 0) {
948
- // for (let ob of self._collisions.keys()) {
949
- // const entry = self._collisions!.get(ob)!;
950
- // if (self.context.time.frameCount - entry.frame > 1) {
951
- // self._collisions!.delete(ob);
952
- // self.onCollisionExit?.call(self, entry.col);
953
- // }
954
- // }
955
- // yield;
956
- // }
957
- // }
958
- // this._collisionExitRoutine = this.startCoroutine(routine(), FrameEvent.EarlyUpdate);
911
+ __internalHandleExitCollisionEvent(obj: Object3D, isTriggerCollision: boolean) {
912
+ if (isTriggerCollision) {
913
+ if (!this._triggerCollisions) return;
914
+ }
915
+ else {
916
+ if (!this._collisions) return;
917
+ }
918
+
919
+ const collection = isTriggerCollision ? this._triggerCollisions! : this._collisions!;
920
+
921
+ const collision = collection.get(obj);
922
+ if (!collision) return;
923
+ collision.exitFrame = this.context.time.frameCount;
924
+ // console.log("EXIT col", this.name, this.context.time.frameCount);
925
+ // if (this.onCollisionExit !== undefined)
926
+ this.__waitForCollisionExit(isTriggerCollision);
927
+ if (!isTriggerCollision)
928
+ this.onCollisionExitRaw?.call(this, collision.col);
929
+ // this._collisions.delete(obj);
930
+ }
931
+
932
+ private __waitForCollisionExit(isTriggerCollision: boolean) {
933
+ const routine = isTriggerCollision ? this._triggerExitRoutine : this._collisionExitRoutine;
934
+ if (routine) return;
935
+
936
+ const collection = isTriggerCollision ? this._triggerCollisions! : this._collisions!;
937
+ const self = this;
938
+ const frames = 10;
939
+ function* delayedExitRoutine() {
940
+ while (collection && collection.size > 0) {
941
+ for (let other of collection.keys()) {
942
+ const entry = collection!.get(other)!;
943
+ if (entry.frame !== undefined && self.context.time.frameCount - entry.frame >= frames) {
944
+ // console.log("EXIT real", self.name, entry.col.gameObject.name, collection);
945
+ collection!.delete(other);
946
+ if (isTriggerCollision)
947
+ self.onTriggerExit?.(entry.col);
948
+ else
949
+ self.onCollisionExit?.call(self, entry.col);
950
+ }
951
+ }
952
+ for (let i = 0; i < frames; i++)
953
+ yield;
954
+ }
955
+ if (isTriggerCollision)
956
+ self._triggerExitRoutine = undefined;
957
+ else
958
+ self._collisionExitRoutine = null;
959
+ // console.log("DONE", self.name);
960
+ }
961
+
962
+ const newRoutine = this.startCoroutine(delayedExitRoutine(), FrameEvent.OnAfterRender);
963
+ if (isTriggerCollision)
964
+ this._triggerExitRoutine = newRoutine;
965
+ else
966
+ this._collisionExitRoutine = newRoutine
959
967
  }
960
968
 
961
969
 
@@ -1046,7 +1054,7 @@ class Component implements EventTarget {
1046
1054
  private static _forward: THREE.Vector3 = new THREE.Vector3(0, 0, 1);
1047
1055
  public get forward(): THREE.Vector3 {
1048
1056
 
1049
- return Component._forward.set(0, 0, 1).applyQuaternion(this.worldQuaternion);
1057
+ return Component._forward.set(0, 0, -1).applyQuaternion(this.worldQuaternion);
1050
1058
  }
1051
1059
 
1052
1060
 
@@ -5,6 +5,7 @@ import * as THREE from 'three'
5
5
  import { getWorldPosition } from "../engine/engine_three_utils";
6
6
  import { serializeable } from "../engine/engine_serialization_decorator";
7
7
  import { Watch } from "../engine/engine_utils";
8
+ import { Vector3 } from "three";
8
9
 
9
10
  export class Rigidbody extends Behaviour {
10
11
 
@@ -51,7 +52,7 @@ export class Rigidbody extends Behaviour {
51
52
  private _dirty: boolean = false;
52
53
 
53
54
  private _positionWatch?: Watch;
54
- // private _matrixWatch?: Watch;
55
+ private _matrixWatch?: Watch;
55
56
  private _setMatrix: THREE.Matrix4;
56
57
 
57
58
  constructor() {
@@ -64,11 +65,13 @@ export class Rigidbody extends Behaviour {
64
65
  this.currentVelocity = new THREE.Vector3();
65
66
  this._smoothedVelocity = new THREE.Vector3();
66
67
  this.lastWorldPosition = getWorldPosition(this.gameObject).clone();
68
+ this._matrixWatch = undefined;
69
+ this._positionWatch = undefined;
67
70
  }
68
71
 
69
- start() {
70
- this.setBodyFromGameObject();
71
- }
72
+ // start() {
73
+ // this.setBodyFromGameObject();
74
+ // }
72
75
 
73
76
  onEnable() {
74
77
  if (this._body) {
@@ -88,22 +91,13 @@ export class Rigidbody extends Behaviour {
88
91
  this._positionWatch.subscribeWrite(_ => {
89
92
  if (!this.context.physics.isUpdating && !this._ignoreChange) {
90
93
  this._dirty = true;
94
+ this._setMatrix.copy(this.gameObject.matrix);
91
95
  this._setMatrix.setPosition(this.gameObject.position);
92
96
  }
93
97
  })
94
-
95
- // this._matrixWatch = onChange(this.gameObject.matrix, "elements", (newValue, oldValue) => {
96
- // if (newValue !== oldValue) {
97
- // if (!this.context.physics.isUpdating && !this._ignoreChange) {
98
- // this.dirty = true;
99
- // this._setMatrix.copy(this.gameObject.matrix);
100
- // }
101
- // }
102
- // });
103
98
  }
104
99
 
105
100
  onDisable(): void {
106
- // this._matrixWatch?.u();
107
101
  if (this._body)
108
102
  this.context.physics.removeBody(this.gameObject, this._body, false);
109
103
  }
@@ -113,27 +107,23 @@ export class Rigidbody extends Behaviour {
113
107
  this.context.physics.removeBody(this.gameObject, this._body);
114
108
  }
115
109
 
116
- earlyUpdate() {
110
+ onBeforeRender() {
111
+ this._ignoreChange = true;
112
+ this.updateVelocity();
113
+
117
114
  if (this._dirty) {
118
- this._ignoreChange = true;
119
115
  this._dirty = false;
120
- // // console.log("RESET");
121
116
  this._setMatrix.decompose(this.gameObject.position, this.gameObject.quaternion, this.gameObject.scale);
122
117
  this.setBodyFromGameObject();
123
- this._ignoreChange = false;
124
118
  }
125
- }
126
- onBeforeRender() {
127
- this._ignoreChange = true;
128
- this.updateVelocity();
129
- // this._ignoreChange = true;
130
- // this._setMatrix.decompose(this.gameObject.position, this.gameObject.quaternion, this.gameObject.scale);
131
- // this.setBodyFromGameObject();
119
+
132
120
  this._ignoreChange = false;
133
121
  }
134
122
 
135
123
  initialize() {
136
- if (this._body) return;
124
+ if (this._body) {
125
+ return;
126
+ }
137
127
  const options = new BodyOptions();
138
128
  options.drag = this.drag;
139
129
  options.angularDrag = this.angularDrag;
@@ -149,8 +139,14 @@ export class Rigidbody extends Behaviour {
149
139
  this.body?.wakeUp();
150
140
  }
151
141
 
152
- public applyForce(vec: THREE.Vector3, rel: THREE.Vector3 | undefined) {
153
- this.body?.applyForce(new CANNON.Vec3(vec.x, vec.y, vec.z), rel ? new CANNON.Vec3(rel.x, rel.y, rel.z) : undefined);
142
+ public applyForce(vec: THREE.Vector3, rel?: THREE.Vector3) {
143
+ const force = new CANNON.Vec3(vec.x, vec.y, vec.z);
144
+ force.scale(1 / this.context.time.deltaTime, force);
145
+ this.body?.applyForce(force, rel ? new CANNON.Vec3(rel.x, rel.y, rel.z) : undefined);
146
+ }
147
+
148
+ public setForce(x: number, y: number, z: number) {
149
+ this.body?.force.set(x, y, z);
154
150
  }
155
151
 
156
152
  public getVelocity(): THREE.Vector3 {
@@ -159,13 +155,39 @@ export class Rigidbody extends Behaviour {
159
155
  return Rigidbody.tempPosition.set(0, 0, 0);
160
156
  }
161
157
 
162
- public setVelocity(x: number, y: number, z: number) {
158
+ public setVelocity(x: number | Vector3, y: number, z: number) {
163
159
  if (!this.body) return;
160
+ if (x instanceof Vector3) {
161
+ const vec = x;
162
+ x = vec.x;
163
+ y = vec.y;
164
+ z = vec.z;
165
+ }
164
166
  this.body.velocity.x = x / this.context.time.deltaTime;
165
167
  this.body.velocity.y = y / this.context.time.deltaTime;
166
168
  this.body.velocity.z = z / this.context.time.deltaTime;
167
169
  }
168
170
 
171
+ public getTorque(): THREE.Vector3 {
172
+ if (this.body)
173
+ return Rigidbody.tempPosition.set(this.body?.torque.x, this.body?.torque.y, this.body?.torque.z);
174
+ return Rigidbody.tempPosition.set(0, 0, 0);
175
+ }
176
+
177
+ public setTorque(x: number | Vector3, y: number, z: number) {
178
+ if (!this.body) return;
179
+ if (x instanceof Vector3) {
180
+ const vec = x;
181
+ x = vec.x;
182
+ y = vec.y;
183
+ z = vec.z;
184
+ }
185
+ this.body.torque.x = x / this.context.time.deltaTime;
186
+ this.body.torque.y = y / this.context.time.deltaTime;
187
+ this.body.torque.z = z / this.context.time.deltaTime;
188
+
189
+ }
190
+
169
191
  public get smoothedVelocity() { return this._smoothedVelocity; }
170
192
 
171
193
  public setAngularVelocity(x: number, y: number, z: number) {