@needle-tools/engine 2.37.0-pre → 2.38.0-pre.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +21 -0
- package/dist/needle-engine.d.ts +118 -19
- package/dist/needle-engine.js +352 -352
- package/dist/needle-engine.js.map +4 -4
- package/dist/needle-engine.min.js +25 -25
- package/dist/needle-engine.min.js.map +4 -4
- package/lib/engine/engine_addressables.d.ts +3 -1
- package/lib/engine/engine_addressables.js +12 -5
- package/lib/engine/engine_addressables.js.map +1 -1
- package/lib/engine/engine_element.js +3 -2
- package/lib/engine/engine_element.js.map +1 -1
- package/lib/engine/engine_element_overlay.js +4 -3
- package/lib/engine/engine_element_overlay.js.map +1 -1
- package/lib/engine/engine_input.d.ts +2 -0
- package/lib/engine/engine_input.js +14 -3
- package/lib/engine/engine_input.js.map +1 -1
- package/lib/engine/engine_physics.d.ts +11 -4
- package/lib/engine/engine_physics.js +107 -42
- package/lib/engine/engine_physics.js.map +1 -1
- package/lib/engine/engine_physics.types.d.ts +7 -0
- package/lib/engine/engine_physics.types.js +8 -0
- package/lib/engine/engine_physics.types.js.map +1 -1
- package/lib/engine/engine_setup.d.ts +12 -6
- package/lib/engine/engine_setup.js +30 -22
- package/lib/engine/engine_setup.js.map +1 -1
- package/lib/engine/engine_types.d.ts +3 -1
- package/lib/engine/engine_types.js.map +1 -1
- package/lib/engine-components/Animation.d.ts +1 -0
- package/lib/engine-components/Animation.js +7 -0
- package/lib/engine-components/Animation.js.map +1 -1
- package/lib/engine-components/AnimatorController.js +14 -7
- package/lib/engine-components/AnimatorController.js.map +1 -1
- package/lib/engine-components/Camera.d.ts +2 -0
- package/lib/engine-components/Camera.js +24 -6
- package/lib/engine-components/Camera.js.map +1 -1
- package/lib/engine-components/CharacterController.d.ts +34 -0
- package/lib/engine-components/CharacterController.js +179 -0
- package/lib/engine-components/CharacterController.js.map +1 -0
- package/lib/engine-components/Collider.d.ts +10 -5
- package/lib/engine-components/Collider.js +18 -11
- package/lib/engine-components/Collider.js.map +1 -1
- package/lib/engine-components/Joints.d.ts +15 -0
- package/lib/engine-components/Joints.js +42 -0
- package/lib/engine-components/Joints.js.map +1 -0
- package/lib/engine-components/Light.d.ts +2 -0
- package/lib/engine-components/Light.js +13 -2
- package/lib/engine-components/Light.js.map +1 -1
- package/lib/engine-components/OrbitControls.js +1 -1
- package/lib/engine-components/OrbitControls.js.map +1 -1
- package/lib/engine-components/Renderer.js +4 -0
- package/lib/engine-components/Renderer.js.map +1 -1
- package/lib/engine-components/RigidBody.d.ts +6 -1
- package/lib/engine-components/RigidBody.js +62 -25
- package/lib/engine-components/RigidBody.js.map +1 -1
- package/lib/engine-components/SmoothFollow.d.ts +2 -1
- package/lib/engine-components/SmoothFollow.js +25 -17
- package/lib/engine-components/SmoothFollow.js.map +1 -1
- package/lib/engine-components/WebXR.js +3 -4
- package/lib/engine-components/WebXR.js.map +1 -1
- package/lib/engine-components/codegen/components.d.ts +4 -0
- package/lib/engine-components/codegen/components.js +4 -0
- package/lib/engine-components/codegen/components.js.map +1 -1
- package/package.json +1 -1
- package/src/engine/codegen/register_types.js +16 -0
- package/src/engine/dist/engine_physics.js +739 -0
- package/src/engine/dist/engine_setup.js +777 -0
- package/src/engine/engine_addressables.ts +18 -8
- package/src/engine/engine_element.ts +3 -2
- package/src/engine/engine_element_overlay.ts +4 -3
- package/src/engine/engine_input.ts +12 -3
- package/src/engine/engine_physics.ts +119 -57
- package/src/engine/engine_physics.types.ts +9 -0
- package/src/engine/engine_setup.ts +53 -45
- package/src/engine/engine_types.ts +4 -1
- package/src/engine-components/Animation.ts +8 -0
- package/src/engine-components/AnimatorController.ts +16 -11
- package/src/engine-components/Camera.ts +25 -5
- package/src/engine-components/CharacterController.ts +185 -0
- package/src/engine-components/Collider.ts +21 -15
- package/src/engine-components/Joints.ts +40 -0
- package/src/engine-components/Light.ts +17 -3
- package/src/engine-components/OrbitControls.ts +1 -1
- package/src/engine-components/Renderer.ts +5 -1
- package/src/engine-components/RigidBody.ts +63 -29
- package/src/engine-components/SmoothFollow.ts +21 -18
- package/src/engine-components/WebXR.ts +3 -4
- package/src/engine-components/codegen/components.ts +4 -0
- package/src/engine-components/dist/CharacterController.js +123 -0
- package/src/engine-components/dist/RigidBody.js +458 -0
- package/src/include/console/ConsoleReroute.js +79 -0
- package/src/include/draco/draco_decoder.js +48 -0
- package/src/include/draco/draco_decoder.wasm +0 -0
- package/src/include/ktx2/basis_transcoder.js +21 -0
- package/src/include/ktx2/basis_transcoder.wasm +0 -0
- package/src/include/three/ARButton.js +208 -0
- package/src/include/three/DragControls.js +232 -0
- package/src/include/three/EXT_mesh_gpu_instancing_exporter.js +67 -0
- package/src/include/three/VRButton.js +196 -0
- package/src/include/three-mesh-ui-assets/backspace.png +0 -0
- package/src/include/three-mesh-ui-assets/enter.png +0 -0
- package/src/include/three-mesh-ui-assets/shift.png +0 -0
|
@@ -24,8 +24,8 @@ import { Application } from './engine_application';
|
|
|
24
24
|
import { LightDataRegistry, ILightDataRegistry } from './engine_lightdata';
|
|
25
25
|
import { PlayerViewManager } from './engine_playerview';
|
|
26
26
|
|
|
27
|
-
import { ICamera
|
|
28
|
-
import { destroy } from './engine_gameobject';
|
|
27
|
+
import { ICamera, IComponent, ILight } from "./engine_types"
|
|
28
|
+
import { destroy, foreachComponent } from './engine_gameobject';
|
|
29
29
|
|
|
30
30
|
|
|
31
31
|
const debug = utils.getParam("debugSetup");
|
|
@@ -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
|
-
|
|
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
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
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
|
|
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;
|
|
@@ -150,14 +157,14 @@ export class Context {
|
|
|
150
157
|
|
|
151
158
|
get mainCamera(): THREE.Camera | null {
|
|
152
159
|
if (this.mainCameraComponent) {
|
|
153
|
-
const cam = this.mainCameraComponent as
|
|
160
|
+
const cam = this.mainCameraComponent as ICamera;
|
|
154
161
|
if (!cam.cam)
|
|
155
162
|
cam.buildCamera();
|
|
156
163
|
return cam.cam;
|
|
157
164
|
}
|
|
158
165
|
return null;
|
|
159
166
|
}
|
|
160
|
-
mainCameraComponent:
|
|
167
|
+
mainCameraComponent: ICamera | undefined;
|
|
161
168
|
|
|
162
169
|
post_setup_callbacks: Function[] = [];
|
|
163
170
|
pre_update_callbacks: Function[] = [];
|
|
@@ -178,11 +185,11 @@ export class Context {
|
|
|
178
185
|
* @deprecated AssetDataBase is deprecated
|
|
179
186
|
*/
|
|
180
187
|
assets: AssetDatabase;
|
|
181
|
-
mainLight:
|
|
188
|
+
mainLight: ILight | null = null;
|
|
182
189
|
rendererData: RendererData;
|
|
183
190
|
addressables: Addressables;
|
|
184
191
|
lightmaps: ILightDataRegistry;
|
|
185
|
-
players
|
|
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
|
}
|
|
@@ -315,9 +323,9 @@ export class Context {
|
|
|
315
323
|
}
|
|
316
324
|
}
|
|
317
325
|
|
|
318
|
-
private _cameraStack:
|
|
326
|
+
private _cameraStack: ICamera[] = [];
|
|
319
327
|
|
|
320
|
-
setCurrentCamera(cam:
|
|
328
|
+
setCurrentCamera(cam: ICamera) {
|
|
321
329
|
if (!cam) return;
|
|
322
330
|
if (!cam.cam) cam.buildCamera(); // < to build camera
|
|
323
331
|
if (!cam.cam) {
|
|
@@ -331,17 +339,17 @@ export class Context {
|
|
|
331
339
|
const camera = cam.cam as THREE.PerspectiveCamera;
|
|
332
340
|
if (camera.isPerspectiveCamera)
|
|
333
341
|
this.updateAspect(camera);
|
|
334
|
-
(this.mainCameraComponent as
|
|
342
|
+
(this.mainCameraComponent as ICamera)?.applyClearFlagsIfIsActiveCamera();
|
|
335
343
|
}
|
|
336
344
|
|
|
337
|
-
removeCamera(cam?:
|
|
338
|
-
if(!cam) return;
|
|
345
|
+
removeCamera(cam?: ICamera | null) {
|
|
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);
|
|
@@ -460,25 +468,24 @@ export class Context {
|
|
|
460
468
|
}
|
|
461
469
|
|
|
462
470
|
if (!this.mainCamera) {
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
// }
|
|
471
|
+
Context._current = this;
|
|
472
|
+
let camera: ICamera | null = null;
|
|
473
|
+
foreachComponent(this.scene, comp => {
|
|
474
|
+
const cam = comp as ICamera;
|
|
475
|
+
if (cam?.isCamera) {
|
|
476
|
+
if (cam.tag === "MainCamera") {
|
|
477
|
+
camera = cam;
|
|
478
|
+
return true;
|
|
479
|
+
}
|
|
480
|
+
else camera = cam;
|
|
481
|
+
}
|
|
482
|
+
return undefined;
|
|
483
|
+
});
|
|
484
|
+
if (camera) {
|
|
485
|
+
this.setCurrentCamera(camera);
|
|
486
|
+
}
|
|
487
|
+
else
|
|
488
|
+
console.error("MISSING camera", this);
|
|
482
489
|
}
|
|
483
490
|
|
|
484
491
|
Context._current = this;
|
|
@@ -569,8 +576,9 @@ export class Context {
|
|
|
569
576
|
const physicsSteps = 1;
|
|
570
577
|
const dt = this.time.deltaTime / physicsSteps;
|
|
571
578
|
for (let i = 0; i < physicsSteps; i++) {
|
|
579
|
+
this.executeCoroutines(FrameEvent.PrePhysicsStep);
|
|
572
580
|
this.physics.step(dt);
|
|
573
|
-
this.executeCoroutines(FrameEvent.
|
|
581
|
+
this.executeCoroutines(FrameEvent.PostPhysicsStep);
|
|
574
582
|
}
|
|
575
583
|
}
|
|
576
584
|
catch (err) {
|
|
@@ -40,6 +40,7 @@ export interface IComponent {
|
|
|
40
40
|
get name(): string;
|
|
41
41
|
get layer(): number;
|
|
42
42
|
get destroyed(): boolean;
|
|
43
|
+
get tag() : string;
|
|
43
44
|
|
|
44
45
|
context: any;
|
|
45
46
|
|
|
@@ -83,6 +84,7 @@ export interface IComponent {
|
|
|
83
84
|
|
|
84
85
|
|
|
85
86
|
export declare interface ICamera extends IComponent {
|
|
87
|
+
get isCamera() : boolean;
|
|
86
88
|
applyClearFlagsIfIsActiveCamera(): unknown;
|
|
87
89
|
buildCamera();
|
|
88
90
|
get cam(): Camera;
|
|
@@ -173,7 +175,7 @@ export class ContactPoint {
|
|
|
173
175
|
/// all info in here must be readonly because the object is only created once per started collision
|
|
174
176
|
export class Collision {
|
|
175
177
|
|
|
176
|
-
|
|
178
|
+
readonly contacts: ContactPoint[];
|
|
177
179
|
|
|
178
180
|
constructor(obj: Object3D, otherCollider: ICollider, contacts: ContactPoint[]) {
|
|
179
181
|
this.me = obj;
|
|
@@ -201,6 +203,7 @@ export class Collision {
|
|
|
201
203
|
return this.collider?.attachedRigidbody;
|
|
202
204
|
}
|
|
203
205
|
|
|
206
|
+
|
|
204
207
|
|
|
205
208
|
// private _normal?: Vector3;
|
|
206
209
|
// get normal(): Vector3 {
|
|
@@ -112,6 +112,14 @@ export class Animation extends Behaviour {
|
|
|
112
112
|
return this.actions?.find(a => a.getClip().name === name);
|
|
113
113
|
}
|
|
114
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
|
+
|
|
115
123
|
play(clipOrNumber: AnimationClip | number | string, options?: PlayOptions): Promise<AnimationAction> | void {
|
|
116
124
|
this.init();
|
|
117
125
|
if (!this.mixer) return;
|
|
@@ -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
|
-
|
|
236
|
-
|
|
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
|
-
|
|
244
|
-
console.log(
|
|
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
|
-
|
|
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
|
-
|
|
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
|
}
|
|
@@ -7,6 +7,7 @@ import { RGBAColor } from "./js-extensions/RGBAColor";
|
|
|
7
7
|
import { PerspectiveCamera } from "three";
|
|
8
8
|
import { XRSessionMode } from "../engine/engine_setup";
|
|
9
9
|
import { ICamera } from "../engine/engine_types"
|
|
10
|
+
import { showBalloonMessage } from "../engine/debug/debug";
|
|
10
11
|
|
|
11
12
|
export enum ClearFlags {
|
|
12
13
|
Skybox = 1,
|
|
@@ -18,6 +19,9 @@ const debug = getParam("debugcam");
|
|
|
18
19
|
|
|
19
20
|
export class Camera extends Behaviour implements ICamera {
|
|
20
21
|
|
|
22
|
+
get isCamera() {
|
|
23
|
+
return true;
|
|
24
|
+
}
|
|
21
25
|
|
|
22
26
|
get aspect(): number {
|
|
23
27
|
if (this._cam instanceof PerspectiveCamera) return this._cam.aspect;
|
|
@@ -121,12 +125,16 @@ export class Camera extends Behaviour implements ICamera {
|
|
|
121
125
|
onEnable(): void {
|
|
122
126
|
if (debug) console.log(this);
|
|
123
127
|
this.buildCamera();
|
|
124
|
-
if (this.tag == "MainCamera") {
|
|
128
|
+
if (this.tag == "MainCamera" || !this.context.mainCameraComponent) {
|
|
125
129
|
this.context.setCurrentCamera(this);
|
|
126
130
|
}
|
|
127
131
|
this.applyClearFlagsIfIsActiveCamera();
|
|
128
132
|
}
|
|
129
133
|
|
|
134
|
+
onDisable() {
|
|
135
|
+
this.context.removeCamera(this);
|
|
136
|
+
}
|
|
137
|
+
|
|
130
138
|
buildCamera() {
|
|
131
139
|
if (this._cam) return;
|
|
132
140
|
|
|
@@ -168,6 +176,8 @@ export class Camera extends Behaviour implements ICamera {
|
|
|
168
176
|
}
|
|
169
177
|
|
|
170
178
|
applyClearFlagsIfIsActiveCamera() {
|
|
179
|
+
if (debug)
|
|
180
|
+
showBalloonMessage("apply Camera clear flags");
|
|
171
181
|
if (this._cam && this.context.mainCameraComponent === this) {
|
|
172
182
|
switch (this._clearFlags) {
|
|
173
183
|
case ClearFlags.Skybox:
|
|
@@ -203,12 +213,22 @@ export class Camera extends Behaviour implements ICamera {
|
|
|
203
213
|
const session = this.context.renderer.xr?.getSession();
|
|
204
214
|
if (!session) return false;
|
|
205
215
|
const environmentBlendMode = session.environmentBlendMode;
|
|
216
|
+
if (debug)
|
|
217
|
+
showBalloonMessage("Environment blend mode: " + environmentBlendMode + " on " + navigator.userAgent);
|
|
206
218
|
const transparent = environmentBlendMode === 'additive' || environmentBlendMode === 'alpha-blend';
|
|
207
|
-
// workaround for Quest 2 returning opaque when it should be alpha-blend
|
|
208
|
-
// check user agent if this is the Quest browser and return true if so
|
|
209
219
|
|
|
210
|
-
if (
|
|
211
|
-
if (
|
|
220
|
+
if (this.context.xrSessionMode === XRSessionMode.ImmersiveAR) {
|
|
221
|
+
if (environmentBlendMode === "opaque") {
|
|
222
|
+
// workaround for Quest 2 returning opaque when it should be alpha-blend
|
|
223
|
+
// check user agent if this is the Quest browser and return true if so
|
|
224
|
+
if (navigator.userAgent?.includes("OculusBrowser")) {
|
|
225
|
+
return true;
|
|
226
|
+
}
|
|
227
|
+
// Mozilla WebXR Viewer
|
|
228
|
+
else if (navigator.userAgent?.includes("Mozilla") && navigator.userAgent?.includes("Mobile WebXRViewer/v2")) {
|
|
229
|
+
return true;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
212
232
|
}
|
|
213
233
|
return transparent;
|
|
214
234
|
}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import { Quaternion, Ray, Vector3 } from "three";
|
|
2
|
+
import { Mathf } from "../engine/engine_math";
|
|
3
|
+
import { serializeable } from "../engine/engine_serialization";
|
|
4
|
+
import { Collision } from "../engine/engine_types";
|
|
5
|
+
import { CapsuleCollider } from "./Collider";
|
|
6
|
+
import { Behaviour, GameObject } from "./Component";
|
|
7
|
+
import { Rigidbody } from "./RigidBody";
|
|
8
|
+
import { Animator } from "./Animator"
|
|
9
|
+
import { RaycastOptions } from "../engine/engine_physics";
|
|
10
|
+
import { getWorldPosition } from "../engine/engine_three_utils";
|
|
11
|
+
|
|
12
|
+
export class CharacterController extends Behaviour {
|
|
13
|
+
|
|
14
|
+
@serializeable(Vector3)
|
|
15
|
+
center: Vector3 = new Vector3(0, 0, 0);
|
|
16
|
+
@serializeable()
|
|
17
|
+
radius: number = .5;
|
|
18
|
+
@serializeable()
|
|
19
|
+
height: number = 2;
|
|
20
|
+
|
|
21
|
+
private _rigidbody: Rigidbody | null = null;
|
|
22
|
+
get rigidbody(): Rigidbody {
|
|
23
|
+
if (this._rigidbody) return this._rigidbody;
|
|
24
|
+
this._rigidbody = this.gameObject.getComponent(Rigidbody);
|
|
25
|
+
if (!this._rigidbody)
|
|
26
|
+
this._rigidbody = this.gameObject.addNewComponent(Rigidbody) as Rigidbody;
|
|
27
|
+
return this.rigidbody;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
onEnable() {
|
|
31
|
+
let rb = this.rigidbody;
|
|
32
|
+
let collider = this.gameObject.getComponent(CapsuleCollider);
|
|
33
|
+
if (!collider)
|
|
34
|
+
collider = this.gameObject.addNewComponent(CapsuleCollider) as CapsuleCollider;
|
|
35
|
+
// rb.isKinematic = true;
|
|
36
|
+
collider.center.copy(this.center);
|
|
37
|
+
collider.radius = this.radius;
|
|
38
|
+
collider.height = this.height;
|
|
39
|
+
this.gameObject.rotation.x = 0;
|
|
40
|
+
this.gameObject.rotation.z = 0;
|
|
41
|
+
rb.lockRotationX = true;
|
|
42
|
+
rb.lockRotationY = true;
|
|
43
|
+
rb.lockRotationZ = true;
|
|
44
|
+
|
|
45
|
+
// TODO: this doesnt work yet
|
|
46
|
+
// setInterval(()=>{
|
|
47
|
+
// this.rigidbody.isKinematic = !this.rigidbody.isKinematic;
|
|
48
|
+
// console.log(this.rigidbody.isKinematic);
|
|
49
|
+
// }, 1000)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
move(vec: Vector3) {
|
|
53
|
+
this.gameObject.position.add(vec);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
private _activeGroundCollisions: Set<Collision> = new Set();
|
|
57
|
+
|
|
58
|
+
onCollisionEnter(col: Collision) {
|
|
59
|
+
for (const contact of col.contacts) {
|
|
60
|
+
// console.log(contact.normal);
|
|
61
|
+
if (contact.normal.y > .1) {
|
|
62
|
+
this._activeGroundCollisions.add(col);
|
|
63
|
+
break;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
onCollisionExit(col: Collision) {
|
|
69
|
+
this._activeGroundCollisions.delete(col);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
get isGrounded(): boolean { return this._activeGroundCollisions.size > 0; }
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export class CharacterControllerInput extends Behaviour {
|
|
76
|
+
|
|
77
|
+
@serializeable(CharacterController)
|
|
78
|
+
controller?: CharacterController;
|
|
79
|
+
|
|
80
|
+
@serializeable()
|
|
81
|
+
movementSpeed: number = 2;
|
|
82
|
+
|
|
83
|
+
@serializeable()
|
|
84
|
+
rotationSpeed: number = 2;
|
|
85
|
+
|
|
86
|
+
@serializeable()
|
|
87
|
+
jumpForce: number = 1;
|
|
88
|
+
|
|
89
|
+
@serializeable(Animator)
|
|
90
|
+
animator?: Animator;
|
|
91
|
+
|
|
92
|
+
lookForward: boolean = true;
|
|
93
|
+
|
|
94
|
+
private _currentSpeed: Vector3 = new Vector3(0, 0, 0);
|
|
95
|
+
private _currentAngularSpeed: Vector3 = new Vector3(0, 0, 0);
|
|
96
|
+
|
|
97
|
+
private _temp: Vector3 = new Vector3(0, 0, 0);
|
|
98
|
+
private _jumpCount: number = 0;
|
|
99
|
+
private _currentRotation!: Quaternion;
|
|
100
|
+
|
|
101
|
+
awake(){
|
|
102
|
+
this._currentRotation = new Quaternion();
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
update() {
|
|
106
|
+
|
|
107
|
+
if (this.controller?.isGrounded) {
|
|
108
|
+
this._jumpCount = 0;
|
|
109
|
+
this.animator?.SetBool("doubleJump", false);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const forward = this.context.input.isKeyPressed("w");
|
|
113
|
+
const backward = this.context.input.isKeyPressed("s");
|
|
114
|
+
const rotateLeft = this.context.input.isKeyPressed("a");
|
|
115
|
+
const rotateRight = this.context.input.isKeyPressed("d");
|
|
116
|
+
const jump = this.context.input.isKeyDown(" ");
|
|
117
|
+
// if (jumpDown) this._jumpDownTime = this.context.time.time;
|
|
118
|
+
// const jumpUp = this.context.input.isKeyUp(" ");
|
|
119
|
+
|
|
120
|
+
const step = forward ? 1 : 0 + backward ? -1 : 0;
|
|
121
|
+
this._currentSpeed.z += step * this.movementSpeed * this.context.time.deltaTime;
|
|
122
|
+
|
|
123
|
+
// if (!this.controller || this.controller.isGrounded)
|
|
124
|
+
this.animator?.SetBool("running", step != 0);
|
|
125
|
+
this.animator?.SetBool("jumping", this.controller?.isGrounded === true && jump);
|
|
126
|
+
|
|
127
|
+
this._temp.copy(this._currentSpeed);
|
|
128
|
+
this._temp.applyQuaternion(this.gameObject.quaternion);
|
|
129
|
+
if (this.controller) this.controller.move(this._temp);
|
|
130
|
+
else this.gameObject.position.add(this._temp);
|
|
131
|
+
|
|
132
|
+
const rotation = rotateLeft ? 1 : 0 + rotateRight ? -1 : 0;
|
|
133
|
+
this._currentAngularSpeed.y += Mathf.toRadians(rotation * this.rotationSpeed) * this.context.time.deltaTime;
|
|
134
|
+
if (this.lookForward && Math.abs(this._currentAngularSpeed.y) < .01) {
|
|
135
|
+
const forwardVector = this.context.mainCameraComponent!.forward;
|
|
136
|
+
forwardVector.y = 0;
|
|
137
|
+
forwardVector.normalize();
|
|
138
|
+
this._currentRotation.setFromUnitVectors(new Vector3(0, 0, 1), forwardVector);
|
|
139
|
+
this.gameObject.quaternion.slerp(this._currentRotation, this.context.time.deltaTime * 10);
|
|
140
|
+
}
|
|
141
|
+
this.gameObject.rotateY(this._currentAngularSpeed.y);
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
this._currentSpeed.multiplyScalar(1 - this.context.time.deltaTime * 10);
|
|
145
|
+
this._currentAngularSpeed.y *= 1 - this.context.time.deltaTime * 10;
|
|
146
|
+
|
|
147
|
+
if (this.controller && jump && this.jumpForce > 0) {
|
|
148
|
+
let canJump = this.controller?.isGrounded;
|
|
149
|
+
if (!this.controller?.isGrounded && this._jumpCount === 1) {
|
|
150
|
+
canJump = true;
|
|
151
|
+
this.animator?.SetBool("doubleJump", true);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (canJump) {
|
|
155
|
+
this._jumpCount += 1;
|
|
156
|
+
// TODO: factor in mass
|
|
157
|
+
const rb = this.controller.rigidbody;
|
|
158
|
+
// const fullJumpHoldLength = .1;
|
|
159
|
+
const factor = this._jumpCount === 2 ? 2 : 1;// Mathf.clamp((this.context.time.time - this._jumpDownTime), 0, fullJumpHoldLength) / fullJumpHoldLength;
|
|
160
|
+
rb.applyImpulse(new Vector3(0, 1, 0).multiplyScalar(this.jumpForce * factor));
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (this.controller) {
|
|
165
|
+
// TODO: should probably raycast to the ground or check if we're still in the jump animation
|
|
166
|
+
const verticalSpeed = this.controller?.rigidbody.getVelocity().y;
|
|
167
|
+
if (verticalSpeed < -1) {
|
|
168
|
+
if (!this._raycastOptions.ray) this._raycastOptions.ray = new Ray();
|
|
169
|
+
this._raycastOptions.ray.origin.copy(getWorldPosition(this.gameObject));
|
|
170
|
+
this._raycastOptions.ray.direction.set(0, -1, 0);
|
|
171
|
+
const currentLayer = this.layer;
|
|
172
|
+
this.gameObject.layers.disableAll();
|
|
173
|
+
this.gameObject.layers.set(2);
|
|
174
|
+
const hits = this.context.physics.raycast(this._raycastOptions);
|
|
175
|
+
this.gameObject.layers.set(currentLayer);
|
|
176
|
+
if ((hits.length && hits[0].distance > 2 || verticalSpeed < -10)) {
|
|
177
|
+
this.animator?.SetBool("falling", true);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
else this.animator?.SetBool("falling", false);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
private _raycastOptions = new RaycastOptions();
|
|
185
|
+
}
|
|
@@ -2,16 +2,9 @@ import { Behaviour } from "./Component";
|
|
|
2
2
|
import { Rigidbody } from "./RigidBody";
|
|
3
3
|
import { serializeable } from "../engine/engine_serialization_decorator";
|
|
4
4
|
import { Event, Mesh, Object3D, Vector3 } from "three"
|
|
5
|
-
import { IColliderProvider, registerColliderProvider } from "../engine/engine_physics";
|
|
5
|
+
// import { IColliderProvider, registerColliderProvider } from "../engine/engine_physics";
|
|
6
6
|
import { ICollider } from "../engine/engine_types";
|
|
7
|
-
import { getComponentInChildren } from "../engine/engine_components";
|
|
8
7
|
|
|
9
|
-
class ColliderProvider implements IColliderProvider {
|
|
10
|
-
getCollider(obj: Object3D): ICollider {
|
|
11
|
-
return getComponentInChildren<Collider>(obj, Collider);
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
registerColliderProvider(new ColliderProvider());
|
|
15
8
|
|
|
16
9
|
export class Collider extends Behaviour implements ICollider {
|
|
17
10
|
|
|
@@ -54,7 +47,7 @@ export class SphereCollider extends Collider {
|
|
|
54
47
|
@serializeable()
|
|
55
48
|
radius: number = .5;
|
|
56
49
|
@serializeable(Vector3)
|
|
57
|
-
center:
|
|
50
|
+
center: Vector3 = new Vector3(0, 0, 0);
|
|
58
51
|
|
|
59
52
|
onEnable() {
|
|
60
53
|
super.onEnable();
|
|
@@ -65,9 +58,9 @@ export class SphereCollider extends Collider {
|
|
|
65
58
|
export class BoxCollider extends Collider {
|
|
66
59
|
|
|
67
60
|
@serializeable(Vector3)
|
|
68
|
-
size:
|
|
61
|
+
size: Vector3 = new Vector3(1, 1, 1);
|
|
69
62
|
@serializeable(Vector3)
|
|
70
|
-
center:
|
|
63
|
+
center: Vector3 = new Vector3(0, 0, 0);
|
|
71
64
|
|
|
72
65
|
onEnable() {
|
|
73
66
|
super.onEnable();
|
|
@@ -83,10 +76,6 @@ export class MeshCollider extends Collider {
|
|
|
83
76
|
@serializeable()
|
|
84
77
|
convex: boolean = false;
|
|
85
78
|
|
|
86
|
-
awake(){
|
|
87
|
-
console.log(this);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
79
|
onEnable() {
|
|
91
80
|
super.onEnable();
|
|
92
81
|
if (!this.sharedMesh?.isMesh) {
|
|
@@ -98,4 +87,21 @@ export class MeshCollider extends Collider {
|
|
|
98
87
|
if (this.sharedMesh?.isMesh)
|
|
99
88
|
this.context.physics.addMeshCollider(this, this.sharedMesh, this.convex);
|
|
100
89
|
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
export class CapsuleCollider extends Collider {
|
|
94
|
+
@serializeable(Vector3)
|
|
95
|
+
center: Vector3 = new Vector3(0, 0, 0);
|
|
96
|
+
|
|
97
|
+
@serializeable()
|
|
98
|
+
radius: number = .5;
|
|
99
|
+
@serializeable()
|
|
100
|
+
height: number = 2;
|
|
101
|
+
|
|
102
|
+
onEnable() {
|
|
103
|
+
super.onEnable();
|
|
104
|
+
this.context.physics.addCapsuleCollider(this, this.center, this.height, this.radius);
|
|
105
|
+
}
|
|
106
|
+
|
|
101
107
|
}
|