@gg-web-engine/core 0.0.48 → 0.0.56
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/shapes.d.ts +3 -1
- package/dist/3d/entities/controllers/input/car-keyboard-handling.controller.d.ts +1 -1
- package/dist/3d/entities/controllers/input/free-camera.controller.d.ts +32 -13
- package/dist/3d/entities/controllers/input/free-camera.controller.js +99 -45
- package/dist/3d/entities/controllers/input/gg-car-keyboard-handling.controller.d.ts +1 -1
- package/dist/3d/entities/controllers/input/orbit-camera.controller.d.ts +29 -9
- package/dist/3d/entities/controllers/input/orbit-camera.controller.js +64 -33
- 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/gg-3d-world.d.ts +3 -0
- package/dist/3d/gg-3d-world.js +21 -13
- package/dist/3d/loader.js +1 -1
- package/dist/3d/models/shapes.d.ts +3 -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/gg-world.d.ts +6 -0
- package/dist/base/gg-world.js +102 -65
- package/dist/base/index.d.ts +1 -0
- package/dist/base/index.js +1 -0
- 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.d.ts +1 -0
- package/dist/base/inputs/mouse.input.js +6 -2
- package/dist/base/pipes/gg-elastic.pipe.d.ts +5 -0
- package/dist/base/pipes/gg-elastic.pipe.js +44 -0
- 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 +13 -10
- 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,12 +1,14 @@
|
|
|
1
1
|
import { Point2 } from '../../base';
|
|
2
2
|
import { Body2DOptions } from './body-options';
|
|
3
3
|
export type Shape2DDescriptor = {
|
|
4
|
+
collisionMargin?: number;
|
|
5
|
+
} & ({
|
|
4
6
|
shape: 'SQUARE';
|
|
5
7
|
dimensions: Point2;
|
|
6
8
|
} | {
|
|
7
9
|
shape: 'CIRCLE';
|
|
8
10
|
radius: number;
|
|
9
|
-
};
|
|
11
|
+
});
|
|
10
12
|
export type BodyShape2DDescriptor = {
|
|
11
13
|
shape: Shape2DDescriptor;
|
|
12
14
|
body: Partial<Body2DOptions>;
|
|
@@ -12,7 +12,7 @@ export declare class CarKeyboardHandlingController extends IEntity {
|
|
|
12
12
|
protected readonly keyboard: KeyboardInput;
|
|
13
13
|
protected readonly options: CarKeyboardControllerOptions;
|
|
14
14
|
readonly tickOrder = TickOrder.INPUT_CONTROLLERS;
|
|
15
|
-
|
|
15
|
+
readonly directionsInput: DirectionKeyboardInput;
|
|
16
16
|
private _output$;
|
|
17
17
|
get output$(): Observable<CarHandlingOutput>;
|
|
18
18
|
constructor(keyboard: KeyboardInput, options?: CarKeyboardControllerOptions);
|
|
@@ -1,28 +1,40 @@
|
|
|
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.
|
|
5
6
|
*/
|
|
6
7
|
export type FreeCameraControllerOptions = {
|
|
7
8
|
/**
|
|
8
|
-
* A keymap for controlling camera movement, where each key corresponds to a movement direction.
|
|
9
|
+
* A keymap for controlling camera movement, where each key corresponds to a movement direction. 'wasd' by default
|
|
9
10
|
*/
|
|
10
11
|
keymap: DirectionKeyboardKeymap;
|
|
11
12
|
/**
|
|
12
|
-
*
|
|
13
|
+
* The speed of camera movement in meters per second. 20 by default
|
|
13
14
|
*/
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* The speed of camera movement.
|
|
17
|
-
*/
|
|
18
|
-
speed: number;
|
|
19
|
-
};
|
|
15
|
+
cameraLinearSpeed: number;
|
|
20
16
|
/**
|
|
21
|
-
*
|
|
17
|
+
* An elasticity factor for camera movement. 0 by default (no elastic motion)
|
|
18
|
+
*/
|
|
19
|
+
cameraMovementElasticity: number;
|
|
20
|
+
/**
|
|
21
|
+
* A linear speed multiplier when user holds shift key. 2.5 by default
|
|
22
|
+
*/
|
|
23
|
+
cameraBoostMultiplier: number;
|
|
24
|
+
/**
|
|
25
|
+
* The speed of camera rotation in radians per 1000px mouse movement. 1 by default
|
|
26
|
+
*/
|
|
27
|
+
cameraRotationSensitivity: number;
|
|
28
|
+
/**
|
|
29
|
+
* An elasticity factor for camera rotation. 0 by default (no elastic motion)
|
|
30
|
+
*/
|
|
31
|
+
cameraRotationElasticity: number;
|
|
32
|
+
/**
|
|
33
|
+
* Flag to ignore cursor movement if pointer was not locked. false by default
|
|
22
34
|
*/
|
|
23
35
|
ignoreMouseUnlessPointerLocked: boolean;
|
|
24
36
|
/**
|
|
25
|
-
* Flag to ignore keyboard events if pointer was not locked.
|
|
37
|
+
* Flag to ignore keyboard events if pointer was not locked. false by default
|
|
26
38
|
*/
|
|
27
39
|
ignoreKeyboardUnlessPointerLocked: boolean;
|
|
28
40
|
/**
|
|
@@ -41,11 +53,17 @@ export declare class FreeCameraController extends IEntity {
|
|
|
41
53
|
/**
|
|
42
54
|
* The mouse input controller used for camera rotation.
|
|
43
55
|
*/
|
|
44
|
-
|
|
56
|
+
readonly mouseInput: MouseInput;
|
|
45
57
|
/**
|
|
46
58
|
* The keyboard input controller used for camera movement.
|
|
47
59
|
*/
|
|
48
|
-
|
|
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>;
|
|
49
67
|
/**
|
|
50
68
|
* Creates a new FreeCameraInput instance.
|
|
51
69
|
* @param keyboard The keyboard input controller to use for camera movement.
|
|
@@ -53,6 +71,7 @@ export declare class FreeCameraController extends IEntity {
|
|
|
53
71
|
* @param options Optional configuration options for the controller.
|
|
54
72
|
*/
|
|
55
73
|
constructor(keyboard: KeyboardInput, camera: Renderer3dEntity, options?: Partial<FreeCameraControllerOptions>);
|
|
74
|
+
reset(): void;
|
|
56
75
|
onSpawned(world: GgWorld<any, any>): Promise<void>;
|
|
57
76
|
onRemoved(): Promise<void>;
|
|
58
77
|
}
|
|
@@ -7,11 +7,16 @@ 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 { combineLatest, filter, takeUntil } from 'rxjs';
|
|
11
|
-
import { DirectionKeyboardInput, IEntity, MouseInput, Pnt2, Pnt3, Qtrn, TickOrder, } from '../../../../base';
|
|
10
|
+
import { BehaviorSubject, combineLatest, filter, Subject, takeUntil } from 'rxjs';
|
|
11
|
+
import { DirectionKeyboardInput, ggElastic, IEntity, MouseInput, Pnt2, Pnt3, Qtrn, TickOrder, } from '../../../../base';
|
|
12
|
+
import { map } from 'rxjs/operators';
|
|
12
13
|
const DEFAULT_FREE_CAMERA_CONTROLLER_OPTIONS = {
|
|
13
14
|
keymap: 'wasd',
|
|
14
|
-
|
|
15
|
+
cameraLinearSpeed: 20,
|
|
16
|
+
cameraMovementElasticity: 0,
|
|
17
|
+
cameraBoostMultiplier: 2.5,
|
|
18
|
+
cameraRotationSensitivity: 1,
|
|
19
|
+
cameraRotationElasticity: 0,
|
|
15
20
|
mouseOptions: {},
|
|
16
21
|
ignoreMouseUnlessPointerLocked: false,
|
|
17
22
|
ignoreKeyboardUnlessPointerLocked: false,
|
|
@@ -20,6 +25,23 @@ const DEFAULT_FREE_CAMERA_CONTROLLER_OPTIONS = {
|
|
|
20
25
|
* A controller for a free-moving camera.
|
|
21
26
|
*/
|
|
22
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
|
+
}
|
|
23
45
|
/**
|
|
24
46
|
* Creates a new FreeCameraInput instance.
|
|
25
47
|
* @param keyboard The keyboard input controller to use for camera movement.
|
|
@@ -31,75 +53,107 @@ export class FreeCameraController extends IEntity {
|
|
|
31
53
|
this.keyboard = keyboard;
|
|
32
54
|
this.camera = camera;
|
|
33
55
|
this.tickOrder = TickOrder.INPUT_CONTROLLERS;
|
|
56
|
+
this._spherical = { phi: 0, radius: 1, theta: 0 };
|
|
57
|
+
this.resetMotion$ = new Subject();
|
|
34
58
|
this.options = Object.assign(Object.assign({}, DEFAULT_FREE_CAMERA_CONTROLLER_OPTIONS), options);
|
|
35
59
|
if (options.mouseOptions) {
|
|
36
|
-
this.options.
|
|
60
|
+
this.options.mouseOptions = Object.assign(Object.assign({}, DEFAULT_FREE_CAMERA_CONTROLLER_OPTIONS.mouseOptions), options.mouseOptions);
|
|
37
61
|
}
|
|
38
|
-
this.mouseInput = new MouseInput(options.mouseOptions);
|
|
62
|
+
this.mouseInput = new MouseInput(this.options.mouseOptions);
|
|
39
63
|
this.directionsInput = new DirectionKeyboardInput(keyboard, this.options.keymap);
|
|
40
64
|
}
|
|
65
|
+
reset() {
|
|
66
|
+
this._spherical = Pnt3.toSpherical(Pnt3.rot({ x: 0, y: 0, z: -1 }, this.camera.rotation));
|
|
67
|
+
this.resetMotion$.next();
|
|
68
|
+
}
|
|
41
69
|
onSpawned(world) {
|
|
42
70
|
const _super = Object.create(null, {
|
|
43
71
|
onSpawned: { get: () => super.onSpawned }
|
|
44
72
|
});
|
|
45
73
|
return __awaiter(this, void 0, void 0, function* () {
|
|
46
74
|
yield _super.onSpawned.call(this, world);
|
|
75
|
+
this._spherical = Pnt3.toSpherical(Pnt3.rot({ x: 0, y: 0, z: -1 }, this.camera.rotation));
|
|
47
76
|
// Subscribe to keyboard input for movement controls
|
|
48
|
-
let controls = { direction: {}, rest: [] };
|
|
49
77
|
const keys = ['KeyE', 'KeyQ'];
|
|
50
78
|
if (this.camera.camera.supportsFov) {
|
|
51
79
|
keys.push('KeyZ', 'KeyC');
|
|
52
80
|
}
|
|
53
81
|
keys.push('ShiftLeft');
|
|
54
|
-
this.directionsInput.output
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
.pipe(takeUntil(this._onRemoved$))
|
|
59
|
-
.subscribe((d) => {
|
|
60
|
-
controls.rest = d;
|
|
61
|
-
});
|
|
62
|
-
// Subscribe to mouse input for camera rotation
|
|
63
|
-
let rotationDelta = Pnt2.O;
|
|
64
|
-
let isTouchScreen = MouseInput.isTouchDevice();
|
|
65
|
-
this.mouseInput.delta$
|
|
66
|
-
.pipe(takeUntil(this._onRemoved$), filter(() => isTouchScreen || !this.options.ignoreMouseUnlessPointerLocked || this.mouseInput.isPointerLocked))
|
|
67
|
-
.subscribe(delta => {
|
|
68
|
-
rotationDelta = Pnt2.add(rotationDelta, delta);
|
|
69
|
-
});
|
|
70
|
-
// Setup updating camera position and rotation based on input
|
|
71
|
-
this.camera.tick$.pipe(takeUntil(this._onRemoved$)).subscribe(() => {
|
|
72
|
-
let c = controls;
|
|
73
|
-
if (this.options.ignoreKeyboardUnlessPointerLocked && !this.mouseInput.isPointerLocked) {
|
|
74
|
-
c = { direction: {}, rest: [false, false, false, false, false] };
|
|
82
|
+
let controlsObs = combineLatest([this.directionsInput.output$, ...keys.map(c => this.keyboard.bind(c))]).pipe(takeUntil(this._onRemoved$), map(([direction, ...rest]) => {
|
|
83
|
+
let c = { direction: {}, rest: [] };
|
|
84
|
+
if (!this.options.ignoreKeyboardUnlessPointerLocked || this.mouseInput.isPointerLocked) {
|
|
85
|
+
c = { direction, rest };
|
|
75
86
|
}
|
|
76
|
-
let
|
|
87
|
+
let translate = Object.assign({}, Pnt3.O);
|
|
77
88
|
const [u, d, zo, zi, speedBoost] = c.rest;
|
|
78
89
|
if (c.direction.upDown !== undefined)
|
|
79
|
-
|
|
90
|
+
translate.z = c.direction.upDown ? -1 : 1;
|
|
80
91
|
if (c.direction.leftRight !== undefined)
|
|
81
|
-
|
|
92
|
+
translate.x = c.direction.leftRight ? -1 : 1;
|
|
82
93
|
if (u != d)
|
|
83
|
-
|
|
94
|
+
translate.y = d ? -1 : 1;
|
|
95
|
+
let cameraFovInc = 0;
|
|
84
96
|
if (zo != zi)
|
|
85
|
-
|
|
86
|
-
|
|
97
|
+
cameraFovInc = zo ? 1 : -1;
|
|
98
|
+
translate = Pnt3.norm(translate);
|
|
87
99
|
if (speedBoost) {
|
|
88
|
-
|
|
89
|
-
}
|
|
90
|
-
this.camera.position = Pnt3.add(this.camera.position, Pnt3.rot(Pnt3.scalarMult(Pnt3.norm(translateVector), speed), this.camera.rotation));
|
|
91
|
-
if (rotationDelta.x != 0 || rotationDelta.y != 0) {
|
|
92
|
-
const spherical = Pnt3.toSpherical(Pnt3.rot({ x: 0, y: 0, z: -1 }, this.camera.rotation));
|
|
93
|
-
spherical.theta -= rotationDelta.x / 300;
|
|
94
|
-
spherical.phi += rotationDelta.y / 300;
|
|
95
|
-
spherical.phi = Math.max(0.000001, Math.min(Math.PI - 0.000001, spherical.phi));
|
|
96
|
-
this.camera.rotation = Qtrn.lookAt(this.camera.position, Pnt3.add(this.camera.position, Pnt3.fromSpherical(spherical)));
|
|
97
|
-
rotationDelta = Pnt2.O;
|
|
100
|
+
translate = Pnt3.scalarMult(translate, this.options.cameraBoostMultiplier);
|
|
98
101
|
}
|
|
102
|
+
return [translate, cameraFovInc];
|
|
103
|
+
}));
|
|
104
|
+
if (this.options.cameraMovementElasticity > 0) {
|
|
105
|
+
controlsObs = controlsObs.pipe(ggElastic(this.camera.tick$, this.options.cameraMovementElasticity, ([at, _], [bt, bf], f) => [Pnt3.lerp(at, bt, f), bf], ([at, af], [bt, bf]) => af == bf && Pnt3.dist(at, bt) < 0.001));
|
|
106
|
+
}
|
|
107
|
+
let translateVector = Pnt3.O;
|
|
108
|
+
let cameraFovInc = 0;
|
|
109
|
+
controlsObs.subscribe(([t, f]) => {
|
|
110
|
+
translateVector = t;
|
|
111
|
+
cameraFovInc = f;
|
|
112
|
+
});
|
|
113
|
+
// Subscribe to mouse input for camera rotation
|
|
114
|
+
let isTouchScreen = MouseInput.isTouchDevice();
|
|
115
|
+
let mouseDelta$ = this.mouseInput.delta$.pipe(takeUntil(this._onRemoved$), filter(() => this.active &&
|
|
116
|
+
(isTouchScreen || !this.options.ignoreMouseUnlessPointerLocked || this.mouseInput.isPointerLocked)));
|
|
117
|
+
if (this.options.cameraRotationElasticity > 0) {
|
|
118
|
+
const s$ = new BehaviorSubject(this._spherical);
|
|
119
|
+
mouseDelta$.subscribe(delta => {
|
|
120
|
+
const s = s$.getValue();
|
|
121
|
+
s$.next({
|
|
122
|
+
phi: Math.max(0.000001, Math.min(Math.PI - 0.000001, s.phi + (delta.y * this.options.cameraRotationSensitivity) / 1000)),
|
|
123
|
+
theta: s.theta - (delta.x * this.options.cameraRotationSensitivity) / 1000,
|
|
124
|
+
radius: 1,
|
|
125
|
+
});
|
|
126
|
+
});
|
|
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();
|
|
136
|
+
});
|
|
137
|
+
startElasticMotion();
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
mouseDelta$.subscribe(delta => {
|
|
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));
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
// Setup updating camera position and rotation based on input
|
|
147
|
+
this.camera.tick$
|
|
148
|
+
.pipe(takeUntil(this._onRemoved$), filter(() => this.active))
|
|
149
|
+
.subscribe(([_, delta]) => {
|
|
150
|
+
this.camera.camera.fov += cameraFovInc;
|
|
151
|
+
this.camera.position = Pnt3.add(this.camera.position, Pnt3.rot(Pnt3.scalarMult(translateVector, (this.options.cameraLinearSpeed * delta) / 1000), this.camera.rotation));
|
|
152
|
+
this.camera.rotation = Qtrn.lookAt(this.camera.position, Pnt3.add(this.camera.position, Pnt3.fromSpherical(this._spherical)));
|
|
99
153
|
});
|
|
100
154
|
// start input
|
|
101
|
-
|
|
102
|
-
|
|
155
|
+
this.mouseInput.start();
|
|
156
|
+
this.directionsInput.start();
|
|
103
157
|
});
|
|
104
158
|
}
|
|
105
159
|
onRemoved() {
|
|
@@ -11,7 +11,7 @@ export declare class GgCarKeyboardHandlingController extends IEntity {
|
|
|
11
11
|
car: GgCarEntity | null;
|
|
12
12
|
protected readonly options: GgCarKeyboardControllerOptions;
|
|
13
13
|
readonly tickOrder = TickOrder.INPUT_CONTROLLERS;
|
|
14
|
-
|
|
14
|
+
readonly carHandlingInput: CarKeyboardHandlingController;
|
|
15
15
|
switchingGearsEnabled: boolean;
|
|
16
16
|
constructor(keyboard: KeyboardInput, car: GgCarEntity | null, options?: GgCarKeyboardControllerOptions);
|
|
17
17
|
onSpawned(world: GgWorld<any, any>): Promise<void>;
|
|
@@ -1,18 +1,38 @@
|
|
|
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 = {
|
|
5
|
+
/**
|
|
6
|
+
* Options for configuring mouse input.
|
|
7
|
+
*/
|
|
4
8
|
mouseOptions: Partial<MouseInputOptions>;
|
|
9
|
+
/**
|
|
10
|
+
* Orbiting options. false disables orbiting, sensitivity fields are the speed in radians per 1000px mouse movement. 1 by default
|
|
11
|
+
*/
|
|
5
12
|
orbiting: {
|
|
6
13
|
sensitivityX: number;
|
|
7
14
|
sensitivityY: number;
|
|
8
15
|
} | false;
|
|
16
|
+
/**
|
|
17
|
+
* An elasticity factor for orbiting. 0 by default (no elastic motion)
|
|
18
|
+
*/
|
|
19
|
+
orbitingElasticity: number;
|
|
20
|
+
/**
|
|
21
|
+
* Zooming options. false disables zooming. Enabled by default
|
|
22
|
+
*/
|
|
9
23
|
zooming: {
|
|
10
24
|
sensitivity: number;
|
|
11
25
|
} | false;
|
|
26
|
+
/**
|
|
27
|
+
* Panning options. false disables panning. Enabled by default
|
|
28
|
+
*/
|
|
12
29
|
panning: {
|
|
13
30
|
sensitivityX: number;
|
|
14
31
|
sensitivityY: number;
|
|
15
32
|
} | false;
|
|
33
|
+
/**
|
|
34
|
+
* Dollying options. false disables dollying. Enabled by default
|
|
35
|
+
*/
|
|
16
36
|
dollying: {
|
|
17
37
|
sensitivity: number;
|
|
18
38
|
} | false;
|
|
@@ -21,16 +41,16 @@ export declare class OrbitCameraController extends IEntity {
|
|
|
21
41
|
protected readonly camera: Renderer3dEntity;
|
|
22
42
|
readonly tickOrder = TickOrder.INPUT_CONTROLLERS;
|
|
23
43
|
protected readonly options: OrbitCameraControllerOptions;
|
|
24
|
-
|
|
25
|
-
protected
|
|
44
|
+
readonly mouseInput: MouseInput;
|
|
45
|
+
protected _spherical: MutableSpherical;
|
|
26
46
|
target: Point3;
|
|
27
|
-
get
|
|
28
|
-
set
|
|
29
|
-
get
|
|
30
|
-
set
|
|
31
|
-
|
|
32
|
-
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>;
|
|
33
52
|
constructor(camera: Renderer3dEntity, options?: Partial<OrbitCameraControllerOptions>);
|
|
53
|
+
reset(): void;
|
|
34
54
|
onSpawned(world: GgWorld<any, any>): Promise<void>;
|
|
35
55
|
onRemoved(): Promise<void>;
|
|
36
56
|
}
|