@gg-web-engine/core 0.0.49 → 0.0.57
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/dist/2d/entities/entity-2d.d.ts +6 -3
- package/dist/2d/entities/entity-2d.js +20 -17
- package/dist/2d/gg-2d-world.d.ts +3 -0
- package/dist/2d/gg-2d-world.js +21 -13
- package/dist/2d/models/body-options.d.ts +4 -4
- package/dist/2d/models/body-options.js +6 -1
- package/dist/3d/entities/controllers/input/free-camera.controller.d.ts +9 -1
- package/dist/3d/entities/controllers/input/free-camera.controller.js +45 -12
- package/dist/3d/entities/controllers/input/orbit-camera.controller.d.ts +9 -8
- package/dist/3d/entities/controllers/input/orbit-camera.controller.js +46 -32
- package/dist/3d/entities/entity-3d.d.ts +6 -3
- package/dist/3d/entities/entity-3d.js +20 -17
- package/dist/3d/entities/raycast-vehicle-3d.entity.js +5 -5
- package/dist/3d/entities/surface-following.entity.d.ts +96 -0
- package/dist/3d/entities/surface-following.entity.js +296 -0
- package/dist/3d/gg-3d-world.d.ts +3 -0
- package/dist/3d/gg-3d-world.js +21 -13
- package/dist/3d/index.d.ts +1 -0
- package/dist/3d/index.js +1 -0
- package/dist/3d/loader.js +1 -1
- package/dist/3d/models/body-options.d.ts +4 -4
- package/dist/3d/models/body-options.js +6 -1
- package/dist/base/clock/global-clock.d.ts +2 -6
- package/dist/base/clock/global-clock.js +16 -16
- package/dist/base/clock/i-clock.d.ts +14 -5
- package/dist/base/clock/i-clock.js +43 -1
- package/dist/base/clock/pausable-clock.d.ts +3 -13
- package/dist/base/clock/pausable-clock.js +8 -16
- package/dist/base/components/physics/i-body.component.d.ts +5 -5
- package/dist/base/components/physics/i-physics-world.component.d.ts +43 -5
- package/dist/base/data-structures/bitmask.d.ts +5 -4
- package/dist/base/data-structures/bitmask.js +4 -3
- package/dist/base/gg-world.d.ts +8 -1
- package/dist/base/gg-world.js +102 -65
- package/dist/base/inputs/keyboard.input.d.ts +1 -1
- package/dist/base/inputs/keyboard.input.js +10 -10
- package/dist/base/inputs/mouse.input.js +3 -2
- package/dist/base/math/point2.d.ts +2 -0
- package/dist/base/math/point2.js +6 -3
- package/dist/base/math/point3.d.ts +2 -0
- package/dist/base/math/point3.js +6 -3
- package/dist/base/models/body-options.d.ts +27 -9
- package/dist/base/models/body-options.js +65 -1
- package/dist/dev/gg-console.ui.js +14 -4
- package/dist/dev/gg-debugger.ui.d.ts +2 -2
- package/dist/dev/gg-debugger.ui.js +15 -20
- package/dist/dev/gg-static.d.ts +6 -1
- package/dist/dev/gg-static.js +104 -25
- package/dist/index.d.ts +2 -0
- package/dist/index.js +3 -0
- package/dist/version.d.ts +1 -0
- package/dist/version.js +1 -0
- package/package.json +4 -3
|
@@ -3,8 +3,6 @@ import { IPositionable2d } from '../interfaces/i-positionable-2d';
|
|
|
3
3
|
import { IRenderable2dEntity } from './i-renderable-2d.entity';
|
|
4
4
|
import { PhysicsTypeDocRepo2D, VisualTypeDocRepo2D } from '../gg-2d-world';
|
|
5
5
|
export declare class Entity2d<VTypeDoc extends VisualTypeDocRepo2D = VisualTypeDocRepo2D, PTypeDoc extends PhysicsTypeDocRepo2D = PhysicsTypeDocRepo2D> extends IRenderable2dEntity<VTypeDoc, PTypeDoc> implements IPositionable2d {
|
|
6
|
-
readonly object2D: VTypeDoc['displayObject'] | null;
|
|
7
|
-
readonly objectBody: PTypeDoc['rigidBody'] | null;
|
|
8
6
|
readonly tickOrder = TickOrder.OBJECTS_BINDING;
|
|
9
7
|
private _position;
|
|
10
8
|
get position(): Point2;
|
|
@@ -12,10 +10,15 @@ export declare class Entity2d<VTypeDoc extends VisualTypeDocRepo2D = VisualTypeD
|
|
|
12
10
|
private _rotation;
|
|
13
11
|
get rotation(): number;
|
|
14
12
|
set rotation(value: number);
|
|
13
|
+
readonly object2D: VTypeDoc['displayObject'] | null;
|
|
14
|
+
readonly objectBody: PTypeDoc['rigidBody'] | null;
|
|
15
15
|
updateVisibility(): void;
|
|
16
16
|
/**
|
|
17
17
|
* Synchronize physics body transform with entity (and object2d if defined)
|
|
18
18
|
* */
|
|
19
19
|
protected runTransformBinding(objectBody: PTypeDoc['rigidBody'], object2D: VTypeDoc['displayObject'] | null): void;
|
|
20
|
-
constructor(
|
|
20
|
+
constructor(options: {
|
|
21
|
+
object2D?: VTypeDoc['displayObject'];
|
|
22
|
+
objectBody?: PTypeDoc['rigidBody'];
|
|
23
|
+
});
|
|
21
24
|
}
|
|
@@ -44,29 +44,32 @@ export class Entity2d extends IRenderable2dEntity {
|
|
|
44
44
|
this._position = pos;
|
|
45
45
|
this._rotation = quat;
|
|
46
46
|
}
|
|
47
|
-
constructor(
|
|
47
|
+
constructor(options) {
|
|
48
48
|
super();
|
|
49
|
-
this.object2D = object2D;
|
|
50
|
-
this.objectBody = objectBody;
|
|
51
49
|
this.tickOrder = TickOrder.OBJECTS_BINDING;
|
|
52
50
|
this._position = Pnt2.O;
|
|
53
51
|
this._rotation = 0;
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
this.
|
|
59
|
-
this.
|
|
52
|
+
this.object2D = null;
|
|
53
|
+
this.objectBody = null;
|
|
54
|
+
if (options.objectBody) {
|
|
55
|
+
this.objectBody = options.objectBody;
|
|
56
|
+
this.name = this.objectBody.name;
|
|
57
|
+
this.addComponents(this.objectBody);
|
|
60
58
|
}
|
|
61
|
-
|
|
62
|
-
this.
|
|
63
|
-
|
|
64
|
-
|
|
59
|
+
if (options.object2D) {
|
|
60
|
+
this.object2D = options.object2D;
|
|
61
|
+
if (!options.objectBody) {
|
|
62
|
+
this._position = this.object2D.position;
|
|
63
|
+
this._rotation = this.object2D.rotation;
|
|
64
|
+
this.name = this.object2D.name;
|
|
65
|
+
}
|
|
66
|
+
this.addComponents(this.object2D);
|
|
65
67
|
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
+
if (this.objectBody) {
|
|
69
|
+
this.tick$.subscribe(() => {
|
|
70
|
+
this.runTransformBinding(this.objectBody, this.object2D);
|
|
71
|
+
});
|
|
72
|
+
this.runTransformBinding(this.objectBody, this.object2D);
|
|
68
73
|
}
|
|
69
|
-
objectBody && this.addComponents(objectBody);
|
|
70
|
-
object2D && this.addComponents(object2D);
|
|
71
74
|
}
|
|
72
75
|
}
|
package/dist/2d/gg-2d-world.d.ts
CHANGED
|
@@ -27,4 +27,7 @@ export declare class Gg2dWorld<VTypeDoc extends VisualTypeDocRepo2D = VisualType
|
|
|
27
27
|
constructor(visualScene: VS, physicsWorld: PW);
|
|
28
28
|
addPrimitiveRigidBody(descr: BodyShape2DDescriptor, position?: Point2, rotation?: number, material?: DisplayObject2dOpts<VTypeDoc['texture']>): Entity2d<VTypeDoc, PTypeDoc>;
|
|
29
29
|
addRenderer(canvas?: HTMLCanvasElement, rendererOptions?: Partial<RendererOptions & VTypeDoc['rendererExtraOpts']>): Renderer2dEntity<VTypeDoc>;
|
|
30
|
+
protected registerConsoleCommands(ggstatic: {
|
|
31
|
+
registerConsoleCommand: (world: GgWorld<any, any> | null, command: string, handler: (...args: string[]) => Promise<string>, doc?: string) => void;
|
|
32
|
+
}): void;
|
|
30
33
|
}
|
package/dist/2d/gg-2d-world.js
CHANGED
|
@@ -15,21 +15,12 @@ export class Gg2dWorld extends GgWorld {
|
|
|
15
15
|
super(visualScene, physicsWorld);
|
|
16
16
|
this.visualScene = visualScene;
|
|
17
17
|
this.physicsWorld = physicsWorld;
|
|
18
|
-
if (window.ggstatic) {
|
|
19
|
-
window.ggstatic.registerConsoleCommand(this, 'ph_gravity', (...args) => __awaiter(this, void 0, void 0, function* () {
|
|
20
|
-
if (args.length == 1) {
|
|
21
|
-
args = ['0', args[0]]; // mean Y axis
|
|
22
|
-
}
|
|
23
|
-
if (args.length > 0) {
|
|
24
|
-
this.physicsWorld.gravity = { x: +args[0], y: +args[1] };
|
|
25
|
-
}
|
|
26
|
-
return JSON.stringify(this.physicsWorld.gravity);
|
|
27
|
-
}), 'args: [float] or [float float]; change 2D world gravity vector. 1 argument means ' +
|
|
28
|
-
'{x: 0, y: value}, 2 arguments set the whole vector. Default value is "9.82" or "0 9.82"');
|
|
29
|
-
}
|
|
30
18
|
}
|
|
31
19
|
addPrimitiveRigidBody(descr, position = Pnt2.O, rotation = 0, material = {}) {
|
|
32
|
-
const entity = new Entity2d(
|
|
20
|
+
const entity = new Entity2d({
|
|
21
|
+
object2D: this.visualScene.factory.createPrimitive(descr.shape, material),
|
|
22
|
+
objectBody: this.physicsWorld.factory.createRigidBody(descr),
|
|
23
|
+
});
|
|
33
24
|
entity.position = position;
|
|
34
25
|
entity.rotation = rotation;
|
|
35
26
|
this.addEntity(entity);
|
|
@@ -40,4 +31,21 @@ export class Gg2dWorld extends GgWorld {
|
|
|
40
31
|
this.addEntity(entity);
|
|
41
32
|
return entity;
|
|
42
33
|
}
|
|
34
|
+
registerConsoleCommands(ggstatic) {
|
|
35
|
+
super.registerConsoleCommands(ggstatic);
|
|
36
|
+
ggstatic.registerConsoleCommand(this, 'gravity', (...args) => __awaiter(this, void 0, void 0, function* () {
|
|
37
|
+
if (args.length == 1) {
|
|
38
|
+
args = ['0', args[0]]; // mean Y axis
|
|
39
|
+
}
|
|
40
|
+
if (args.length > 0) {
|
|
41
|
+
if (isNaN(+args[0]) || isNaN(+args[1])) {
|
|
42
|
+
throw new Error('Wrong arguments');
|
|
43
|
+
}
|
|
44
|
+
this.physicsWorld.gravity = { x: +args[0], y: +args[1] };
|
|
45
|
+
}
|
|
46
|
+
return JSON.stringify(this.physicsWorld.gravity);
|
|
47
|
+
}), 'args: [ ?float, ?float ]; Get or set 2D world gravity vector. 1 argument sets' +
|
|
48
|
+
' vector {x: 0, y: value}, 2 arguments sets the whole vector.' +
|
|
49
|
+
' Default value is "9.82" or "0 9.82"');
|
|
50
|
+
}
|
|
43
51
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { BodyOptions, DebugBodySettings } from '../../base';
|
|
1
|
+
import { BodyOptions, DebugBodySettings, DebugBodyType } from '../../base';
|
|
2
2
|
import { Shape2DDescriptor } from './shapes';
|
|
3
3
|
export interface Body2DOptions extends BodyOptions {
|
|
4
4
|
}
|
|
5
|
-
export
|
|
6
|
-
shape: Shape2DDescriptor;
|
|
7
|
-
}
|
|
5
|
+
export declare class DebugBody2DSettings extends DebugBodySettings<Shape2DDescriptor> {
|
|
6
|
+
constructor(type: DebugBodyType, shape: Shape2DDescriptor, ignoreTransform?: boolean, color?: number | undefined);
|
|
7
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Subject } from 'rxjs';
|
|
2
|
+
import { DirectionKeyboardInput, DirectionKeyboardKeymap, GgWorld, IEntity, KeyboardInput, MouseInput, MouseInputOptions, MutableSpherical, Spherical, TickOrder } from '../../../../base';
|
|
2
3
|
import { Renderer3dEntity } from '../../renderer-3d.entity';
|
|
3
4
|
/**
|
|
4
5
|
* Options for configuring a FreeCameraInput controller.
|
|
@@ -57,6 +58,12 @@ export declare class FreeCameraController extends IEntity {
|
|
|
57
58
|
* The keyboard input controller used for camera movement.
|
|
58
59
|
*/
|
|
59
60
|
readonly directionsInput: DirectionKeyboardInput;
|
|
61
|
+
protected _spherical: MutableSpherical;
|
|
62
|
+
get active(): boolean;
|
|
63
|
+
set active(value: boolean);
|
|
64
|
+
get spherical(): Spherical;
|
|
65
|
+
set spherical(value: Spherical);
|
|
66
|
+
protected resetMotion$: Subject<void>;
|
|
60
67
|
/**
|
|
61
68
|
* Creates a new FreeCameraInput instance.
|
|
62
69
|
* @param keyboard The keyboard input controller to use for camera movement.
|
|
@@ -64,6 +71,7 @@ export declare class FreeCameraController extends IEntity {
|
|
|
64
71
|
* @param options Optional configuration options for the controller.
|
|
65
72
|
*/
|
|
66
73
|
constructor(keyboard: KeyboardInput, camera: Renderer3dEntity, options?: Partial<FreeCameraControllerOptions>);
|
|
74
|
+
reset(): void;
|
|
67
75
|
onSpawned(world: GgWorld<any, any>): Promise<void>;
|
|
68
76
|
onRemoved(): Promise<void>;
|
|
69
77
|
}
|
|
@@ -7,7 +7,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
7
7
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
|
-
import { BehaviorSubject, combineLatest, filter, takeUntil } from 'rxjs';
|
|
10
|
+
import { BehaviorSubject, combineLatest, filter, Subject, takeUntil } from 'rxjs';
|
|
11
11
|
import { DirectionKeyboardInput, ggElastic, IEntity, MouseInput, Pnt2, Pnt3, Qtrn, TickOrder, } from '../../../../base';
|
|
12
12
|
import { map } from 'rxjs/operators';
|
|
13
13
|
const DEFAULT_FREE_CAMERA_CONTROLLER_OPTIONS = {
|
|
@@ -25,6 +25,23 @@ const DEFAULT_FREE_CAMERA_CONTROLLER_OPTIONS = {
|
|
|
25
25
|
* A controller for a free-moving camera.
|
|
26
26
|
*/
|
|
27
27
|
export class FreeCameraController extends IEntity {
|
|
28
|
+
get active() {
|
|
29
|
+
return super.active;
|
|
30
|
+
}
|
|
31
|
+
set active(value) {
|
|
32
|
+
if (!super.active && value) {
|
|
33
|
+
this.reset();
|
|
34
|
+
}
|
|
35
|
+
super.active = value;
|
|
36
|
+
}
|
|
37
|
+
get spherical() {
|
|
38
|
+
return this._spherical;
|
|
39
|
+
}
|
|
40
|
+
set spherical(value) {
|
|
41
|
+
this._spherical.phi = Math.max(0.000001, Math.min(Math.PI - 0.000001, value.phi));
|
|
42
|
+
this._spherical.theta = value.theta;
|
|
43
|
+
this.resetMotion$.next();
|
|
44
|
+
}
|
|
28
45
|
/**
|
|
29
46
|
* Creates a new FreeCameraInput instance.
|
|
30
47
|
* @param keyboard The keyboard input controller to use for camera movement.
|
|
@@ -36,6 +53,8 @@ export class FreeCameraController extends IEntity {
|
|
|
36
53
|
this.keyboard = keyboard;
|
|
37
54
|
this.camera = camera;
|
|
38
55
|
this.tickOrder = TickOrder.INPUT_CONTROLLERS;
|
|
56
|
+
this._spherical = { phi: 0, radius: 1, theta: 0 };
|
|
57
|
+
this.resetMotion$ = new Subject();
|
|
39
58
|
this.options = Object.assign(Object.assign({}, DEFAULT_FREE_CAMERA_CONTROLLER_OPTIONS), options);
|
|
40
59
|
if (options.mouseOptions) {
|
|
41
60
|
this.options.mouseOptions = Object.assign(Object.assign({}, DEFAULT_FREE_CAMERA_CONTROLLER_OPTIONS.mouseOptions), options.mouseOptions);
|
|
@@ -43,12 +62,17 @@ export class FreeCameraController extends IEntity {
|
|
|
43
62
|
this.mouseInput = new MouseInput(this.options.mouseOptions);
|
|
44
63
|
this.directionsInput = new DirectionKeyboardInput(keyboard, this.options.keymap);
|
|
45
64
|
}
|
|
65
|
+
reset() {
|
|
66
|
+
this._spherical = Pnt3.toSpherical(Pnt3.rot({ x: 0, y: 0, z: -1 }, this.camera.rotation));
|
|
67
|
+
this.resetMotion$.next();
|
|
68
|
+
}
|
|
46
69
|
onSpawned(world) {
|
|
47
70
|
const _super = Object.create(null, {
|
|
48
71
|
onSpawned: { get: () => super.onSpawned }
|
|
49
72
|
});
|
|
50
73
|
return __awaiter(this, void 0, void 0, function* () {
|
|
51
74
|
yield _super.onSpawned.call(this, world);
|
|
75
|
+
this._spherical = Pnt3.toSpherical(Pnt3.rot({ x: 0, y: 0, z: -1 }, this.camera.rotation));
|
|
52
76
|
// Subscribe to keyboard input for movement controls
|
|
53
77
|
const keys = ['KeyE', 'KeyQ'];
|
|
54
78
|
if (this.camera.camera.supportsFov) {
|
|
@@ -87,11 +111,11 @@ export class FreeCameraController extends IEntity {
|
|
|
87
111
|
cameraFovInc = f;
|
|
88
112
|
});
|
|
89
113
|
// Subscribe to mouse input for camera rotation
|
|
90
|
-
const spherical = Pnt3.toSpherical(Pnt3.rot({ x: 0, y: 0, z: -1 }, this.camera.rotation));
|
|
91
114
|
let isTouchScreen = MouseInput.isTouchDevice();
|
|
92
|
-
let mouseDelta$ = this.mouseInput.delta$.pipe(takeUntil(this._onRemoved$), filter(() =>
|
|
115
|
+
let mouseDelta$ = this.mouseInput.delta$.pipe(takeUntil(this._onRemoved$), filter(() => this.active &&
|
|
116
|
+
(isTouchScreen || !this.options.ignoreMouseUnlessPointerLocked || this.mouseInput.isPointerLocked)));
|
|
93
117
|
if (this.options.cameraRotationElasticity > 0) {
|
|
94
|
-
const s$ = new BehaviorSubject(
|
|
118
|
+
const s$ = new BehaviorSubject(this._spherical);
|
|
95
119
|
mouseDelta$.subscribe(delta => {
|
|
96
120
|
const s = s$.getValue();
|
|
97
121
|
s$.next({
|
|
@@ -100,23 +124,32 @@ export class FreeCameraController extends IEntity {
|
|
|
100
124
|
radius: 1,
|
|
101
125
|
});
|
|
102
126
|
});
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
127
|
+
const startElasticMotion = () => {
|
|
128
|
+
s$.pipe(takeUntil(this._onRemoved$), ggElastic(this.tick$, this.options.cameraRotationElasticity, (a, b, f) => ({ phi: a.phi + f * (b.phi - a.phi), theta: a.theta + f * (b.theta - a.theta), radius: 1 }), (a, b) => Pnt2.dist({ x: a.phi, y: a.theta }, { x: b.phi, y: b.theta }) < 0.0001), takeUntil(this.resetMotion$)).subscribe(s => {
|
|
129
|
+
this._spherical.theta = s.theta;
|
|
130
|
+
this._spherical.phi = s.phi;
|
|
131
|
+
});
|
|
132
|
+
};
|
|
133
|
+
this.resetMotion$.pipe(takeUntil(this._onRemoved$)).subscribe(() => {
|
|
134
|
+
s$.next(this._spherical);
|
|
135
|
+
startElasticMotion();
|
|
106
136
|
});
|
|
137
|
+
startElasticMotion();
|
|
107
138
|
}
|
|
108
139
|
else {
|
|
109
140
|
mouseDelta$.subscribe(delta => {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
141
|
+
this._spherical.theta -= (delta.x * this.options.cameraRotationSensitivity) / 1000;
|
|
142
|
+
this._spherical.phi += (delta.y * this.options.cameraRotationSensitivity) / 1000;
|
|
143
|
+
this._spherical.phi = Math.max(0.000001, Math.min(Math.PI - 0.000001, this._spherical.phi));
|
|
113
144
|
});
|
|
114
145
|
}
|
|
115
146
|
// Setup updating camera position and rotation based on input
|
|
116
|
-
this.camera.tick
|
|
147
|
+
this.camera.tick$
|
|
148
|
+
.pipe(takeUntil(this._onRemoved$), filter(() => this.active))
|
|
149
|
+
.subscribe(([_, delta]) => {
|
|
117
150
|
this.camera.camera.fov += cameraFovInc;
|
|
118
151
|
this.camera.position = Pnt3.add(this.camera.position, Pnt3.rot(Pnt3.scalarMult(translateVector, (this.options.cameraLinearSpeed * delta) / 1000), this.camera.rotation));
|
|
119
|
-
this.camera.rotation = Qtrn.lookAt(this.camera.position, Pnt3.add(this.camera.position, Pnt3.fromSpherical(
|
|
152
|
+
this.camera.rotation = Qtrn.lookAt(this.camera.position, Pnt3.add(this.camera.position, Pnt3.fromSpherical(this._spherical)));
|
|
120
153
|
});
|
|
121
154
|
// start input
|
|
122
155
|
this.mouseInput.start();
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { GgWorld, IEntity, MouseInput, MouseInputOptions, MutableSpherical, Point3, TickOrder } from '../../../../base';
|
|
1
|
+
import { GgWorld, IEntity, MouseInput, MouseInputOptions, MutableSpherical, Point3, Spherical, TickOrder } from '../../../../base';
|
|
2
|
+
import { Subject } from 'rxjs';
|
|
2
3
|
import { Renderer3dEntity } from '../../renderer-3d.entity';
|
|
3
4
|
export type OrbitCameraControllerOptions = {
|
|
4
5
|
/**
|
|
@@ -41,15 +42,15 @@ export declare class OrbitCameraController extends IEntity {
|
|
|
41
42
|
readonly tickOrder = TickOrder.INPUT_CONTROLLERS;
|
|
42
43
|
protected readonly options: OrbitCameraControllerOptions;
|
|
43
44
|
readonly mouseInput: MouseInput;
|
|
44
|
-
protected
|
|
45
|
+
protected _spherical: MutableSpherical;
|
|
45
46
|
target: Point3;
|
|
46
|
-
get
|
|
47
|
-
set
|
|
48
|
-
get
|
|
49
|
-
set
|
|
50
|
-
|
|
51
|
-
set theta(value: number);
|
|
47
|
+
get active(): boolean;
|
|
48
|
+
set active(value: boolean);
|
|
49
|
+
get spherical(): Spherical;
|
|
50
|
+
set spherical(value: Spherical);
|
|
51
|
+
protected resetMotion$: Subject<void>;
|
|
52
52
|
constructor(camera: Renderer3dEntity, options?: Partial<OrbitCameraControllerOptions>);
|
|
53
|
+
reset(): void;
|
|
53
54
|
onSpawned(world: GgWorld<any, any>): Promise<void>;
|
|
54
55
|
onRemoved(): Promise<void>;
|
|
55
56
|
}
|
|
@@ -8,7 +8,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
10
|
import { ggElastic, IEntity, MouseInput, MouseInputState, Pnt2, Pnt3, Qtrn, TickOrder, } from '../../../../base';
|
|
11
|
-
import { BehaviorSubject, filter, takeUntil } from 'rxjs';
|
|
11
|
+
import { BehaviorSubject, filter, Subject, takeUntil } from 'rxjs';
|
|
12
12
|
import { map } from 'rxjs/operators';
|
|
13
13
|
const DEFAULT_OPTIONS = {
|
|
14
14
|
mouseOptions: {},
|
|
@@ -19,44 +19,51 @@ const DEFAULT_OPTIONS = {
|
|
|
19
19
|
dollying: { sensitivity: 1 },
|
|
20
20
|
};
|
|
21
21
|
export class OrbitCameraController extends IEntity {
|
|
22
|
-
get
|
|
23
|
-
return
|
|
22
|
+
get active() {
|
|
23
|
+
return super.active;
|
|
24
24
|
}
|
|
25
|
-
set
|
|
26
|
-
|
|
25
|
+
set active(value) {
|
|
26
|
+
if (!super.active && value) {
|
|
27
|
+
this.reset();
|
|
28
|
+
}
|
|
29
|
+
super.active = value;
|
|
27
30
|
}
|
|
28
|
-
get
|
|
29
|
-
return this.
|
|
31
|
+
get spherical() {
|
|
32
|
+
return this._spherical;
|
|
30
33
|
}
|
|
31
|
-
set
|
|
32
|
-
this.
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
}
|
|
37
|
-
set theta(value) {
|
|
38
|
-
this.spherical.theta = value;
|
|
34
|
+
set spherical(value) {
|
|
35
|
+
this._spherical.phi = Math.max(0.000001, Math.min(Math.PI - 0.000001, value.phi));
|
|
36
|
+
this._spherical.theta = value.theta;
|
|
37
|
+
this._spherical.radius = value.radius;
|
|
38
|
+
this.resetMotion$.next();
|
|
39
39
|
}
|
|
40
40
|
constructor(camera, options = {}) {
|
|
41
41
|
super();
|
|
42
42
|
this.camera = camera;
|
|
43
43
|
this.tickOrder = TickOrder.INPUT_CONTROLLERS;
|
|
44
|
-
this.
|
|
44
|
+
this._spherical = { phi: 0, radius: 10, theta: 0 };
|
|
45
45
|
this.target = Pnt3.O;
|
|
46
|
+
this.resetMotion$ = new Subject();
|
|
46
47
|
this.options = Object.assign(Object.assign({}, DEFAULT_OPTIONS), options);
|
|
47
48
|
this.mouseInput = new MouseInput(this.options.mouseOptions);
|
|
48
49
|
}
|
|
50
|
+
reset() {
|
|
51
|
+
let targetDistance = Pnt3.dist(this.target, this.camera.position);
|
|
52
|
+
this.target = Pnt3.add(this.camera.position, Pnt3.rot({ x: 0, y: 0, z: -targetDistance }, this.camera.rotation));
|
|
53
|
+
this._spherical = Pnt3.toSpherical(Pnt3.sub(this.camera.position, this.target));
|
|
54
|
+
this.resetMotion$.next();
|
|
55
|
+
}
|
|
49
56
|
onSpawned(world) {
|
|
50
57
|
const _super = Object.create(null, {
|
|
51
58
|
onSpawned: { get: () => super.onSpawned }
|
|
52
59
|
});
|
|
53
60
|
return __awaiter(this, void 0, void 0, function* () {
|
|
54
61
|
yield _super.onSpawned.call(this, world);
|
|
55
|
-
this.
|
|
62
|
+
this._spherical = Pnt3.toSpherical(Pnt3.sub(this.camera.position, this.target));
|
|
56
63
|
if (this.options.orbiting) {
|
|
57
|
-
let mouseDelta$ = this.mouseInput.delta$.pipe(takeUntil(this._onRemoved$), filter(() => this.mouseInput.state == MouseInputState.DRAG));
|
|
64
|
+
let mouseDelta$ = this.mouseInput.delta$.pipe(takeUntil(this._onRemoved$), filter(() => this.active && this.mouseInput.state == MouseInputState.DRAG));
|
|
58
65
|
if (this.options.orbitingElasticity > 0) {
|
|
59
|
-
const s$ = new BehaviorSubject(this.
|
|
66
|
+
const s$ = new BehaviorSubject(this._spherical);
|
|
60
67
|
mouseDelta$.subscribe(delta => {
|
|
61
68
|
const s = s$.getValue();
|
|
62
69
|
s$.next({
|
|
@@ -65,31 +72,38 @@ export class OrbitCameraController extends IEntity {
|
|
|
65
72
|
radius: 1,
|
|
66
73
|
});
|
|
67
74
|
});
|
|
68
|
-
|
|
69
|
-
this.
|
|
70
|
-
|
|
75
|
+
const startElasticMotion = () => {
|
|
76
|
+
s$.pipe(takeUntil(this._onRemoved$), ggElastic(this.tick$, this.options.orbitingElasticity, (a, b, f) => ({ phi: a.phi + f * (b.phi - a.phi), theta: a.theta + f * (b.theta - a.theta), radius: 1 }), (a, b) => Pnt2.dist({ x: a.phi, y: a.theta }, { x: b.phi, y: b.theta }) < 0.0001), takeUntil(this.resetMotion$)).subscribe(s => {
|
|
77
|
+
this._spherical.theta = s.theta;
|
|
78
|
+
this._spherical.phi = s.phi;
|
|
79
|
+
});
|
|
80
|
+
};
|
|
81
|
+
this.resetMotion$.pipe(takeUntil(this._onRemoved$)).subscribe(() => {
|
|
82
|
+
s$.next(this._spherical);
|
|
83
|
+
startElasticMotion();
|
|
71
84
|
});
|
|
85
|
+
startElasticMotion();
|
|
72
86
|
}
|
|
73
87
|
else {
|
|
74
88
|
mouseDelta$.subscribe(delta => {
|
|
75
|
-
this.
|
|
76
|
-
this.
|
|
77
|
-
this.
|
|
89
|
+
this._spherical.theta -= (delta.x * this.options.orbiting.sensitivityX) / 1000;
|
|
90
|
+
this._spherical.phi -= (delta.y * this.options.orbiting.sensitivityY) / 1000;
|
|
91
|
+
this._spherical.phi = Math.max(0.000001, Math.min(Math.PI - 0.000001, this._spherical.phi));
|
|
78
92
|
});
|
|
79
93
|
}
|
|
80
94
|
}
|
|
81
95
|
if (this.options.zooming) {
|
|
82
96
|
this.mouseInput.wheel$.pipe(takeUntil(this._onRemoved$)).subscribe(delta => {
|
|
83
97
|
if (delta != 0) {
|
|
84
|
-
this.
|
|
98
|
+
this._spherical.radius *= Math.pow(0.95, this.options.zooming.sensitivity * (delta > 0 ? -1 : 1));
|
|
85
99
|
}
|
|
86
100
|
});
|
|
87
101
|
}
|
|
88
102
|
const performPan = (delta) => {
|
|
89
|
-
const targetCameraVector = Pnt3.fromSpherical(this.
|
|
103
|
+
const targetCameraVector = Pnt3.fromSpherical(this._spherical);
|
|
90
104
|
const viewUp = Pnt3.rotAround(targetCameraVector, {
|
|
91
|
-
x: -Math.sin(this.
|
|
92
|
-
y: Math.cos(this.
|
|
105
|
+
x: -Math.sin(this._spherical.theta),
|
|
106
|
+
y: Math.cos(this._spherical.theta),
|
|
93
107
|
z: 0,
|
|
94
108
|
}, Math.PI / 2);
|
|
95
109
|
const viewRight = Pnt3.rotAround(targetCameraVector, Pnt3.norm(viewUp), Math.PI / 2);
|
|
@@ -106,14 +120,14 @@ export class OrbitCameraController extends IEntity {
|
|
|
106
120
|
this.mouseInput.delta$
|
|
107
121
|
.pipe(takeUntil(this._onRemoved$), filter(() => this.mouseInput.state == MouseInputState.DRAG_MIDDLE_BUTTON))
|
|
108
122
|
.subscribe(delta => {
|
|
109
|
-
this.
|
|
123
|
+
this._spherical.radius *= Math.pow(0.95, (-this.options.dollying.sensitivity * delta.y) / 10);
|
|
110
124
|
});
|
|
111
125
|
}
|
|
112
126
|
if (MouseInput.isTouchDevice() && (this.options.dollying || this.options.panning)) {
|
|
113
127
|
this.mouseInput.twoTouchGestureDelta$.pipe(takeUntil(this._onRemoved$)).subscribe(delta => {
|
|
114
128
|
// dolly on fingers pitch
|
|
115
129
|
if (this.options.dollying) {
|
|
116
|
-
this.
|
|
130
|
+
this._spherical.radius *= Math.pow(0.95, (this.options.dollying.sensitivity * delta.distanceDelta) / 10);
|
|
117
131
|
}
|
|
118
132
|
// pan on fingers move
|
|
119
133
|
if (this.options.panning) {
|
|
@@ -123,7 +137,7 @@ export class OrbitCameraController extends IEntity {
|
|
|
123
137
|
}
|
|
124
138
|
// Setup updating camera position and rotation based on input
|
|
125
139
|
this.camera.tick$
|
|
126
|
-
.pipe(takeUntil(this._onRemoved$), map(() => this.
|
|
140
|
+
.pipe(takeUntil(this._onRemoved$), filter(() => this.active), map(() => this._spherical))
|
|
127
141
|
.subscribe(spherical => {
|
|
128
142
|
this.camera.position = Pnt3.add(this.target, Pnt3.fromSpherical(spherical));
|
|
129
143
|
this.camera.rotation = Qtrn.lookAt(this.camera.position, this.target);
|
|
@@ -5,8 +5,6 @@ import { IPositionable3d } from '../interfaces/i-positionable-3d';
|
|
|
5
5
|
import { IRenderable3dEntity } from './i-renderable-3d.entity';
|
|
6
6
|
import { PhysicsTypeDocRepo3D, VisualTypeDocRepo3D } from '../gg-3d-world';
|
|
7
7
|
export declare class Entity3d<VTypeDoc extends VisualTypeDocRepo3D = VisualTypeDocRepo3D, PTypeDoc extends PhysicsTypeDocRepo3D = PhysicsTypeDocRepo3D> extends IRenderable3dEntity<VTypeDoc, PTypeDoc> implements IPositionable3d {
|
|
8
|
-
readonly object3D: VTypeDoc['displayObject'] | null;
|
|
9
|
-
readonly objectBody: PTypeDoc['rigidBody'] | null;
|
|
10
8
|
readonly tickOrder = TickOrder.OBJECTS_BINDING;
|
|
11
9
|
private _position;
|
|
12
10
|
get position(): Point3;
|
|
@@ -14,10 +12,15 @@ export declare class Entity3d<VTypeDoc extends VisualTypeDocRepo3D = VisualTypeD
|
|
|
14
12
|
private _rotation;
|
|
15
13
|
get rotation(): Point4;
|
|
16
14
|
set rotation(value: Point4);
|
|
15
|
+
readonly object3D: VTypeDoc['displayObject'] | null;
|
|
16
|
+
readonly objectBody: PTypeDoc['rigidBody'] | null;
|
|
17
17
|
updateVisibility(): void;
|
|
18
18
|
/**
|
|
19
19
|
* Synchronize physics body transform with entity (and mesh if defined)
|
|
20
20
|
* */
|
|
21
21
|
protected runTransformBinding(objectBody: IRigidBody3dComponent, object3D: IDisplayObject3dComponent | null): void;
|
|
22
|
-
constructor(
|
|
22
|
+
constructor(options: {
|
|
23
|
+
object3D?: VTypeDoc['displayObject'] | null;
|
|
24
|
+
objectBody?: PTypeDoc['rigidBody'] | null;
|
|
25
|
+
});
|
|
23
26
|
}
|
|
@@ -44,29 +44,32 @@ export class Entity3d extends IRenderable3dEntity {
|
|
|
44
44
|
this._position = pos;
|
|
45
45
|
this._rotation = quat;
|
|
46
46
|
}
|
|
47
|
-
constructor(
|
|
47
|
+
constructor(options) {
|
|
48
48
|
super();
|
|
49
|
-
this.object3D = object3D;
|
|
50
|
-
this.objectBody = objectBody;
|
|
51
49
|
this.tickOrder = TickOrder.OBJECTS_BINDING;
|
|
52
50
|
this._position = Pnt3.O;
|
|
53
51
|
this._rotation = Qtrn.O;
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
this.
|
|
59
|
-
this.
|
|
52
|
+
this.object3D = null;
|
|
53
|
+
this.objectBody = null;
|
|
54
|
+
if (options.objectBody) {
|
|
55
|
+
this.objectBody = options.objectBody;
|
|
56
|
+
this.name = this.objectBody.name;
|
|
57
|
+
this.addComponents(this.objectBody);
|
|
60
58
|
}
|
|
61
|
-
|
|
62
|
-
this.
|
|
63
|
-
|
|
64
|
-
|
|
59
|
+
if (options.object3D) {
|
|
60
|
+
this.object3D = options.object3D;
|
|
61
|
+
if (!options.objectBody) {
|
|
62
|
+
this._position = this.object3D.position;
|
|
63
|
+
this._rotation = this.object3D.rotation;
|
|
64
|
+
this.name = this.object3D.name;
|
|
65
|
+
}
|
|
66
|
+
this.addComponents(this.object3D);
|
|
65
67
|
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
+
if (this.objectBody) {
|
|
69
|
+
this.tick$.subscribe(() => {
|
|
70
|
+
this.runTransformBinding(this.objectBody, this.object3D);
|
|
71
|
+
});
|
|
72
|
+
this.runTransformBinding(this.objectBody, this.object3D);
|
|
68
73
|
}
|
|
69
|
-
objectBody && this.addComponents(objectBody);
|
|
70
|
-
object3D && this.addComponents(object3D);
|
|
71
74
|
}
|
|
72
75
|
}
|
|
@@ -56,7 +56,7 @@ export class RaycastVehicle3dEntity extends Entity3d {
|
|
|
56
56
|
}
|
|
57
57
|
/** car mesh and physics body direction has to be pointing: y front, z up*/
|
|
58
58
|
constructor(carProperties, chassis3D, vehicleComponent) {
|
|
59
|
-
super(chassis3D, vehicleComponent);
|
|
59
|
+
super({ object3D: chassis3D, objectBody: vehicleComponent });
|
|
60
60
|
this.carProperties = carProperties;
|
|
61
61
|
this.chassis3D = chassis3D;
|
|
62
62
|
this.vehicleComponent = vehicleComponent;
|
|
@@ -104,9 +104,9 @@ export class RaycastVehicle3dEntity extends Entity3d {
|
|
|
104
104
|
this.wheelLocalRotation.push(null);
|
|
105
105
|
continue;
|
|
106
106
|
}
|
|
107
|
-
const
|
|
107
|
+
const displayObj = display.displayObject.clone();
|
|
108
108
|
if (display.autoScaleMesh) {
|
|
109
|
-
const boundingBox = Box.expandByPoint(
|
|
109
|
+
const boundingBox = Box.expandByPoint(displayObj.getBoundings(), Pnt3.O);
|
|
110
110
|
const scale = Object.assign({}, Pnt3.O);
|
|
111
111
|
const wheelObjectDirection = display.wheelObjectDirection || 'x';
|
|
112
112
|
for (const dir of ['x', 'y', 'z']) {
|
|
@@ -115,7 +115,7 @@ export class RaycastVehicle3dEntity extends Entity3d {
|
|
|
115
115
|
? options.tyreWidth / (boundingBox.max[dir] - boundingBox.min[dir])
|
|
116
116
|
: (options.tyreRadius * 2) / (boundingBox.max[dir] - boundingBox.min[dir]);
|
|
117
117
|
}
|
|
118
|
-
|
|
118
|
+
displayObj.scale = scale;
|
|
119
119
|
}
|
|
120
120
|
const direction = display.wheelObjectDirection || 'x';
|
|
121
121
|
const flip = direction.includes('-') ? options.isLeft : !options.isLeft;
|
|
@@ -134,7 +134,7 @@ export class RaycastVehicle3dEntity extends Entity3d {
|
|
|
134
134
|
localRotation = { x: 0, y: 0.707107 * (flip ? 1 : -1), z: 0, w: 0.707107 };
|
|
135
135
|
}
|
|
136
136
|
this.wheelLocalRotation.push(localRotation);
|
|
137
|
-
const wheelEntity = new Entity3d(
|
|
137
|
+
const wheelEntity = new Entity3d({ object3D: displayObj });
|
|
138
138
|
wheelEntity.name = this.name + '__wheel_' + (options.isFront ? 'f' : 'r') + (options.isLeft ? 'l' : 'r');
|
|
139
139
|
this.wheels.push(wheelEntity);
|
|
140
140
|
}
|