@gg-web-engine/core 0.0.18 → 0.0.20
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/gg-2d-entity.d.ts +5 -3
- package/dist/2d/entities/gg-2d-entity.js +6 -12
- package/dist/2d/entities/gg-positionable-2d-entity.js +2 -1
- package/dist/2d/gg-2d-world.js +2 -4
- package/dist/3d/entities/controllers/animators/camera-3d.animator.js +1 -1
- package/dist/3d/entities/controllers/input/car-keyboard-handling.controller.d.ts +1 -0
- package/dist/3d/entities/controllers/input/car-keyboard-handling.controller.js +20 -6
- package/dist/3d/entities/controllers/input/free-camera.controller.d.ts +8 -0
- package/dist/3d/entities/controllers/input/free-camera.controller.js +22 -11
- package/dist/3d/entities/controllers/input/orbit-camera.controller.d.ts +7 -1
- package/dist/3d/entities/controllers/input/orbit-camera.controller.js +24 -6
- package/dist/3d/entities/gg-3d-entity.d.ts +5 -3
- package/dist/3d/entities/gg-3d-entity.js +6 -12
- package/dist/3d/entities/gg-3d-map-graph.entity.d.ts +4 -1
- package/dist/3d/entities/gg-3d-map-graph.entity.js +6 -6
- package/dist/3d/entities/gg-3d-raycast-vehicle.entity.d.ts +9 -1
- package/dist/3d/entities/gg-3d-raycast-vehicle.entity.js +24 -11
- package/dist/3d/entities/gg-3d-trigger.entity.js +1 -0
- package/dist/3d/entities/gg-positionable-3d-entity.js +3 -2
- package/dist/3d/gg-3d-world.js +3 -5
- package/dist/3d/loader.js +2 -2
- package/dist/base/entities/base-gg-renderer.js +4 -3
- package/dist/base/entities/gg-entity.d.ts +2 -0
- package/dist/base/entities/gg-entity.js +14 -3
- package/dist/base/entities/gg-positionable-entity.d.ts +1 -1
- package/dist/base/entities/inline-controller.js +1 -1
- package/dist/base/entities/mixins/renderable-entity.mixin.d.ts +10 -0
- package/dist/base/entities/mixins/renderable-entity.mixin.js +57 -0
- package/dist/base/gg-world.d.ts +2 -1
- package/dist/base/gg-world.js +4 -3
- package/dist/base/inputs/direction.keyboard-input.d.ts +1 -1
- package/dist/base/inputs/direction.keyboard-input.js +34 -45
- package/dist/base/inputs/input.d.ts +8 -10
- package/dist/base/inputs/input.js +15 -31
- package/dist/base/inputs/keyboard.input.d.ts +14 -2
- package/dist/base/inputs/keyboard.input.js +47 -20
- package/dist/base/inputs/mouse.input.d.ts +3 -3
- package/dist/base/inputs/mouse.input.js +87 -103
- package/dist/base/math/point2.d.ts +8 -0
- package/dist/base/math/point2.js +17 -1
- package/dist/base/math/point3.d.ts +10 -0
- package/dist/base/math/point3.js +21 -1
- package/dist/base/math/quaternion.d.ts +3 -1
- package/dist/base/math/quaternion.js +5 -1
- package/package.json +5 -3
- package/tsconfig.json +1 -1
|
@@ -3,7 +3,9 @@ import { Point2 } from '../../base/models/points';
|
|
|
3
3
|
import { IGg2dBody, IGg2dObject } from '../interfaces';
|
|
4
4
|
import { Gg2dWorld } from '../gg-2d-world';
|
|
5
5
|
import { GGTickOrder } from '../../base/entities/gg-entity';
|
|
6
|
-
|
|
6
|
+
import { RenderableEntityMixin } from '../../base/entities/mixins/renderable-entity.mixin';
|
|
7
|
+
declare const Gg2dEntity_base: import("ts-mixer/dist/types/types").Class<any[], RenderableEntityMixin & GgPositionable2dEntity, typeof RenderableEntityMixin & typeof GgPositionable2dEntity, false>;
|
|
8
|
+
export declare class Gg2dEntity extends Gg2dEntity_base {
|
|
7
9
|
readonly object2D: IGg2dObject | null;
|
|
8
10
|
readonly objectBody: IGg2dBody | null;
|
|
9
11
|
readonly tickOrder = GGTickOrder.OBJECTS_BINDING;
|
|
@@ -13,8 +15,7 @@ export declare class Gg2dEntity extends GgPositionable2dEntity {
|
|
|
13
15
|
set rotation(value: number);
|
|
14
16
|
get scale(): Point2;
|
|
15
17
|
set scale(value: Point2);
|
|
16
|
-
|
|
17
|
-
set visible(value: boolean);
|
|
18
|
+
updateVisibility(): void;
|
|
18
19
|
/**
|
|
19
20
|
* Synchronize physics body transform with entity (and object2d if defined)
|
|
20
21
|
* */
|
|
@@ -24,3 +25,4 @@ export declare class Gg2dEntity extends GgPositionable2dEntity {
|
|
|
24
25
|
onRemoved(): void;
|
|
25
26
|
dispose(): void;
|
|
26
27
|
}
|
|
28
|
+
export {};
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { GgPositionable2dEntity } from './gg-positionable-2d-entity';
|
|
2
2
|
import { GGTickOrder } from '../../base/entities/gg-entity';
|
|
3
|
-
|
|
3
|
+
import { Mixin } from 'ts-mixer';
|
|
4
|
+
import { RenderableEntityMixin } from '../../base/entities/mixins/renderable-entity.mixin';
|
|
5
|
+
export class Gg2dEntity extends Mixin(RenderableEntityMixin, GgPositionable2dEntity) {
|
|
4
6
|
constructor(object2D, objectBody) {
|
|
5
7
|
super();
|
|
6
8
|
this.object2D = object2D;
|
|
@@ -60,19 +62,11 @@ export class Gg2dEntity extends GgPositionable2dEntity {
|
|
|
60
62
|
}
|
|
61
63
|
super.scale = value;
|
|
62
64
|
}
|
|
63
|
-
|
|
64
|
-
var _a;
|
|
65
|
-
return !!((_a = this.object2D) === null || _a === void 0 ? void 0 : _a.visible);
|
|
66
|
-
}
|
|
67
|
-
set visible(value) {
|
|
65
|
+
updateVisibility() {
|
|
68
66
|
if (this.object2D) {
|
|
69
|
-
this.object2D.visible =
|
|
70
|
-
}
|
|
71
|
-
for (const entity of this._children) {
|
|
72
|
-
if (entity instanceof Gg2dEntity) {
|
|
73
|
-
entity.visible = value;
|
|
74
|
-
}
|
|
67
|
+
this.object2D.visible = this.worldVisible;
|
|
75
68
|
}
|
|
69
|
+
super.updateVisibility();
|
|
76
70
|
}
|
|
77
71
|
/**
|
|
78
72
|
* Synchronize physics body transform with entity (and object2d if defined)
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { GgPositionableEntity } from '../../base/entities/gg-positionable-entity';
|
|
2
|
+
import { Pnt2 } from '../../base/math/point2';
|
|
2
3
|
export class GgPositionable2dEntity extends GgPositionableEntity {
|
|
3
4
|
getDefaultPosition() {
|
|
4
|
-
return
|
|
5
|
+
return Pnt2.O;
|
|
5
6
|
}
|
|
6
7
|
getDefaultRotation() {
|
|
7
8
|
return 0;
|
package/dist/2d/gg-2d-world.js
CHANGED
|
@@ -9,6 +9,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
9
9
|
};
|
|
10
10
|
import { GgWorld } from '../base/gg-world';
|
|
11
11
|
import { Gg2dEntity } from './entities/gg-2d-entity';
|
|
12
|
+
import { Pnt2 } from '../base/math/point2';
|
|
12
13
|
export class Gg2dWorld extends GgWorld {
|
|
13
14
|
constructor(visualScene, physicsWorld, consoleEnabled = false) {
|
|
14
15
|
super(visualScene, physicsWorld, consoleEnabled);
|
|
@@ -28,10 +29,7 @@ export class Gg2dWorld extends GgWorld {
|
|
|
28
29
|
'{x: 0, y: value}, 2 arguments set the whole vector. Default value is "9.82" or "0 9.82"');
|
|
29
30
|
}
|
|
30
31
|
}
|
|
31
|
-
addPrimitiveRigidBody(descr, position = {
|
|
32
|
-
x: 0,
|
|
33
|
-
y: 0,
|
|
34
|
-
}, rotation = 0) {
|
|
32
|
+
addPrimitiveRigidBody(descr, position = Pnt2.O, rotation = 0) {
|
|
35
33
|
const entity = new Gg2dEntity(this.visualScene.factory.createPrimitive(descr.shape), this.physicsWorld.factory.createRigidBody(descr));
|
|
36
34
|
entity.position = position;
|
|
37
35
|
entity.rotation = rotation;
|
|
@@ -3,7 +3,7 @@ import { Pnt3 } from '../../../../base/math/point3';
|
|
|
3
3
|
import { Qtrn } from '../../../../base/math/quaternion';
|
|
4
4
|
import { takeUntil } from 'rxjs';
|
|
5
5
|
import { lerpNumber } from '../../../../base/math/numbers';
|
|
6
|
-
const defaultUp =
|
|
6
|
+
const defaultUp = Pnt3.Z;
|
|
7
7
|
const defaultFov = 65;
|
|
8
8
|
export class Camera3dAnimator extends AnimationMixer {
|
|
9
9
|
constructor(entity, _animationFunction) {
|
|
@@ -7,6 +7,7 @@ import { GgWorld } from '../../../../base/gg-world';
|
|
|
7
7
|
export declare type CarKeyboardControllerOptions = {
|
|
8
8
|
keymap: DirectionKeyboardKeymap;
|
|
9
9
|
gearUpDownKeys: [string, string];
|
|
10
|
+
handbrakeKey: string;
|
|
10
11
|
};
|
|
11
12
|
export declare class CarKeyboardHandlingController extends GgEntity {
|
|
12
13
|
protected readonly keyboard: KeyboardInput;
|
|
@@ -13,10 +13,14 @@ import { DirectionKeyboardInput, } from '../../../../base/inputs/direction.keybo
|
|
|
13
13
|
import { GgEntity, GGTickOrder } from '../../../../base/entities/gg-entity';
|
|
14
14
|
// TODO pass as settings
|
|
15
15
|
// TODO smooth y?
|
|
16
|
-
const TICKER_INTERVAL = 16;
|
|
16
|
+
const TICKER_INTERVAL = 16; // TODO when refactored, reflect in CarKeyboardHandlingController test
|
|
17
17
|
const TICKER_MAX_STEPS = 10;
|
|
18
18
|
export class CarKeyboardHandlingController extends GgEntity {
|
|
19
|
-
constructor(keyboard, car, options = {
|
|
19
|
+
constructor(keyboard, car, options = {
|
|
20
|
+
keymap: 'arrows',
|
|
21
|
+
gearUpDownKeys: ['KeyA', 'KeyZ'],
|
|
22
|
+
handbrakeKey: 'Space',
|
|
23
|
+
}) {
|
|
20
24
|
super();
|
|
21
25
|
this.keyboard = keyboard;
|
|
22
26
|
this.car = car;
|
|
@@ -28,7 +32,7 @@ export class CarKeyboardHandlingController extends GgEntity {
|
|
|
28
32
|
this.y$ = new BehaviorSubject(0);
|
|
29
33
|
this.lastX = 0;
|
|
30
34
|
this.switchingGearsEnabled = true;
|
|
31
|
-
this.pairTickerPipe = pipe(
|
|
35
|
+
this.pairTickerPipe = pipe(pairwise(), map(([beforeValue, afterValue]) => [this.lastX, afterValue]), switchMap(([beforeValue, afterValue]) => interval(TICKER_INTERVAL).pipe(startWith(-1), take(TICKER_MAX_STEPS), map(count => count + 2), map(count => beforeValue * ((TICKER_MAX_STEPS - count) / TICKER_MAX_STEPS) + afterValue * (count / TICKER_MAX_STEPS)), tap(x => {
|
|
32
36
|
this.lastX = x;
|
|
33
37
|
}))));
|
|
34
38
|
this.directionsInput = new DirectionKeyboardInput(keyboard, options.keymap);
|
|
@@ -61,6 +65,14 @@ export class CarKeyboardHandlingController extends GgEntity {
|
|
|
61
65
|
}
|
|
62
66
|
}
|
|
63
67
|
});
|
|
68
|
+
this.keyboard
|
|
69
|
+
.bind(this.options.handbrakeKey)
|
|
70
|
+
.pipe(takeUntil(this._onRemoved$))
|
|
71
|
+
.subscribe(isKeyDown => {
|
|
72
|
+
if (this.car) {
|
|
73
|
+
this.car.handBrake = isKeyDown;
|
|
74
|
+
}
|
|
75
|
+
});
|
|
64
76
|
this.directionsInput.output$.pipe(takeUntil(this._onRemoved$)).subscribe(d => {
|
|
65
77
|
moveDirection = d;
|
|
66
78
|
});
|
|
@@ -78,9 +90,11 @@ export class CarKeyboardHandlingController extends GgEntity {
|
|
|
78
90
|
this.y$.next(y);
|
|
79
91
|
});
|
|
80
92
|
combineLatest([
|
|
81
|
-
this.x$.pipe(takeUntil(this._onRemoved$), distinctUntilChanged(), this.pairTickerPipe),
|
|
82
|
-
this.y$.pipe(takeUntil(this._onRemoved$), distinctUntilChanged()),
|
|
83
|
-
])
|
|
93
|
+
this.x$.pipe(takeUntil(this._onRemoved$), distinctUntilChanged(), startWith(0), this.pairTickerPipe),
|
|
94
|
+
this.y$.pipe(takeUntil(this._onRemoved$), distinctUntilChanged(), startWith(0)),
|
|
95
|
+
])
|
|
96
|
+
.pipe(takeUntil(this._onRemoved$))
|
|
97
|
+
.subscribe(([x, y]) => {
|
|
84
98
|
if (this.car) {
|
|
85
99
|
this.car.setXAxisControlValue(x);
|
|
86
100
|
this.car.setYAxisControlValue(y);
|
|
@@ -21,6 +21,14 @@ export declare type FreeCameraControllerOptions = {
|
|
|
21
21
|
*/
|
|
22
22
|
speed: number;
|
|
23
23
|
};
|
|
24
|
+
/**
|
|
25
|
+
* Flag to ignore cursor movement if pointer was not locked. By default false
|
|
26
|
+
*/
|
|
27
|
+
ignoreMouseUnlessPointerLocked: boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Flag to ignore keyboard events if pointer was not locked. By default false
|
|
30
|
+
*/
|
|
31
|
+
ignoreKeyboardUnlessPointerLocked: boolean;
|
|
24
32
|
/**
|
|
25
33
|
* Options for configuring mouse input.
|
|
26
34
|
*/
|
|
@@ -28,6 +28,8 @@ export class FreeCameraController extends GgEntity {
|
|
|
28
28
|
keymap: 'wasd',
|
|
29
29
|
movementOptions: { speed: 0.5 },
|
|
30
30
|
mouseOptions: {},
|
|
31
|
+
ignoreMouseUnlessPointerLocked: false,
|
|
32
|
+
ignoreKeyboardUnlessPointerLocked: false,
|
|
31
33
|
}) {
|
|
32
34
|
super();
|
|
33
35
|
this.keyboard = keyboard;
|
|
@@ -49,6 +51,7 @@ export class FreeCameraController extends GgEntity {
|
|
|
49
51
|
if (this.camera.object3D.supportsFov) {
|
|
50
52
|
keys.push('KeyZ', 'KeyC');
|
|
51
53
|
}
|
|
54
|
+
keys.push('ShiftLeft');
|
|
52
55
|
this.directionsInput.output$.pipe(takeUntil(this._onRemoved$)).subscribe(d => {
|
|
53
56
|
controls.direction = d;
|
|
54
57
|
});
|
|
@@ -58,33 +61,41 @@ export class FreeCameraController extends GgEntity {
|
|
|
58
61
|
controls.rest = d;
|
|
59
62
|
});
|
|
60
63
|
// Subscribe to mouse input for camera rotation
|
|
61
|
-
let rotationDelta =
|
|
64
|
+
let rotationDelta = Pnt2.O;
|
|
62
65
|
let isTouchScreen = MouseInput.isTouchDevice();
|
|
63
66
|
this.mouseInput.delta$
|
|
64
|
-
.pipe(takeUntil(this._onRemoved$), filter(() => isTouchScreen || this.mouseInput.isPointerLocked))
|
|
67
|
+
.pipe(takeUntil(this._onRemoved$), filter(() => isTouchScreen || !this.options.ignoreMouseUnlessPointerLocked || this.mouseInput.isPointerLocked))
|
|
65
68
|
.subscribe(delta => {
|
|
66
69
|
rotationDelta = Pnt2.add(rotationDelta, delta);
|
|
67
70
|
});
|
|
68
71
|
// Setup updating camera position and rotation based on input
|
|
69
72
|
this.camera.tick$.pipe(takeUntil(this._onRemoved$)).subscribe(() => {
|
|
70
|
-
let
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
73
|
+
let c = controls;
|
|
74
|
+
if (this.options.ignoreKeyboardUnlessPointerLocked && !this.mouseInput.isPointerLocked) {
|
|
75
|
+
c = { direction: {}, rest: [false, false, false, false, false] };
|
|
76
|
+
}
|
|
77
|
+
let translateVector = Object.assign({}, Pnt3.O);
|
|
78
|
+
const [u, d, zo, zi, speedBoost] = c.rest;
|
|
79
|
+
if (c.direction.upDown !== undefined)
|
|
80
|
+
translateVector.z = c.direction.upDown ? -1 : 1;
|
|
81
|
+
if (c.direction.leftRight !== undefined)
|
|
82
|
+
translateVector.x = c.direction.leftRight ? -1 : 1;
|
|
76
83
|
if (u != d)
|
|
77
84
|
translateVector.y = d ? -1 : 1;
|
|
78
85
|
if (zo != zi)
|
|
79
86
|
this.camera.object3D.fov += zo ? 1 : -1;
|
|
80
|
-
|
|
87
|
+
let speed = this.options.movementOptions.speed;
|
|
88
|
+
if (speedBoost) {
|
|
89
|
+
speed *= 2.5;
|
|
90
|
+
}
|
|
91
|
+
this.camera.position = Pnt3.add(this.camera.position, Pnt3.rot(Pnt3.scalarMult(Pnt3.norm(translateVector), speed), this.camera.rotation));
|
|
81
92
|
if (rotationDelta.x != 0 || rotationDelta.y != 0) {
|
|
82
93
|
const spherical = Pnt3.toSpherical(Pnt3.rot({ x: 0, y: 0, z: -1 }, this.camera.rotation));
|
|
83
94
|
spherical.theta -= rotationDelta.x / 300;
|
|
84
95
|
spherical.phi += rotationDelta.y / 300;
|
|
85
96
|
spherical.phi = Math.max(0.000001, Math.min(Math.PI - 0.000001, spherical.phi));
|
|
86
|
-
this.camera.rotation = Qtrn.lookAt(this.camera.position, Pnt3.add(this.camera.position, Pnt3.fromSpherical(spherical))
|
|
87
|
-
rotationDelta =
|
|
97
|
+
this.camera.rotation = Qtrn.lookAt(this.camera.position, Pnt3.add(this.camera.position, Pnt3.fromSpherical(spherical)));
|
|
98
|
+
rotationDelta = Pnt2.O;
|
|
88
99
|
}
|
|
89
100
|
});
|
|
90
101
|
// start input
|
|
@@ -5,7 +5,6 @@ import { GgWorld } from '../../../../base/gg-world';
|
|
|
5
5
|
import { MutableSpherical, Point3 } from '../../../../base/models/points';
|
|
6
6
|
export declare type OrbitCameraControllerOptions = {
|
|
7
7
|
mouseOptions: Partial<MouseInputOptions>;
|
|
8
|
-
target: Point3;
|
|
9
8
|
orbiting: {
|
|
10
9
|
sensitivityX: number;
|
|
11
10
|
sensitivityY: number;
|
|
@@ -27,6 +26,13 @@ export declare class OrbitCameraController extends GgEntity {
|
|
|
27
26
|
protected readonly options: OrbitCameraControllerOptions;
|
|
28
27
|
protected readonly mouseInput: MouseInput;
|
|
29
28
|
protected spherical: MutableSpherical;
|
|
29
|
+
target: Point3;
|
|
30
|
+
get radius(): number;
|
|
31
|
+
set radius(value: number);
|
|
32
|
+
get phi(): number;
|
|
33
|
+
set phi(value: number);
|
|
34
|
+
get theta(): number;
|
|
35
|
+
set theta(value: number);
|
|
30
36
|
constructor(camera: Gg3dCameraEntity, options?: Partial<OrbitCameraControllerOptions>);
|
|
31
37
|
onSpawned(world: GgWorld<any, any>): Promise<void>;
|
|
32
38
|
onRemoved(): Promise<void>;
|
|
@@ -15,7 +15,6 @@ import { Pnt3 } from '../../../../base/math/point3';
|
|
|
15
15
|
import { map } from 'rxjs/operators';
|
|
16
16
|
const DEFAULT_OPTIONS = {
|
|
17
17
|
mouseOptions: {},
|
|
18
|
-
target: { x: 0, y: 0, z: 0 },
|
|
19
18
|
orbiting: { sensitivityX: 1, sensitivityY: 1 },
|
|
20
19
|
zooming: { sensitivity: 1 },
|
|
21
20
|
panning: { sensitivityX: 1, sensitivityY: 1 },
|
|
@@ -26,17 +25,36 @@ export class OrbitCameraController extends GgEntity {
|
|
|
26
25
|
super();
|
|
27
26
|
this.camera = camera;
|
|
28
27
|
this.tickOrder = GGTickOrder.INPUT_CONTROLLERS;
|
|
29
|
-
this.spherical = { phi: 0, radius:
|
|
28
|
+
this.spherical = { phi: 0, radius: 10, theta: 0 };
|
|
29
|
+
this.target = Pnt3.O;
|
|
30
30
|
this.options = Object.assign(Object.assign({}, DEFAULT_OPTIONS), options);
|
|
31
31
|
this.mouseInput = new MouseInput(this.options.mouseOptions);
|
|
32
32
|
}
|
|
33
|
+
get radius() {
|
|
34
|
+
return this.spherical.radius;
|
|
35
|
+
}
|
|
36
|
+
set radius(value) {
|
|
37
|
+
this.spherical.radius = value;
|
|
38
|
+
}
|
|
39
|
+
get phi() {
|
|
40
|
+
return this.spherical.phi;
|
|
41
|
+
}
|
|
42
|
+
set phi(value) {
|
|
43
|
+
this.spherical.phi = Math.max(0.000001, Math.min(Math.PI - 0.000001, value));
|
|
44
|
+
}
|
|
45
|
+
get theta() {
|
|
46
|
+
return this.spherical.theta;
|
|
47
|
+
}
|
|
48
|
+
set theta(value) {
|
|
49
|
+
this.spherical.theta = value;
|
|
50
|
+
}
|
|
33
51
|
onSpawned(world) {
|
|
34
52
|
const _super = Object.create(null, {
|
|
35
53
|
onSpawned: { get: () => super.onSpawned }
|
|
36
54
|
});
|
|
37
55
|
return __awaiter(this, void 0, void 0, function* () {
|
|
38
56
|
yield _super.onSpawned.call(this, world);
|
|
39
|
-
this.spherical = Pnt3.toSpherical(Pnt3.sub(this.camera.position, this.
|
|
57
|
+
this.spherical = Pnt3.toSpherical(Pnt3.sub(this.camera.position, this.target));
|
|
40
58
|
if (this.options.orbiting) {
|
|
41
59
|
this.mouseInput.delta$
|
|
42
60
|
.pipe(takeUntil(this._onRemoved$), filter(() => this.mouseInput.state == MouseInputState.DRAG))
|
|
@@ -61,7 +79,7 @@ export class OrbitCameraController extends GgEntity {
|
|
|
61
79
|
z: 0,
|
|
62
80
|
}, Math.PI / 2);
|
|
63
81
|
const viewRight = Pnt3.rotAround(targetCameraVector, Pnt3.norm(viewUp), Math.PI / 2);
|
|
64
|
-
this.
|
|
82
|
+
this.target = Pnt3.add(this.target, Pnt3.add(Pnt3.scalarMult(viewUp, (-this.options.panning.sensitivityY * delta.y) / 1000), Pnt3.scalarMult(viewRight, (this.options.panning.sensitivityX * delta.x) / 1000)));
|
|
65
83
|
};
|
|
66
84
|
if (this.options.panning) {
|
|
67
85
|
this.mouseInput.delta$
|
|
@@ -93,8 +111,8 @@ export class OrbitCameraController extends GgEntity {
|
|
|
93
111
|
this.camera.tick$
|
|
94
112
|
.pipe(takeUntil(this._onRemoved$), map(() => this.spherical))
|
|
95
113
|
.subscribe(spherical => {
|
|
96
|
-
this.camera.position = Pnt3.add(this.
|
|
97
|
-
this.camera.rotation = Qtrn.lookAt(this.camera.position, this.
|
|
114
|
+
this.camera.position = Pnt3.add(this.target, Pnt3.fromSpherical(spherical));
|
|
115
|
+
this.camera.rotation = Qtrn.lookAt(this.camera.position, this.target);
|
|
98
116
|
});
|
|
99
117
|
// start input
|
|
100
118
|
yield this.mouseInput.start();
|
|
@@ -3,7 +3,9 @@ import { Point3, Point4 } from '../../base/models/points';
|
|
|
3
3
|
import { Gg3dWorld } from '../gg-3d-world';
|
|
4
4
|
import { IGg3dBody, IGg3dObject } from '../interfaces';
|
|
5
5
|
import { GGTickOrder } from '../../base/entities/gg-entity';
|
|
6
|
-
|
|
6
|
+
import { RenderableEntityMixin } from '../../base/entities/mixins/renderable-entity.mixin';
|
|
7
|
+
declare const Gg3dEntity_base: import("ts-mixer/dist/types/types").Class<any[], RenderableEntityMixin & GgPositionable3dEntity, typeof RenderableEntityMixin & typeof GgPositionable3dEntity, false>;
|
|
8
|
+
export declare class Gg3dEntity extends Gg3dEntity_base {
|
|
7
9
|
readonly object3D: IGg3dObject | null;
|
|
8
10
|
readonly objectBody: IGg3dBody | null;
|
|
9
11
|
readonly tickOrder = GGTickOrder.OBJECTS_BINDING;
|
|
@@ -13,8 +15,7 @@ export declare class Gg3dEntity extends GgPositionable3dEntity {
|
|
|
13
15
|
set rotation(value: Point4);
|
|
14
16
|
get scale(): Point3;
|
|
15
17
|
set scale(value: Point3);
|
|
16
|
-
|
|
17
|
-
set visible(value: boolean);
|
|
18
|
+
updateVisibility(): void;
|
|
18
19
|
/**
|
|
19
20
|
* Synchronize physics body transform with entity (and mesh if defined)
|
|
20
21
|
* */
|
|
@@ -24,3 +25,4 @@ export declare class Gg3dEntity extends GgPositionable3dEntity {
|
|
|
24
25
|
onRemoved(): void;
|
|
25
26
|
dispose(): void;
|
|
26
27
|
}
|
|
28
|
+
export {};
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { GgPositionable3dEntity } from './gg-positionable-3d-entity';
|
|
2
2
|
import { GGTickOrder } from '../../base/entities/gg-entity';
|
|
3
|
-
|
|
3
|
+
import { Mixin } from 'ts-mixer';
|
|
4
|
+
import { RenderableEntityMixin } from '../../base/entities/mixins/renderable-entity.mixin';
|
|
5
|
+
export class Gg3dEntity extends Mixin(RenderableEntityMixin, GgPositionable3dEntity) {
|
|
4
6
|
constructor(object3D, objectBody = null) {
|
|
5
7
|
super();
|
|
6
8
|
this.object3D = object3D;
|
|
@@ -60,19 +62,11 @@ export class Gg3dEntity extends GgPositionable3dEntity {
|
|
|
60
62
|
}
|
|
61
63
|
super.scale = value;
|
|
62
64
|
}
|
|
63
|
-
|
|
64
|
-
var _a;
|
|
65
|
-
return !!((_a = this.object3D) === null || _a === void 0 ? void 0 : _a.visible);
|
|
66
|
-
}
|
|
67
|
-
set visible(value) {
|
|
65
|
+
updateVisibility() {
|
|
68
66
|
if (this.object3D) {
|
|
69
|
-
this.object3D.visible =
|
|
70
|
-
}
|
|
71
|
-
for (const entity of this._children) {
|
|
72
|
-
if (entity instanceof Gg3dEntity) {
|
|
73
|
-
entity.visible = value;
|
|
74
|
-
}
|
|
67
|
+
this.object3D.visible = this.worldVisible;
|
|
75
68
|
}
|
|
69
|
+
super.updateVisibility();
|
|
76
70
|
}
|
|
77
71
|
/**
|
|
78
72
|
* Synchronize physics body transform with entity (and mesh if defined)
|
|
@@ -6,6 +6,7 @@ import { GgPositionable3dEntity } from './gg-positionable-3d-entity';
|
|
|
6
6
|
import { Gg3dWorld } from '../gg-3d-world';
|
|
7
7
|
import { Gg3dEntity } from './gg-3d-entity';
|
|
8
8
|
import { LoadOptions, LoadResultWithProps } from '../loader';
|
|
9
|
+
import { RenderableEntityMixin } from '../../base/entities/mixins/renderable-entity.mixin';
|
|
9
10
|
export declare type MapGraphNodeType = {
|
|
10
11
|
path: string;
|
|
11
12
|
position: Point3;
|
|
@@ -38,7 +39,8 @@ export declare type Gg3dMapGraphEntityOptions = {
|
|
|
38
39
|
loadDepth: number;
|
|
39
40
|
inertia: number;
|
|
40
41
|
};
|
|
41
|
-
|
|
42
|
+
declare const Gg3dMapGraphEntity_base: import("ts-mixer/dist/types/types").Class<any[], RenderableEntityMixin & GgEntity, typeof RenderableEntityMixin & typeof GgEntity, false>;
|
|
43
|
+
export declare class Gg3dMapGraphEntity extends Gg3dMapGraphEntity_base {
|
|
42
44
|
readonly mapGraph: MapGraph;
|
|
43
45
|
readonly tickOrder = GGTickOrder.POST_RENDERING;
|
|
44
46
|
readonly loaderCursorEntity$: BehaviorSubject<GgPositionable3dEntity | null>;
|
|
@@ -65,3 +67,4 @@ export declare class Gg3dMapGraphEntity extends GgEntity {
|
|
|
65
67
|
protected loadChunk(node: MapGraphNodeType): Promise<[Gg3dEntity[], LoadResultWithProps]>;
|
|
66
68
|
protected disposeChunk(node: MapGraphNodeType): void;
|
|
67
69
|
}
|
|
70
|
+
export {};
|
|
@@ -11,6 +11,9 @@ import { BehaviorSubject, NEVER, startWith, Subject, switchMap } from 'rxjs';
|
|
|
11
11
|
import { distinctUntilChanged, map, tap, throttleTime } from 'rxjs/operators';
|
|
12
12
|
import { Graph } from '../../base/data-structures/graph';
|
|
13
13
|
import { GgEntity, GGTickOrder } from '../../base/entities/gg-entity';
|
|
14
|
+
import { Qtrn } from '../../base/math/quaternion';
|
|
15
|
+
import { RenderableEntityMixin } from '../../base/entities/mixins/renderable-entity.mixin';
|
|
16
|
+
import { Mixin } from 'ts-mixer';
|
|
14
17
|
export class MapGraph extends Graph {
|
|
15
18
|
/**
|
|
16
19
|
* Creates a new MapGraph instance from an array of elements, where each element in the array is a node in the graph.
|
|
@@ -80,7 +83,7 @@ const defaultOptions = {
|
|
|
80
83
|
loadDepth: 5,
|
|
81
84
|
inertia: 0,
|
|
82
85
|
};
|
|
83
|
-
export class Gg3dMapGraphEntity extends GgEntity {
|
|
86
|
+
export class Gg3dMapGraphEntity extends Mixin(RenderableEntityMixin, GgEntity) {
|
|
84
87
|
constructor(mapGraph, options = {}) {
|
|
85
88
|
super();
|
|
86
89
|
this.mapGraph = mapGraph;
|
|
@@ -148,7 +151,7 @@ export class Gg3dMapGraphEntity extends GgEntity {
|
|
|
148
151
|
}
|
|
149
152
|
loadChunk(node) {
|
|
150
153
|
return __awaiter(this, void 0, void 0, function* () {
|
|
151
|
-
const loaded = yield this.world.loader.loadGgGlb(node.path, Object.assign({ position: node.position, rotation: node.rotation ||
|
|
154
|
+
const loaded = yield this.world.loader.loadGgGlb(node.path, Object.assign({ position: node.position, rotation: node.rotation || Qtrn.O }, node.loadOptions));
|
|
152
155
|
const entities = [
|
|
153
156
|
...loaded.entities,
|
|
154
157
|
...(loaded.props || [])
|
|
@@ -160,10 +163,7 @@ export class Gg3dMapGraphEntity extends GgEntity {
|
|
|
160
163
|
];
|
|
161
164
|
this.loaded.set(node, entities);
|
|
162
165
|
this.addChildren(...entities);
|
|
163
|
-
this._chunkLoaded$.next([
|
|
164
|
-
loaded,
|
|
165
|
-
{ position: node.position, rotation: node.rotation || { x: 0, y: 0, z: 0, w: 1 } },
|
|
166
|
-
]);
|
|
166
|
+
this._chunkLoaded$.next([loaded, { position: node.position, rotation: node.rotation || Qtrn.O }]);
|
|
167
167
|
return [entities, loaded];
|
|
168
168
|
});
|
|
169
169
|
}
|
|
@@ -37,6 +37,11 @@ export declare type CarProperties = {
|
|
|
37
37
|
maxRpmIncreasePerSecond: number;
|
|
38
38
|
maxRpmDecreasePerSecond: number;
|
|
39
39
|
};
|
|
40
|
+
brake: {
|
|
41
|
+
frontAxleForce: number;
|
|
42
|
+
rearAxleForce: number;
|
|
43
|
+
handbrakeForce: number;
|
|
44
|
+
};
|
|
40
45
|
transmission: {
|
|
41
46
|
isAuto: boolean;
|
|
42
47
|
reverseGearRatio: number;
|
|
@@ -57,6 +62,7 @@ export declare class Gg3dRaycastVehicleEntity extends Gg3dEntity {
|
|
|
57
62
|
protected readonly wheelLocalRotation: (Point4 | null)[];
|
|
58
63
|
protected readonly wheelLocalTranslation: Point3[];
|
|
59
64
|
protected readonly frontWheelsIndices: number[];
|
|
65
|
+
protected readonly rearWheelsIndices: number[];
|
|
60
66
|
protected readonly tractionWheelIndices: number[];
|
|
61
67
|
readonly tractionWheelRadius: number;
|
|
62
68
|
protected get dynamicTractionWheelRadius(): number;
|
|
@@ -71,7 +77,6 @@ export declare class Gg3dRaycastVehicleEntity extends Gg3dEntity {
|
|
|
71
77
|
get engineRpm(): number;
|
|
72
78
|
protected get tractionForce(): number;
|
|
73
79
|
private readonly _maxSteerVal;
|
|
74
|
-
private readonly brakingForce;
|
|
75
80
|
get maxSteerVal(): number;
|
|
76
81
|
private getMaxStableSteerVal;
|
|
77
82
|
private _tailLightsOn;
|
|
@@ -84,6 +89,9 @@ export declare class Gg3dRaycastVehicleEntity extends Gg3dEntity {
|
|
|
84
89
|
protected brake$: BehaviorSubject<number>;
|
|
85
90
|
protected get brake(): number;
|
|
86
91
|
protected set brake(value: number);
|
|
92
|
+
protected handBrake$: BehaviorSubject<boolean>;
|
|
93
|
+
get handBrake(): boolean;
|
|
94
|
+
set handBrake(value: boolean);
|
|
87
95
|
private _gear;
|
|
88
96
|
private _gear$;
|
|
89
97
|
get gear(): number;
|
|
@@ -17,16 +17,17 @@ export class Gg3dRaycastVehicleEntity extends Gg3dEntity {
|
|
|
17
17
|
this.wheelLocalRotation = [];
|
|
18
18
|
this.wheelLocalTranslation = [];
|
|
19
19
|
this.frontWheelsIndices = [];
|
|
20
|
+
this.rearWheelsIndices = [];
|
|
20
21
|
this.tractionWheelIndices = [];
|
|
21
22
|
this._rpm$ = new BehaviorSubject(this.carProperties.engine.minRpm);
|
|
22
23
|
// TODO should be parameters
|
|
23
24
|
this._maxSteerVal = 0.35;
|
|
24
|
-
this.brakingForce = 300;
|
|
25
25
|
this._tailLightsOn = false;
|
|
26
26
|
// 0..1
|
|
27
27
|
this._acceleration$ = new BehaviorSubject(0);
|
|
28
28
|
// 0..1
|
|
29
29
|
this.brake$ = new BehaviorSubject(0);
|
|
30
|
+
this.handBrake$ = new BehaviorSubject(false);
|
|
30
31
|
this._gear = 0;
|
|
31
32
|
this._gear$ = new BehaviorSubject(0);
|
|
32
33
|
this._steeringValue = 0;
|
|
@@ -34,6 +35,9 @@ export class Gg3dRaycastVehicleEntity extends Gg3dEntity {
|
|
|
34
35
|
if (x.isFront) {
|
|
35
36
|
this.frontWheelsIndices.push(i);
|
|
36
37
|
}
|
|
38
|
+
else {
|
|
39
|
+
this.rearWheelsIndices.push(i);
|
|
40
|
+
}
|
|
37
41
|
if (x.isFront && this.carProperties.typeOfDrive != 'RWD') {
|
|
38
42
|
this.tractionWheelIndices.push(i);
|
|
39
43
|
}
|
|
@@ -57,8 +61,8 @@ export class Gg3dRaycastVehicleEntity extends Gg3dEntity {
|
|
|
57
61
|
}
|
|
58
62
|
const entity = options.wheelObject || this.wheelObject.clone();
|
|
59
63
|
const localTranslation = { x: options.tyre_width * (options.isLeft ? 1 : -1), y: 0, z: 0 };
|
|
60
|
-
const boundingBox = Box.expandByPoint(entity.getBoundings(),
|
|
61
|
-
const scale = {
|
|
64
|
+
const boundingBox = Box.expandByPoint(entity.getBoundings(), Pnt3.O);
|
|
65
|
+
const scale = Object.assign({}, Pnt3.O);
|
|
62
66
|
for (const dir of ['x', 'y', 'z']) {
|
|
63
67
|
const wheelObjectDirection = options.wheelObjectDirection || this.wheelObjectDirection;
|
|
64
68
|
const isNormal = wheelObjectDirection.includes(dir);
|
|
@@ -202,6 +206,12 @@ export class Gg3dRaycastVehicleEntity extends Gg3dEntity {
|
|
|
202
206
|
set brake(value) {
|
|
203
207
|
this.brake$.next(value);
|
|
204
208
|
}
|
|
209
|
+
get handBrake() {
|
|
210
|
+
return this.handBrake$.getValue();
|
|
211
|
+
}
|
|
212
|
+
set handBrake(value) {
|
|
213
|
+
this.handBrake$.next(value);
|
|
214
|
+
}
|
|
205
215
|
get gear() {
|
|
206
216
|
return this._gear;
|
|
207
217
|
}
|
|
@@ -232,8 +242,8 @@ export class Gg3dRaycastVehicleEntity extends Gg3dEntity {
|
|
|
232
242
|
this.updateEngine(delta);
|
|
233
243
|
if (this.isTouchingGround) {
|
|
234
244
|
// TODO 1 - R (1000 rpm) quick switch with acceleration pedal should have the same speed as without acceleration pedal
|
|
235
|
-
let force;
|
|
236
|
-
let
|
|
245
|
+
let force = 0;
|
|
246
|
+
let brake = this.brake;
|
|
237
247
|
const calculatedRpm = this.calculateRpmFromCarSpeed();
|
|
238
248
|
if (this.gear !== 0 && calculatedRpm > this.carProperties.engine.maxRpm) {
|
|
239
249
|
// engine brake, this is related to clutch, better clutch condition - bigger force
|
|
@@ -246,14 +256,17 @@ export class Gg3dRaycastVehicleEntity extends Gg3dEntity {
|
|
|
246
256
|
: 0.5 * (this.carProperties.engine.minRpm - calculatedRpm) * (this.gear > 0 ? 1 : -1); // released, use engine brake
|
|
247
257
|
// this functionality makes car stay still (parking gear) when speed is low
|
|
248
258
|
const speedThreshold = 3;
|
|
249
|
-
if (Math.abs(this.getSpeed()) < speedThreshold && (this.gear == 0 || this.acceleration
|
|
250
|
-
|
|
259
|
+
if (Math.abs(this.getSpeed()) < speedThreshold && (this.gear == 0 || this.acceleration <= 0)) {
|
|
260
|
+
brake = Math.max(brake, (0.3 * (speedThreshold - this.getSpeed())) / speedThreshold);
|
|
251
261
|
force = 0;
|
|
252
262
|
}
|
|
253
263
|
}
|
|
254
|
-
|
|
255
|
-
this.
|
|
256
|
-
this.
|
|
264
|
+
this.tractionWheelIndices.forEach(index => this.chassisBody.applyEngineForce(index, force));
|
|
265
|
+
this.frontWheelsIndices.forEach(index => this.chassisBody.applyBrake(index, brake * this.carProperties.brake.frontAxleForce));
|
|
266
|
+
this.rearWheelsIndices.forEach(index => this.chassisBody.applyBrake(index, brake * this.carProperties.brake.rearAxleForce));
|
|
267
|
+
if (this.handBrake) {
|
|
268
|
+
this.rearWheelsIndices.forEach(index => this.chassisBody.applyBrake(index, this.carProperties.brake.handbrakeForce));
|
|
269
|
+
}
|
|
257
270
|
}
|
|
258
271
|
});
|
|
259
272
|
if (this.carProperties.transmission.isAuto) {
|
|
@@ -361,7 +374,7 @@ export class Gg3dRaycastVehicleEntity extends Gg3dEntity {
|
|
|
361
374
|
}
|
|
362
375
|
else {
|
|
363
376
|
this.acceleration = 0;
|
|
364
|
-
this.brake = -
|
|
377
|
+
this.brake = -value;
|
|
365
378
|
}
|
|
366
379
|
this.setTailLightsOn(value < 0);
|
|
367
380
|
}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { GgPositionableEntity } from '../../base/entities/gg-positionable-entity';
|
|
2
2
|
import { map } from 'rxjs/operators';
|
|
3
3
|
import { Qtrn } from '../../base/math/quaternion';
|
|
4
|
+
import { Pnt3 } from '../../base/math/point3';
|
|
4
5
|
export class GgPositionable3dEntity extends GgPositionableEntity {
|
|
5
6
|
getDefaultPosition() {
|
|
6
|
-
return
|
|
7
|
+
return Pnt3.O;
|
|
7
8
|
}
|
|
8
9
|
getDefaultRotation() {
|
|
9
|
-
return
|
|
10
|
+
return Qtrn.O;
|
|
10
11
|
}
|
|
11
12
|
getDefaultScale() {
|
|
12
13
|
return { x: 1, y: 1, z: 1 };
|
package/dist/3d/gg-3d-world.js
CHANGED
|
@@ -10,6 +10,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
10
10
|
import { GgWorld } from '../base/gg-world';
|
|
11
11
|
import { Gg3dLoader } from './loader';
|
|
12
12
|
import { Gg3dEntity } from './entities/gg-3d-entity';
|
|
13
|
+
import { Qtrn } from '../base/math/quaternion';
|
|
14
|
+
import { Pnt3 } from '../base/math/point3';
|
|
13
15
|
export class Gg3dWorld extends GgWorld {
|
|
14
16
|
constructor(visualScene, physicsWorld, consoleEnabled = false) {
|
|
15
17
|
super(visualScene, physicsWorld, consoleEnabled);
|
|
@@ -30,11 +32,7 @@ export class Gg3dWorld extends GgWorld {
|
|
|
30
32
|
'{x: 0, y: 0, z: -value}, 3 arguments set the whole vector. Default value is "9.82" or "0 0 -9.82"');
|
|
31
33
|
}
|
|
32
34
|
}
|
|
33
|
-
addPrimitiveRigidBody(descr, position = {
|
|
34
|
-
x: 0,
|
|
35
|
-
y: 0,
|
|
36
|
-
z: 0,
|
|
37
|
-
}, rotation = { x: 0, y: 0, z: 0, w: 1 }) {
|
|
35
|
+
addPrimitiveRigidBody(descr, position = Pnt3.O, rotation = Qtrn.O) {
|
|
38
36
|
const entity = new Gg3dEntity(this.visualScene.factory.createPrimitive(descr.shape), this.physicsWorld.factory.createRigidBody(descr));
|
|
39
37
|
entity.position = position;
|
|
40
38
|
entity.rotation = rotation;
|