@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
|
@@ -7,72 +7,103 @@ 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 { IEntity, MouseInput, MouseInputState, Pnt3, Qtrn, TickOrder, } from '../../../../base';
|
|
11
|
-
import { filter, takeUntil } from 'rxjs';
|
|
10
|
+
import { ggElastic, IEntity, MouseInput, MouseInputState, Pnt2, Pnt3, Qtrn, TickOrder, } from '../../../../base';
|
|
11
|
+
import { BehaviorSubject, filter, Subject, takeUntil } from 'rxjs';
|
|
12
12
|
import { map } from 'rxjs/operators';
|
|
13
13
|
const DEFAULT_OPTIONS = {
|
|
14
14
|
mouseOptions: {},
|
|
15
|
-
orbiting: { sensitivityX: 1, sensitivityY: 1 },
|
|
15
|
+
orbiting: { sensitivityX: 1, sensitivityY: 1 },
|
|
16
|
+
orbitingElasticity: 0,
|
|
16
17
|
zooming: { sensitivity: 1 },
|
|
17
18
|
panning: { sensitivityX: 1, sensitivityY: 1 },
|
|
18
19
|
dollying: { sensitivity: 1 },
|
|
19
20
|
};
|
|
20
21
|
export class OrbitCameraController extends IEntity {
|
|
21
|
-
get
|
|
22
|
-
return
|
|
22
|
+
get active() {
|
|
23
|
+
return super.active;
|
|
23
24
|
}
|
|
24
|
-
set
|
|
25
|
-
|
|
25
|
+
set active(value) {
|
|
26
|
+
if (!super.active && value) {
|
|
27
|
+
this.reset();
|
|
28
|
+
}
|
|
29
|
+
super.active = value;
|
|
26
30
|
}
|
|
27
|
-
get
|
|
28
|
-
return this.
|
|
31
|
+
get spherical() {
|
|
32
|
+
return this._spherical;
|
|
29
33
|
}
|
|
30
|
-
set
|
|
31
|
-
this.
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
}
|
|
36
|
-
set theta(value) {
|
|
37
|
-
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();
|
|
38
39
|
}
|
|
39
40
|
constructor(camera, options = {}) {
|
|
40
41
|
super();
|
|
41
42
|
this.camera = camera;
|
|
42
43
|
this.tickOrder = TickOrder.INPUT_CONTROLLERS;
|
|
43
|
-
this.
|
|
44
|
+
this._spherical = { phi: 0, radius: 10, theta: 0 };
|
|
44
45
|
this.target = Pnt3.O;
|
|
46
|
+
this.resetMotion$ = new Subject();
|
|
45
47
|
this.options = Object.assign(Object.assign({}, DEFAULT_OPTIONS), options);
|
|
46
48
|
this.mouseInput = new MouseInput(this.options.mouseOptions);
|
|
47
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
|
+
}
|
|
48
56
|
onSpawned(world) {
|
|
49
57
|
const _super = Object.create(null, {
|
|
50
58
|
onSpawned: { get: () => super.onSpawned }
|
|
51
59
|
});
|
|
52
60
|
return __awaiter(this, void 0, void 0, function* () {
|
|
53
61
|
yield _super.onSpawned.call(this, world);
|
|
54
|
-
this.
|
|
62
|
+
this._spherical = Pnt3.toSpherical(Pnt3.sub(this.camera.position, this.target));
|
|
55
63
|
if (this.options.orbiting) {
|
|
56
|
-
this.mouseInput.delta$
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
64
|
+
let mouseDelta$ = this.mouseInput.delta$.pipe(takeUntil(this._onRemoved$), filter(() => this.active && this.mouseInput.state == MouseInputState.DRAG));
|
|
65
|
+
if (this.options.orbitingElasticity > 0) {
|
|
66
|
+
const s$ = new BehaviorSubject(this._spherical);
|
|
67
|
+
mouseDelta$.subscribe(delta => {
|
|
68
|
+
const s = s$.getValue();
|
|
69
|
+
s$.next({
|
|
70
|
+
phi: Math.max(0.000001, Math.min(Math.PI - 0.000001, s.phi - (delta.y * this.options.orbiting.sensitivityY) / 1000)),
|
|
71
|
+
theta: s.theta - (delta.x * this.options.orbiting.sensitivityX) / 1000,
|
|
72
|
+
radius: 1,
|
|
73
|
+
});
|
|
74
|
+
});
|
|
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();
|
|
84
|
+
});
|
|
85
|
+
startElasticMotion();
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
mouseDelta$.subscribe(delta => {
|
|
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));
|
|
92
|
+
});
|
|
93
|
+
}
|
|
63
94
|
}
|
|
64
95
|
if (this.options.zooming) {
|
|
65
96
|
this.mouseInput.wheel$.pipe(takeUntil(this._onRemoved$)).subscribe(delta => {
|
|
66
97
|
if (delta != 0) {
|
|
67
|
-
this.
|
|
98
|
+
this._spherical.radius *= Math.pow(0.95, this.options.zooming.sensitivity * (delta > 0 ? -1 : 1));
|
|
68
99
|
}
|
|
69
100
|
});
|
|
70
101
|
}
|
|
71
102
|
const performPan = (delta) => {
|
|
72
|
-
const targetCameraVector = Pnt3.fromSpherical(this.
|
|
103
|
+
const targetCameraVector = Pnt3.fromSpherical(this._spherical);
|
|
73
104
|
const viewUp = Pnt3.rotAround(targetCameraVector, {
|
|
74
|
-
x: -Math.sin(this.
|
|
75
|
-
y: Math.cos(this.
|
|
105
|
+
x: -Math.sin(this._spherical.theta),
|
|
106
|
+
y: Math.cos(this._spherical.theta),
|
|
76
107
|
z: 0,
|
|
77
108
|
}, Math.PI / 2);
|
|
78
109
|
const viewRight = Pnt3.rotAround(targetCameraVector, Pnt3.norm(viewUp), Math.PI / 2);
|
|
@@ -89,14 +120,14 @@ export class OrbitCameraController extends IEntity {
|
|
|
89
120
|
this.mouseInput.delta$
|
|
90
121
|
.pipe(takeUntil(this._onRemoved$), filter(() => this.mouseInput.state == MouseInputState.DRAG_MIDDLE_BUTTON))
|
|
91
122
|
.subscribe(delta => {
|
|
92
|
-
this.
|
|
123
|
+
this._spherical.radius *= Math.pow(0.95, (-this.options.dollying.sensitivity * delta.y) / 10);
|
|
93
124
|
});
|
|
94
125
|
}
|
|
95
126
|
if (MouseInput.isTouchDevice() && (this.options.dollying || this.options.panning)) {
|
|
96
127
|
this.mouseInput.twoTouchGestureDelta$.pipe(takeUntil(this._onRemoved$)).subscribe(delta => {
|
|
97
128
|
// dolly on fingers pitch
|
|
98
129
|
if (this.options.dollying) {
|
|
99
|
-
this.
|
|
130
|
+
this._spherical.radius *= Math.pow(0.95, (this.options.dollying.sensitivity * delta.distanceDelta) / 10);
|
|
100
131
|
}
|
|
101
132
|
// pan on fingers move
|
|
102
133
|
if (this.options.panning) {
|
|
@@ -106,7 +137,7 @@ export class OrbitCameraController extends IEntity {
|
|
|
106
137
|
}
|
|
107
138
|
// Setup updating camera position and rotation based on input
|
|
108
139
|
this.camera.tick$
|
|
109
|
-
.pipe(takeUntil(this._onRemoved$), map(() => this.
|
|
140
|
+
.pipe(takeUntil(this._onRemoved$), filter(() => this.active), map(() => this._spherical))
|
|
110
141
|
.subscribe(spherical => {
|
|
111
142
|
this.camera.position = Pnt3.add(this.target, Pnt3.fromSpherical(spherical));
|
|
112
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
|
}
|
package/dist/3d/gg-3d-world.d.ts
CHANGED
|
@@ -36,4 +36,7 @@ export declare class Gg3dWorld<VTypeDoc extends VisualTypeDocRepo3D = VisualType
|
|
|
36
36
|
constructor(visualScene: VS, physicsWorld: PW);
|
|
37
37
|
addPrimitiveRigidBody(descr: BodyShape3DDescriptor, position?: Point3, rotation?: Point4, material?: DisplayObject3dOpts<VTypeDoc['texture']>): Entity3d<VTypeDoc, PTypeDoc>;
|
|
38
38
|
addRenderer(camera: VTypeDoc['camera'], canvas?: HTMLCanvasElement, rendererOptions?: Partial<RendererOptions & VTypeDoc['rendererExtraOpts']>): Renderer3dEntity<VTypeDoc>;
|
|
39
|
+
protected registerConsoleCommands(ggstatic: {
|
|
40
|
+
registerConsoleCommand: (world: GgWorld<any, any> | null, command: string, handler: (...args: string[]) => Promise<string>, doc?: string) => void;
|
|
41
|
+
}): void;
|
|
39
42
|
}
|
package/dist/3d/gg-3d-world.js
CHANGED
|
@@ -17,21 +17,12 @@ export class Gg3dWorld extends GgWorld {
|
|
|
17
17
|
this.visualScene = visualScene;
|
|
18
18
|
this.physicsWorld = physicsWorld;
|
|
19
19
|
this.loader = new Gg3dLoader(this);
|
|
20
|
-
if (window.ggstatic) {
|
|
21
|
-
window.ggstatic.registerConsoleCommand(this, 'ph_gravity', (...args) => __awaiter(this, void 0, void 0, function* () {
|
|
22
|
-
if (args.length == 1) {
|
|
23
|
-
args = ['0', '0', '' + -+args[0]]; // mean -Z axis
|
|
24
|
-
}
|
|
25
|
-
if (args.length > 0) {
|
|
26
|
-
this.physicsWorld.gravity = { x: +args[0], y: +args[1], z: +args[2] };
|
|
27
|
-
}
|
|
28
|
-
return JSON.stringify(this.physicsWorld.gravity);
|
|
29
|
-
}), 'args: [float] or [float float float]; change 3D world gravity vector. 1 argument means ' +
|
|
30
|
-
'{x: 0, y: 0, z: -value}, 3 arguments set the whole vector. Default value is "9.82" or "0 0 -9.82"');
|
|
31
|
-
}
|
|
32
20
|
}
|
|
33
21
|
addPrimitiveRigidBody(descr, position = Pnt3.O, rotation = Qtrn.O, material = {}) {
|
|
34
|
-
const entity = new Entity3d(
|
|
22
|
+
const entity = new Entity3d({
|
|
23
|
+
object3D: this.visualScene.factory.createPrimitive(descr.shape, material),
|
|
24
|
+
objectBody: this.physicsWorld.factory.createRigidBody(descr),
|
|
25
|
+
});
|
|
35
26
|
entity.position = position;
|
|
36
27
|
entity.rotation = rotation;
|
|
37
28
|
this.addEntity(entity);
|
|
@@ -42,4 +33,21 @@ export class Gg3dWorld extends GgWorld {
|
|
|
42
33
|
this.addEntity(entity);
|
|
43
34
|
return entity;
|
|
44
35
|
}
|
|
36
|
+
registerConsoleCommands(ggstatic) {
|
|
37
|
+
super.registerConsoleCommands(ggstatic);
|
|
38
|
+
ggstatic.registerConsoleCommand(this, 'gravity', (...args) => __awaiter(this, void 0, void 0, function* () {
|
|
39
|
+
if (args.length == 1) {
|
|
40
|
+
args = ['0', '0', '' + -+args[0]]; // mean -Z axis
|
|
41
|
+
}
|
|
42
|
+
if (args.length > 0) {
|
|
43
|
+
if (isNaN(+args[0]) || isNaN(+args[1]) || isNaN(+args[2])) {
|
|
44
|
+
throw new Error('Wrong arguments');
|
|
45
|
+
}
|
|
46
|
+
this.physicsWorld.gravity = { x: +args[0], y: +args[1], z: +args[2] };
|
|
47
|
+
}
|
|
48
|
+
return JSON.stringify(this.physicsWorld.gravity);
|
|
49
|
+
}), 'args: [ ?float, ?float, ?float ]; Get or set 3D world gravity vector. 1 argument sets ' +
|
|
50
|
+
'vector {x: 0, y: 0, z: -value}, 3 arguments set the whole vector.' +
|
|
51
|
+
' Default value is "9.82" or "0 0 -9.82"');
|
|
52
|
+
}
|
|
45
53
|
}
|
package/dist/3d/loader.js
CHANGED
|
@@ -99,7 +99,7 @@ export class Gg3dLoader {
|
|
|
99
99
|
const loadOptions = Object.assign(Object.assign({}, defaultLoadOptions), options);
|
|
100
100
|
const { resources, meta } = yield this.loadGgGlbResources(path, loadOptions.cachingStrategy);
|
|
101
101
|
const result = {
|
|
102
|
-
entities: resources.map(
|
|
102
|
+
entities: resources.map(x => new Entity3d({ object3D: x.object3D, objectBody: x.body })),
|
|
103
103
|
meta,
|
|
104
104
|
};
|
|
105
105
|
if (loadOptions.loadProps) {
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { Point2, Point3, Point4 } from '../../base';
|
|
2
2
|
import { Body3DOptions } from './body-options';
|
|
3
3
|
export type Shape3DDescriptor = {
|
|
4
|
+
collisionMargin?: number;
|
|
5
|
+
} & ({
|
|
4
6
|
shape: 'PLANE';
|
|
5
7
|
} | {
|
|
6
8
|
shape: 'BOX';
|
|
@@ -30,7 +32,7 @@ export type Shape3DDescriptor = {
|
|
|
30
32
|
shape: 'MESH';
|
|
31
33
|
vertices: Point3[];
|
|
32
34
|
faces: [number, number, number][];
|
|
33
|
-
};
|
|
35
|
+
});
|
|
34
36
|
export type Shape3DMeshDescriptor = {
|
|
35
37
|
shape: 'PLANE';
|
|
36
38
|
dimensions?: Point2;
|
|
@@ -1,16 +1,12 @@
|
|
|
1
|
-
import { Observable } from 'rxjs';
|
|
2
|
-
import { PausableClock } from './pausable-clock';
|
|
3
1
|
import { IClock } from './i-clock';
|
|
4
2
|
/**
|
|
5
3
|
* A singleton class, providing ability to track time, fire ticks, provide time elapsed + tick delta.
|
|
6
4
|
* Starts as soon as accessed and counts time from 01/01/1970
|
|
7
5
|
*/
|
|
8
|
-
export declare class GgGlobalClock
|
|
6
|
+
export declare class GgGlobalClock extends IClock {
|
|
9
7
|
private static _instance;
|
|
10
8
|
static get instance(): GgGlobalClock;
|
|
11
|
-
private readonly _tick$;
|
|
12
|
-
get tick$(): Observable<[number, number]>;
|
|
13
9
|
get elapsedTime(): number;
|
|
14
|
-
createChildClock(autoStart: boolean): PausableClock;
|
|
15
10
|
private constructor();
|
|
11
|
+
dispose(): void;
|
|
16
12
|
}
|
|
@@ -1,32 +1,32 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
import { PausableClock } from './pausable-clock';
|
|
1
|
+
import { IClock } from './i-clock';
|
|
2
|
+
const now = typeof performance === 'undefined' ? () => Date.now() : () => performance.now();
|
|
4
3
|
/**
|
|
5
4
|
* A singleton class, providing ability to track time, fire ticks, provide time elapsed + tick delta.
|
|
6
5
|
* Starts as soon as accessed and counts time from 01/01/1970
|
|
7
6
|
*/
|
|
8
|
-
export class GgGlobalClock {
|
|
7
|
+
export class GgGlobalClock extends IClock {
|
|
9
8
|
static get instance() {
|
|
10
9
|
if (!GgGlobalClock._instance) {
|
|
11
10
|
GgGlobalClock._instance = new GgGlobalClock();
|
|
12
11
|
}
|
|
13
12
|
return GgGlobalClock._instance;
|
|
14
13
|
}
|
|
15
|
-
get tick$() {
|
|
16
|
-
return this._tick$.pipe(map(([oldTime, newTime]) => [newTime, newTime - oldTime]));
|
|
17
|
-
}
|
|
18
14
|
get elapsedTime() {
|
|
19
|
-
return
|
|
20
|
-
}
|
|
21
|
-
createChildClock(autoStart) {
|
|
22
|
-
return new PausableClock(autoStart, this);
|
|
15
|
+
return now();
|
|
23
16
|
}
|
|
24
17
|
constructor() {
|
|
25
|
-
|
|
18
|
+
super(null);
|
|
26
19
|
let oldRelativeTime = this.elapsedTime;
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
20
|
+
const tick = () => {
|
|
21
|
+
requestAnimationFrame(tick);
|
|
22
|
+
const prev = oldRelativeTime;
|
|
23
|
+
const cur = this.elapsedTime;
|
|
24
|
+
oldRelativeTime = cur;
|
|
25
|
+
this._tick$.next([prev, cur - prev]);
|
|
26
|
+
};
|
|
27
|
+
requestAnimationFrame(tick);
|
|
28
|
+
}
|
|
29
|
+
dispose() {
|
|
30
|
+
throw new Error('Cannot dispose global clock');
|
|
31
31
|
}
|
|
32
32
|
}
|
|
@@ -1,7 +1,16 @@
|
|
|
1
|
-
import { Observable } from 'rxjs';
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import { Observable, Subject } from 'rxjs';
|
|
2
|
+
export declare abstract class IClock {
|
|
3
|
+
readonly parent: IClock | null;
|
|
4
|
+
protected readonly _tick$: Subject<[number, number]>;
|
|
5
|
+
/**
|
|
6
|
+
* Observable stream of ticks, emitting an array containing the current time and the tick delta.
|
|
7
|
+
*/
|
|
4
8
|
get tick$(): Observable<[number, number]>;
|
|
5
|
-
get elapsedTime(): number;
|
|
6
|
-
|
|
9
|
+
abstract get elapsedTime(): number;
|
|
10
|
+
protected _children: IClock[];
|
|
11
|
+
get children(): IClock[];
|
|
12
|
+
protected constructor(parent: IClock | null);
|
|
13
|
+
addChild(clock: IClock): void;
|
|
14
|
+
removeChild(clock: IClock): void;
|
|
15
|
+
dispose(): void;
|
|
7
16
|
}
|
|
@@ -1 +1,43 @@
|
|
|
1
|
-
|
|
1
|
+
import { Subject } from 'rxjs';
|
|
2
|
+
export class IClock {
|
|
3
|
+
/**
|
|
4
|
+
* Observable stream of ticks, emitting an array containing the current time and the tick delta.
|
|
5
|
+
*/
|
|
6
|
+
get tick$() {
|
|
7
|
+
return this._tick$.asObservable();
|
|
8
|
+
}
|
|
9
|
+
get children() {
|
|
10
|
+
return [...this._children];
|
|
11
|
+
}
|
|
12
|
+
constructor(parent) {
|
|
13
|
+
this.parent = parent;
|
|
14
|
+
this._tick$ = new Subject();
|
|
15
|
+
this._children = [];
|
|
16
|
+
if (parent) {
|
|
17
|
+
parent.addChild(this);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
addChild(clock) {
|
|
21
|
+
if (clock.parent !== this) {
|
|
22
|
+
throw new Error('Incorrect child clock');
|
|
23
|
+
}
|
|
24
|
+
if (!this._children.includes(clock)) {
|
|
25
|
+
this._children.push(clock);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
removeChild(clock) {
|
|
29
|
+
if (clock.parent !== this) {
|
|
30
|
+
throw new Error('Incorrect child clock');
|
|
31
|
+
}
|
|
32
|
+
this._children = this._children.filter(c => c !== clock);
|
|
33
|
+
}
|
|
34
|
+
dispose() {
|
|
35
|
+
if (this.parent) {
|
|
36
|
+
this.parent.removeChild(this);
|
|
37
|
+
}
|
|
38
|
+
for (const c of this._children) {
|
|
39
|
+
c.dispose();
|
|
40
|
+
}
|
|
41
|
+
this._tick$.complete();
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -1,17 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Subject } from 'rxjs';
|
|
2
2
|
import { IClock } from './i-clock';
|
|
3
3
|
/**
|
|
4
4
|
* A class providing the ability to track time, fire ticks, provide time elapsed, and tick delta with the ability to suspend/resume it.
|
|
5
5
|
*/
|
|
6
|
-
export declare class PausableClock
|
|
6
|
+
export declare class PausableClock extends IClock {
|
|
7
7
|
protected readonly parentClock: IClock;
|
|
8
8
|
private tickSub;
|
|
9
9
|
private readonly _internalTick$;
|
|
10
|
-
private readonly _tick$;
|
|
11
|
-
/**
|
|
12
|
-
* Observable stream of ticks, emitting an array containing the current time and the tick delta.
|
|
13
|
-
*/
|
|
14
|
-
get tick$(): Observable<[number, number]>;
|
|
15
10
|
/**
|
|
16
11
|
* Checks if the clock is currently running.
|
|
17
12
|
*/
|
|
@@ -54,12 +49,6 @@ export declare class PausableClock implements IClock {
|
|
|
54
49
|
* @param parentClock The parent clock to synchronize with. Defaults to GgGlobalClock instance.
|
|
55
50
|
*/
|
|
56
51
|
constructor(autoStart?: boolean, parentClock?: IClock);
|
|
57
|
-
/**
|
|
58
|
-
* Creates a child clock.
|
|
59
|
-
* @param autoStart Indicates whether the child clock should start automatically.
|
|
60
|
-
* @returns A new instance of PausableClock.
|
|
61
|
-
*/
|
|
62
|
-
createChildClock(autoStart: boolean): PausableClock;
|
|
63
52
|
/**
|
|
64
53
|
* Starts the clock.
|
|
65
54
|
*/
|
|
@@ -84,4 +73,5 @@ export declare class PausableClock implements IClock {
|
|
|
84
73
|
* Stops listening for ticks from the parent clock.
|
|
85
74
|
*/
|
|
86
75
|
protected stopListeningTicks(): void;
|
|
76
|
+
dispose(): void;
|
|
87
77
|
}
|
|
@@ -1,16 +1,11 @@
|
|
|
1
1
|
import { filter, Subject } from 'rxjs';
|
|
2
2
|
import { map, tap } from 'rxjs/operators';
|
|
3
3
|
import { GgGlobalClock } from './global-clock';
|
|
4
|
+
import { IClock } from './i-clock';
|
|
4
5
|
/**
|
|
5
6
|
* A class providing the ability to track time, fire ticks, provide time elapsed, and tick delta with the ability to suspend/resume it.
|
|
6
7
|
*/
|
|
7
|
-
export class PausableClock {
|
|
8
|
-
/**
|
|
9
|
-
* Observable stream of ticks, emitting an array containing the current time and the tick delta.
|
|
10
|
-
*/
|
|
11
|
-
get tick$() {
|
|
12
|
-
return this._tick$.asObservable();
|
|
13
|
-
}
|
|
8
|
+
export class PausableClock extends IClock {
|
|
14
9
|
/**
|
|
15
10
|
* Checks if the clock is currently running.
|
|
16
11
|
*/
|
|
@@ -76,10 +71,10 @@ export class PausableClock {
|
|
|
76
71
|
* @param parentClock The parent clock to synchronize with. Defaults to GgGlobalClock instance.
|
|
77
72
|
*/
|
|
78
73
|
constructor(autoStart = false, parentClock = GgGlobalClock.instance) {
|
|
74
|
+
super(parentClock);
|
|
79
75
|
this.parentClock = parentClock;
|
|
80
76
|
this.tickSub = null;
|
|
81
77
|
this._internalTick$ = new Subject();
|
|
82
|
-
this._tick$ = new Subject();
|
|
83
78
|
/**
|
|
84
79
|
* Tick rate limiter. If set to 0 - tick rate is unlimited, 15 means "allow at most 15 ticks per second"
|
|
85
80
|
*/
|
|
@@ -103,14 +98,6 @@ export class PausableClock {
|
|
|
103
98
|
Math.floor((elapsed * this.tickRateLimit) / 1000)), tap(([elapsed]) => (this.lastFiredTickElapsed = elapsed)))
|
|
104
99
|
.subscribe(this._tick$);
|
|
105
100
|
}
|
|
106
|
-
/**
|
|
107
|
-
* Creates a child clock.
|
|
108
|
-
* @param autoStart Indicates whether the child clock should start automatically.
|
|
109
|
-
* @returns A new instance of PausableClock.
|
|
110
|
-
*/
|
|
111
|
-
createChildClock(autoStart) {
|
|
112
|
-
return new PausableClock(autoStart, this);
|
|
113
|
-
}
|
|
114
101
|
/**
|
|
115
102
|
* Starts the clock.
|
|
116
103
|
*/
|
|
@@ -170,4 +157,9 @@ export class PausableClock {
|
|
|
170
157
|
(_a = this.tickSub) === null || _a === void 0 ? void 0 : _a.unsubscribe();
|
|
171
158
|
this.tickSub = null;
|
|
172
159
|
}
|
|
160
|
+
dispose() {
|
|
161
|
+
this.stopListeningTicks();
|
|
162
|
+
this._internalTick$.complete();
|
|
163
|
+
super.dispose();
|
|
164
|
+
}
|
|
173
165
|
}
|
package/dist/base/gg-world.d.ts
CHANGED
|
@@ -16,6 +16,7 @@ export declare abstract class GgWorld<D, R, VTypeDoc extends VisualTypeDocRepo<D
|
|
|
16
16
|
readonly physicsWorld: PW;
|
|
17
17
|
private static default_name_counter;
|
|
18
18
|
private static _documentWorlds;
|
|
19
|
+
static readonly worldCreated$: Subject<GgWorld<any, any>>;
|
|
19
20
|
static get documentWorlds(): GgWorld<any, any>[];
|
|
20
21
|
readonly worldClock: PausableClock;
|
|
21
22
|
readonly keyboardInput: KeyboardInput;
|
|
@@ -26,6 +27,7 @@ export declare abstract class GgWorld<D, R, VTypeDoc extends VisualTypeDocRepo<D
|
|
|
26
27
|
readonly tickForwardTo$: Subject<IEntity | 'PHYSICS_WORLD'>;
|
|
27
28
|
readonly tickForwardedTo$: Subject<IEntity | 'PHYSICS_WORLD'>;
|
|
28
29
|
readonly paused$: Subject<boolean>;
|
|
30
|
+
readonly disposed$: Subject<void>;
|
|
29
31
|
protected constructor(visualScene: VS, physicsWorld: PW);
|
|
30
32
|
init(): Promise<void>;
|
|
31
33
|
start(): void;
|
|
@@ -40,4 +42,8 @@ export declare abstract class GgWorld<D, R, VTypeDoc extends VisualTypeDocRepo<D
|
|
|
40
42
|
position?: D, rotation?: R, material?: unknown): IPositionable<D, R> & IRenderableEntity<D, R, VTypeDoc>;
|
|
41
43
|
addEntity(entity: IEntity): void;
|
|
42
44
|
removeEntity(entity: IEntity, dispose?: boolean): void;
|
|
45
|
+
private onGgStaticInitialized;
|
|
46
|
+
protected registerConsoleCommands(ggstatic: {
|
|
47
|
+
registerConsoleCommand: (world: GgWorld<any, any> | null, command: string, handler: (...args: string[]) => Promise<string>, doc?: string) => void;
|
|
48
|
+
}): void;
|
|
43
49
|
}
|