@gg-web-engine/core 0.0.38 → 0.0.39
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/components/physics/i-rigid-body-2d.component.d.ts +3 -0
- package/dist/2d/components/physics/i-trigger-2d.component.d.ts +3 -0
- package/dist/2d/models/body-options.d.ts +5 -1
- package/dist/3d/components/physics/i-physics-world-3d.component.d.ts +7 -0
- package/dist/3d/components/physics/i-rigid-body-3d.component.d.ts +3 -0
- package/dist/3d/components/physics/i-trigger-3d.component.d.ts +3 -0
- package/dist/3d/entities/controllers/input/car-keyboard-handling.controller.js +2 -2
- package/dist/3d/entities/controllers/input/gg-car-keyboard-handling.controller.js +3 -3
- package/dist/3d/factories.d.ts +3 -3
- package/dist/3d/models/body-options.d.ts +5 -1
- package/dist/3d/models/shapes.d.ts +41 -1
- package/dist/base/clock/pausable-clock.d.ts +56 -1
- package/dist/base/clock/pausable-clock.js +88 -5
- package/dist/base/components/physics/i-body.component.d.ts +3 -1
- package/dist/base/components/physics/i-physics-world.component.d.ts +8 -6
- package/dist/base/components/rendering/i-renderer.component.d.ts +4 -0
- package/dist/base/components/rendering/i-visual-scene.component.d.ts +0 -4
- package/dist/base/entities/i-entity.d.ts +1 -1
- package/dist/base/entities/i-entity.js +3 -3
- package/dist/base/entities/i-renderer.entity.d.ts +4 -0
- package/dist/base/entities/i-renderer.entity.js +8 -0
- package/dist/base/gg-world.d.ts +0 -2
- package/dist/base/gg-world.js +26 -25
- package/dist/base/index.d.ts +0 -1
- package/dist/base/index.js +0 -1
- package/dist/base/models/body-options.d.ts +9 -0
- package/dist/dev/gg-console.ui.js +16 -8
- package/dist/dev/gg-debugger.ui.d.ts +4 -0
- package/dist/dev/gg-debugger.ui.js +83 -32
- package/dist/dev/gg-static.d.ts +0 -1
- package/dist/dev/gg-static.js +3 -4
- package/package.json +1 -1
- package/dist/base/interfaces/i-debug-physics-drawer.d.ts +0 -8
- package/dist/base/interfaces/i-debug-physics-drawer.js +0 -1
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { IRigidBodyComponent, Point2 } from '../../../base';
|
|
2
2
|
import { PhysicsTypeDocRepo2D } from '../../gg-2d-world';
|
|
3
|
+
import { DebugBody2DSettings } from '../../models/body-options';
|
|
3
4
|
export interface IRigidBody2dComponent<TypeDoc extends PhysicsTypeDocRepo2D = PhysicsTypeDocRepo2D> extends IRigidBodyComponent<Point2, number, TypeDoc> {
|
|
4
5
|
angularVelocity: number;
|
|
6
|
+
/** body info for physics debugger view */
|
|
7
|
+
readonly debugBodySettings: DebugBody2DSettings;
|
|
5
8
|
}
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { ITriggerComponent, Point2 } from '../../../base';
|
|
2
2
|
import { Observable } from 'rxjs';
|
|
3
3
|
import { PhysicsTypeDocRepo2D } from '../../gg-2d-world';
|
|
4
|
+
import { DebugBody2DSettings } from '../../models/body-options';
|
|
4
5
|
export interface ITrigger2dComponent<TypeDoc extends PhysicsTypeDocRepo2D = PhysicsTypeDocRepo2D> extends ITriggerComponent<Point2, number, TypeDoc> {
|
|
6
|
+
/** body info for physics debugger view */
|
|
7
|
+
readonly debugBodySettings: DebugBody2DSettings;
|
|
5
8
|
get onEntityEntered(): Observable<TypeDoc['rigidBody']>;
|
|
6
9
|
get onEntityLeft(): Observable<TypeDoc['rigidBody'] | null>;
|
|
7
10
|
}
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
-
import { BodyOptions } from '../../base';
|
|
1
|
+
import { BodyOptions, DebugBodySettings } from '../../base';
|
|
2
|
+
import { Shape2DDescriptor } from './shapes';
|
|
2
3
|
export interface Body2DOptions extends BodyOptions {
|
|
3
4
|
}
|
|
5
|
+
export declare type DebugBody2DSettings = DebugBodySettings & {
|
|
6
|
+
shape: Shape2DDescriptor;
|
|
7
|
+
};
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import { IPhysicsWorldComponent, Point3, Point4 } from '../../../base';
|
|
2
2
|
import { PhysicsTypeDocRepo3D } from '../../gg-3d-world';
|
|
3
|
+
import { Subject } from 'rxjs';
|
|
3
4
|
export interface IPhysicsWorld3dComponent<TypeDoc extends PhysicsTypeDocRepo3D = PhysicsTypeDocRepo3D> extends IPhysicsWorldComponent<Point3, Point4, TypeDoc> {
|
|
4
5
|
readonly loader: TypeDoc['loader'];
|
|
6
|
+
/** event emitter, emits newly added physics components */
|
|
7
|
+
readonly added$: Subject<TypeDoc['trigger'] | TypeDoc['rigidBody'] | TypeDoc['raycastVehicle'] | any>;
|
|
8
|
+
/** event emitter, emits just removed physics components */
|
|
9
|
+
readonly removed$: Subject<TypeDoc['trigger'] | TypeDoc['rigidBody'] | TypeDoc['raycastVehicle'] | any>;
|
|
10
|
+
/** list of currently added to world physics components */
|
|
11
|
+
readonly children: (TypeDoc['trigger'] | TypeDoc['rigidBody'] | TypeDoc['raycastVehicle'] | any)[];
|
|
5
12
|
}
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { IRigidBodyComponent, Point3, Point4 } from '../../../base';
|
|
2
2
|
import { PhysicsTypeDocRepo3D } from '../../gg-3d-world';
|
|
3
|
+
import { DebugBody3DSettings } from '../../models/body-options';
|
|
3
4
|
export interface IRigidBody3dComponent<TypeDoc extends PhysicsTypeDocRepo3D = PhysicsTypeDocRepo3D> extends IRigidBodyComponent<Point3, Point4, TypeDoc> {
|
|
4
5
|
angularVelocity: Point3;
|
|
6
|
+
/** body info for physics debugger view */
|
|
7
|
+
readonly debugBodySettings: DebugBody3DSettings;
|
|
5
8
|
}
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { ITriggerComponent, Point3, Point4 } from '../../../base';
|
|
2
2
|
import { Observable } from 'rxjs';
|
|
3
3
|
import { PhysicsTypeDocRepo3D } from '../../gg-3d-world';
|
|
4
|
+
import { DebugBody3DSettings } from '../../models/body-options';
|
|
4
5
|
export interface ITrigger3dComponent<TypeDoc extends PhysicsTypeDocRepo3D = PhysicsTypeDocRepo3D> extends ITriggerComponent<Point3, Point4, TypeDoc> {
|
|
6
|
+
/** body info for physics debugger view */
|
|
7
|
+
readonly debugBodySettings: DebugBody3DSettings;
|
|
5
8
|
get onEntityEntered(): Observable<TypeDoc['rigidBody']>;
|
|
6
9
|
get onEntityLeft(): Observable<TypeDoc['rigidBody'] | null>;
|
|
7
10
|
}
|
|
@@ -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 { combineLatest, Subject, takeUntil } from 'rxjs';
|
|
10
|
+
import { combineLatest, filter, Subject, takeUntil } from 'rxjs';
|
|
11
11
|
import { DirectionKeyboardInput, IEntity, TickOrder, } from '../../../../base';
|
|
12
12
|
export class CarKeyboardHandlingController extends IEntity {
|
|
13
13
|
constructor(keyboard, options = {
|
|
@@ -32,7 +32,7 @@ export class CarKeyboardHandlingController extends IEntity {
|
|
|
32
32
|
_super.onSpawned.call(this, world);
|
|
33
33
|
let input = { upDown: 0, leftRight: 0 };
|
|
34
34
|
combineLatest([this.directionsInput.output$, this.tick$])
|
|
35
|
-
.pipe(takeUntil(this._onRemoved$))
|
|
35
|
+
.pipe(filter(() => this.active), takeUntil(this._onRemoved$))
|
|
36
36
|
.subscribe(([d, [_, dt]]) => {
|
|
37
37
|
const direction = { upDown: 0, leftRight: 0 };
|
|
38
38
|
if (d.leftRight !== undefined)
|
|
@@ -64,7 +64,7 @@ export class GgCarKeyboardHandlingController extends IEntity {
|
|
|
64
64
|
});
|
|
65
65
|
this.keyboard
|
|
66
66
|
.bind(this.options.gearUpDownKeys[0])
|
|
67
|
-
.pipe(takeUntil(this._onRemoved$), filter(x => this.switchingGearsEnabled && !!x))
|
|
67
|
+
.pipe(takeUntil(this._onRemoved$), filter(x => this.active && this.switchingGearsEnabled && !!x))
|
|
68
68
|
.subscribe(() => {
|
|
69
69
|
if (this.car && (!this.car.carProperties.transmission.isAuto || this.car.gear <= 0)) {
|
|
70
70
|
this.car.gear++;
|
|
@@ -72,7 +72,7 @@ export class GgCarKeyboardHandlingController extends IEntity {
|
|
|
72
72
|
});
|
|
73
73
|
this.keyboard
|
|
74
74
|
.bind(this.options.gearUpDownKeys[1])
|
|
75
|
-
.pipe(takeUntil(this._onRemoved$), filter(x => this.switchingGearsEnabled && !!x))
|
|
75
|
+
.pipe(takeUntil(this._onRemoved$), filter(x => this.active && this.switchingGearsEnabled && !!x))
|
|
76
76
|
.subscribe(() => {
|
|
77
77
|
if (this.car) {
|
|
78
78
|
if (this.car.carProperties.transmission.isAuto && this.car.gear > 1) {
|
|
@@ -85,7 +85,7 @@ export class GgCarKeyboardHandlingController extends IEntity {
|
|
|
85
85
|
});
|
|
86
86
|
this.keyboard
|
|
87
87
|
.bind(this.options.handbrakeKey)
|
|
88
|
-
.pipe(takeUntil(this._onRemoved$))
|
|
88
|
+
.pipe(takeUntil(this._onRemoved$), filter(() => this.active))
|
|
89
89
|
.subscribe(isKeyDown => {
|
|
90
90
|
if (this.car) {
|
|
91
91
|
this.car.handBrake = isKeyDown;
|
package/dist/3d/factories.d.ts
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import { BodyShape3DDescriptor, Shape3DDescriptor } from './models/shapes';
|
|
1
|
+
import { BodyShape3DDescriptor, Shape3DDescriptor, Shape3DMeshDescriptor } from './models/shapes';
|
|
2
2
|
import { Point3, Point4 } from '../base';
|
|
3
3
|
import { PhysicsTypeDocRepo3D, VisualTypeDocRepo3D } from './gg-3d-world';
|
|
4
4
|
export declare type DisplayObject3dOpts<Tex> = {
|
|
5
5
|
color?: number;
|
|
6
|
-
shading?: 'unlit' | 'standart' | 'phong';
|
|
6
|
+
shading?: 'unlit' | 'standart' | 'phong' | 'wireframe';
|
|
7
7
|
diffuse?: Tex;
|
|
8
8
|
castShadow?: boolean;
|
|
9
9
|
receiveShadow?: boolean;
|
|
10
10
|
};
|
|
11
11
|
export declare abstract class IDisplayObject3dComponentFactory<TypeDoc extends VisualTypeDocRepo3D = VisualTypeDocRepo3D> {
|
|
12
|
-
abstract createPrimitive(descriptor:
|
|
12
|
+
abstract createPrimitive(descriptor: Shape3DMeshDescriptor, material?: DisplayObject3dOpts<TypeDoc['texture']>): TypeDoc['displayObject'];
|
|
13
13
|
abstract createPerspectiveCamera(settings: {
|
|
14
14
|
fov?: number;
|
|
15
15
|
aspectRatio?: number;
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
-
import { BodyOptions } from '../../base';
|
|
1
|
+
import { BodyOptions, DebugBodySettings } from '../../base';
|
|
2
|
+
import { Shape3DDescriptor } from './shapes';
|
|
2
3
|
export interface Body3DOptions extends BodyOptions {
|
|
3
4
|
}
|
|
5
|
+
export declare type DebugBody3DSettings = DebugBodySettings & {
|
|
6
|
+
shape: Shape3DDescriptor;
|
|
7
|
+
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Point3, Point4 } from '../../base';
|
|
1
|
+
import { Point2, Point3, Point4 } from '../../base';
|
|
2
2
|
import { Body3DOptions } from './body-options';
|
|
3
3
|
export declare type Shape3DDescriptor = {
|
|
4
4
|
shape: 'PLANE';
|
|
@@ -31,6 +31,46 @@ export declare type Shape3DDescriptor = {
|
|
|
31
31
|
vertices: Point3[];
|
|
32
32
|
faces: [number, number, number][];
|
|
33
33
|
};
|
|
34
|
+
export declare type Shape3DMeshDescriptor = {
|
|
35
|
+
shape: 'PLANE';
|
|
36
|
+
dimensions?: Point2;
|
|
37
|
+
segments?: Point2;
|
|
38
|
+
} | {
|
|
39
|
+
shape: 'BOX';
|
|
40
|
+
dimensions: Point3;
|
|
41
|
+
segments?: Point3;
|
|
42
|
+
} | {
|
|
43
|
+
shape: 'CONE' | 'CYLINDER';
|
|
44
|
+
radius: number;
|
|
45
|
+
height: number;
|
|
46
|
+
radialSegments?: number;
|
|
47
|
+
heightSegments?: number;
|
|
48
|
+
} | {
|
|
49
|
+
shape: 'CAPSULE';
|
|
50
|
+
radius: number;
|
|
51
|
+
centersDistance: number;
|
|
52
|
+
capSegments?: number;
|
|
53
|
+
radialSegments?: number;
|
|
54
|
+
} | {
|
|
55
|
+
shape: 'SPHERE';
|
|
56
|
+
radius: number;
|
|
57
|
+
widthSegments?: number;
|
|
58
|
+
heightSegments?: number;
|
|
59
|
+
} | {
|
|
60
|
+
shape: 'COMPOUND';
|
|
61
|
+
children: {
|
|
62
|
+
position?: Point3;
|
|
63
|
+
rotation?: Point4;
|
|
64
|
+
shape: Shape3DMeshDescriptor;
|
|
65
|
+
}[];
|
|
66
|
+
} | {
|
|
67
|
+
shape: 'CONVEX_HULL';
|
|
68
|
+
vertices: Point3[];
|
|
69
|
+
} | {
|
|
70
|
+
shape: 'MESH';
|
|
71
|
+
vertices: Point3[];
|
|
72
|
+
faces: [number, number, number][];
|
|
73
|
+
};
|
|
34
74
|
export declare type BodyShape3DDescriptor = {
|
|
35
75
|
shape: Shape3DDescriptor;
|
|
36
76
|
body: Partial<Body3DOptions>;
|
|
@@ -1,25 +1,80 @@
|
|
|
1
1
|
import { Observable } from 'rxjs';
|
|
2
2
|
import { IClock } from './i-clock';
|
|
3
3
|
/**
|
|
4
|
-
* A class
|
|
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
6
|
export declare class PausableClock implements IClock {
|
|
7
7
|
protected readonly parentClock: IClock;
|
|
8
8
|
private tickSub;
|
|
9
9
|
private readonly _tick$;
|
|
10
|
+
/**
|
|
11
|
+
* Observable stream of ticks, emitting an array containing the current time and the tick delta.
|
|
12
|
+
*/
|
|
10
13
|
get tick$(): Observable<[number, number]>;
|
|
14
|
+
/**
|
|
15
|
+
* Checks if the clock is currently running.
|
|
16
|
+
*/
|
|
11
17
|
get isRunning(): boolean;
|
|
18
|
+
/**
|
|
19
|
+
* Checks if the clock is currently paused.
|
|
20
|
+
*/
|
|
12
21
|
get isPaused(): boolean;
|
|
22
|
+
/**
|
|
23
|
+
* Checks if the clock is stopped.
|
|
24
|
+
*/
|
|
25
|
+
get isStopped(): boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Gets the time scale of the clock.
|
|
28
|
+
*/
|
|
29
|
+
get timeScale(): number;
|
|
30
|
+
/**
|
|
31
|
+
* Sets the time scale of the clock.
|
|
32
|
+
*/
|
|
33
|
+
set timeScale(value: number);
|
|
34
|
+
/**
|
|
35
|
+
* Gets the elapsed time since the clock started.
|
|
36
|
+
*/
|
|
13
37
|
get elapsedTime(): number;
|
|
14
38
|
private startedAt;
|
|
15
39
|
private oldRelativeTime;
|
|
16
40
|
private pausedAt;
|
|
41
|
+
private lastStopElapsed;
|
|
42
|
+
private _timeScale;
|
|
43
|
+
private pausedByTimescale;
|
|
44
|
+
/**
|
|
45
|
+
* Constructs a new PausableClock instance.
|
|
46
|
+
* @param autoStart Indicates whether the clock should start automatically upon creation.
|
|
47
|
+
* @param parentClock The parent clock to synchronize with. Defaults to GgGlobalClock instance.
|
|
48
|
+
*/
|
|
17
49
|
constructor(autoStart?: boolean, parentClock?: IClock);
|
|
50
|
+
/**
|
|
51
|
+
* Creates a child clock.
|
|
52
|
+
* @param autoStart Indicates whether the child clock should start automatically.
|
|
53
|
+
* @returns A new instance of PausableClock.
|
|
54
|
+
*/
|
|
18
55
|
createChildClock(autoStart: boolean): PausableClock;
|
|
56
|
+
/**
|
|
57
|
+
* Starts the clock.
|
|
58
|
+
*/
|
|
19
59
|
start(): void;
|
|
60
|
+
/**
|
|
61
|
+
* Stops the clock.
|
|
62
|
+
*/
|
|
20
63
|
stop(): void;
|
|
64
|
+
/**
|
|
65
|
+
* Pauses the clock.
|
|
66
|
+
*/
|
|
21
67
|
pause(): void;
|
|
68
|
+
/**
|
|
69
|
+
* Resumes the clock.
|
|
70
|
+
*/
|
|
22
71
|
resume(): void;
|
|
72
|
+
/**
|
|
73
|
+
* Starts listening for ticks from the parent clock.
|
|
74
|
+
*/
|
|
23
75
|
protected startListeningTicks(): void;
|
|
76
|
+
/**
|
|
77
|
+
* Stops listening for ticks from the parent clock.
|
|
78
|
+
*/
|
|
24
79
|
protected stopListeningTicks(): void;
|
|
25
80
|
}
|
|
@@ -2,39 +2,105 @@ import { Subject } from 'rxjs';
|
|
|
2
2
|
import { map, tap } from 'rxjs/operators';
|
|
3
3
|
import { GgGlobalClock } from './global-clock';
|
|
4
4
|
/**
|
|
5
|
-
* A class
|
|
5
|
+
* A class providing the ability to track time, fire ticks, provide time elapsed, and tick delta with the ability to suspend/resume it.
|
|
6
6
|
*/
|
|
7
7
|
export class PausableClock {
|
|
8
|
+
/**
|
|
9
|
+
* Constructs a new PausableClock instance.
|
|
10
|
+
* @param autoStart Indicates whether the clock should start automatically upon creation.
|
|
11
|
+
* @param parentClock The parent clock to synchronize with. Defaults to GgGlobalClock instance.
|
|
12
|
+
*/
|
|
8
13
|
constructor(autoStart = false, parentClock = GgGlobalClock.instance) {
|
|
9
14
|
this.parentClock = parentClock;
|
|
10
15
|
this.tickSub = null;
|
|
11
16
|
this._tick$ = new Subject();
|
|
12
|
-
//
|
|
17
|
+
// State variables
|
|
13
18
|
this.startedAt = -1;
|
|
14
19
|
this.oldRelativeTime = 0; // "elapsed", emitted on last tick
|
|
15
20
|
this.pausedAt = -1;
|
|
21
|
+
this.lastStopElapsed = 0;
|
|
22
|
+
this._timeScale = 1;
|
|
23
|
+
this.pausedByTimescale = false;
|
|
16
24
|
if (autoStart) {
|
|
17
25
|
this.start();
|
|
18
26
|
}
|
|
19
27
|
}
|
|
28
|
+
/**
|
|
29
|
+
* Observable stream of ticks, emitting an array containing the current time and the tick delta.
|
|
30
|
+
*/
|
|
20
31
|
get tick$() {
|
|
21
32
|
return this._tick$.pipe(map(([oldTime, newTime]) => [newTime, newTime - oldTime]));
|
|
22
33
|
}
|
|
34
|
+
/**
|
|
35
|
+
* Checks if the clock is currently running.
|
|
36
|
+
*/
|
|
23
37
|
get isRunning() {
|
|
24
38
|
return !!this.tickSub;
|
|
25
39
|
}
|
|
40
|
+
/**
|
|
41
|
+
* Checks if the clock is currently paused.
|
|
42
|
+
*/
|
|
26
43
|
get isPaused() {
|
|
27
44
|
return this.pausedAt !== -1;
|
|
28
45
|
}
|
|
46
|
+
/**
|
|
47
|
+
* Checks if the clock is stopped.
|
|
48
|
+
*/
|
|
49
|
+
get isStopped() {
|
|
50
|
+
return this.startedAt === -1;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Gets the time scale of the clock.
|
|
54
|
+
*/
|
|
55
|
+
get timeScale() {
|
|
56
|
+
return this._timeScale;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Sets the time scale of the clock.
|
|
60
|
+
*/
|
|
61
|
+
set timeScale(value) {
|
|
62
|
+
if (value === this._timeScale && !(this.pausedByTimescale && value !== 0))
|
|
63
|
+
return;
|
|
64
|
+
if (value === 0) {
|
|
65
|
+
if (!this.isPaused) {
|
|
66
|
+
this.pause();
|
|
67
|
+
this.pausedByTimescale = true;
|
|
68
|
+
}
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
if (this.isPaused && this.pausedByTimescale) {
|
|
72
|
+
this.resume();
|
|
73
|
+
this.pausedByTimescale = false;
|
|
74
|
+
}
|
|
75
|
+
if (!this.isStopped) {
|
|
76
|
+
const cur = this.isPaused ? this.pausedAt : this.parentClock.elapsedTime;
|
|
77
|
+
this.startedAt = cur - ((cur - this.startedAt) * this.timeScale) / value;
|
|
78
|
+
}
|
|
79
|
+
this._timeScale = value;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Gets the elapsed time since the clock started.
|
|
83
|
+
*/
|
|
29
84
|
get elapsedTime() {
|
|
85
|
+
if (this.isStopped) {
|
|
86
|
+
return this.lastStopElapsed;
|
|
87
|
+
}
|
|
30
88
|
if (this.isPaused) {
|
|
31
|
-
return this.pausedAt - this.startedAt;
|
|
89
|
+
return this._timeScale * (this.pausedAt - this.startedAt);
|
|
32
90
|
}
|
|
33
|
-
return this.parentClock.elapsedTime - this.startedAt;
|
|
91
|
+
return this._timeScale * (this.parentClock.elapsedTime - this.startedAt);
|
|
34
92
|
}
|
|
93
|
+
/**
|
|
94
|
+
* Creates a child clock.
|
|
95
|
+
* @param autoStart Indicates whether the child clock should start automatically.
|
|
96
|
+
* @returns A new instance of PausableClock.
|
|
97
|
+
*/
|
|
35
98
|
createChildClock(autoStart) {
|
|
36
99
|
return new PausableClock(autoStart, this);
|
|
37
100
|
}
|
|
101
|
+
/**
|
|
102
|
+
* Starts the clock.
|
|
103
|
+
*/
|
|
38
104
|
start() {
|
|
39
105
|
if (this.isRunning) {
|
|
40
106
|
return;
|
|
@@ -43,14 +109,25 @@ export class PausableClock {
|
|
|
43
109
|
this.startedAt = this.parentClock.elapsedTime;
|
|
44
110
|
this.startListeningTicks();
|
|
45
111
|
}
|
|
112
|
+
/**
|
|
113
|
+
* Stops the clock.
|
|
114
|
+
*/
|
|
46
115
|
stop() {
|
|
47
116
|
this.stopListeningTicks();
|
|
117
|
+
this.lastStopElapsed = this.elapsedTime;
|
|
48
118
|
this.startedAt = this.pausedAt = -1;
|
|
49
119
|
}
|
|
120
|
+
/**
|
|
121
|
+
* Pauses the clock.
|
|
122
|
+
*/
|
|
50
123
|
pause() {
|
|
51
124
|
this.stopListeningTicks();
|
|
52
125
|
this.pausedAt = this.parentClock.elapsedTime;
|
|
126
|
+
this.pausedByTimescale = false;
|
|
53
127
|
}
|
|
128
|
+
/**
|
|
129
|
+
* Resumes the clock.
|
|
130
|
+
*/
|
|
54
131
|
resume() {
|
|
55
132
|
if (this.isRunning || this.pausedAt == -1) {
|
|
56
133
|
return;
|
|
@@ -59,14 +136,20 @@ export class PausableClock {
|
|
|
59
136
|
this.pausedAt = -1;
|
|
60
137
|
this.startListeningTicks();
|
|
61
138
|
}
|
|
139
|
+
/**
|
|
140
|
+
* Starts listening for ticks from the parent clock.
|
|
141
|
+
*/
|
|
62
142
|
startListeningTicks() {
|
|
63
143
|
if (this.tickSub) {
|
|
64
144
|
throw new Error('Clock is already ticking!');
|
|
65
145
|
}
|
|
66
146
|
this.tickSub = this.parentClock.tick$
|
|
67
|
-
.pipe(map(([
|
|
147
|
+
.pipe(map(([_, d]) => [this.oldRelativeTime, this.oldRelativeTime + d * this.timeScale]), tap(([_, cur]) => (this.oldRelativeTime = cur)))
|
|
68
148
|
.subscribe(this._tick$);
|
|
69
149
|
}
|
|
150
|
+
/**
|
|
151
|
+
* Stops listening for ticks from the parent clock.
|
|
152
|
+
*/
|
|
70
153
|
stopListeningTicks() {
|
|
71
154
|
var _a;
|
|
72
155
|
(_a = this.tickSub) === null || _a === void 0 ? void 0 : _a.unsubscribe();
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { IEntity } from '../../entities/i-entity';
|
|
2
2
|
import { IWorldComponent } from '../i-world-component';
|
|
3
3
|
import { GgWorld, PhysicsTypeDocRepo, VisualTypeDocRepo } from '../../gg-world';
|
|
4
|
-
import { CollisionGroup } from '../../models/body-options';
|
|
4
|
+
import { CollisionGroup, DebugBodySettings } from '../../models/body-options';
|
|
5
5
|
export interface IBodyComponent<D, R, TypeDoc extends PhysicsTypeDocRepo<D, R> = PhysicsTypeDocRepo<D, R>> extends IWorldComponent<D, R, VisualTypeDocRepo<D, R>, TypeDoc> {
|
|
6
6
|
entity: IEntity | null;
|
|
7
7
|
position: D;
|
|
@@ -11,6 +11,8 @@ export interface IBodyComponent<D, R, TypeDoc extends PhysicsTypeDocRepo<D, R> =
|
|
|
11
11
|
set ownCollisionGroups(value: CollisionGroup[] | 'all');
|
|
12
12
|
get interactWithCollisionGroups(): CollisionGroup[];
|
|
13
13
|
set interactWithCollisionGroups(value: CollisionGroup[] | 'all');
|
|
14
|
+
/** body info for physics debugger view */
|
|
15
|
+
readonly debugBodySettings: DebugBodySettings;
|
|
14
16
|
clone(): IBodyComponent<D, R, TypeDoc>;
|
|
15
17
|
addToWorld(world: GgWorld<D, R, VisualTypeDocRepo<D, R>, TypeDoc>): void;
|
|
16
18
|
removeFromWorld(world: GgWorld<D, R, VisualTypeDocRepo<D, R>, TypeDoc>): void;
|
|
@@ -1,12 +1,16 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { IDebugPhysicsDrawer } from '../../interfaces/i-debug-physics-drawer';
|
|
1
|
+
import { PhysicsTypeDocRepo } from '../../gg-world';
|
|
3
2
|
import { IComponent } from '../i-component';
|
|
4
3
|
import { CollisionGroup } from '../../models/body-options';
|
|
4
|
+
import { Subject } from 'rxjs';
|
|
5
5
|
export interface IPhysicsWorldComponent<D, R, TypeDoc extends PhysicsTypeDocRepo<D, R> = PhysicsTypeDocRepo<D, R>> extends IComponent {
|
|
6
6
|
readonly factory: TypeDoc['factory'];
|
|
7
7
|
gravity: D;
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
/** event emitter, emits newly added physics components */
|
|
9
|
+
readonly added$: Subject<TypeDoc['rigidBody'] | TypeDoc['trigger'] | any>;
|
|
10
|
+
/** event emitter, emits just removed physics components */
|
|
11
|
+
readonly removed$: Subject<TypeDoc['rigidBody'] | TypeDoc['trigger'] | any>;
|
|
12
|
+
/** list of currently added to world physics components */
|
|
13
|
+
readonly children: (TypeDoc['rigidBody'] | TypeDoc['trigger'] | any)[];
|
|
10
14
|
init(): Promise<void>;
|
|
11
15
|
/**
|
|
12
16
|
* Runs simulation of the physics world.
|
|
@@ -16,6 +20,4 @@ export interface IPhysicsWorldComponent<D, R, TypeDoc extends PhysicsTypeDocRepo
|
|
|
16
20
|
simulate(delta: number): void;
|
|
17
21
|
registerCollisionGroup(): CollisionGroup;
|
|
18
22
|
deregisterCollisionGroup(group: CollisionGroup): void;
|
|
19
|
-
startDebugger(world: GgWorld<D, R>, drawer: IDebugPhysicsDrawer<D, R>): void;
|
|
20
|
-
stopDebugger(world: GgWorld<D, R>): void;
|
|
21
23
|
}
|
|
@@ -26,6 +26,10 @@ export declare abstract class IRendererComponent<D, R, VTypeDoc extends VisualTy
|
|
|
26
26
|
entity: IEntity | null;
|
|
27
27
|
/** Specifies the options for the renderer. */
|
|
28
28
|
readonly rendererOptions: RendererOptions;
|
|
29
|
+
/** get flag whether renderer shows physics debugger view */
|
|
30
|
+
abstract get physicsDebugViewActive(): boolean;
|
|
31
|
+
/** turns on/off physics debugger view for this renderer */
|
|
32
|
+
abstract set physicsDebugViewActive(value: boolean);
|
|
29
33
|
protected constructor(scene: IVisualSceneComponent<D, R, VTypeDoc>, canvas?: HTMLCanvasElement | undefined, options?: Partial<RendererOptions>);
|
|
30
34
|
/**
|
|
31
35
|
* Renders the scene.
|
|
@@ -1,10 +1,6 @@
|
|
|
1
|
-
import { IDebugPhysicsDrawer } from '../../interfaces/i-debug-physics-drawer';
|
|
2
1
|
import { IComponent } from '../i-component';
|
|
3
2
|
import { VisualTypeDocRepo } from '../../gg-world';
|
|
4
3
|
export interface IVisualSceneComponent<D, R, TypeDoc extends VisualTypeDocRepo<D, R> = VisualTypeDocRepo<D, R>> extends IComponent {
|
|
5
4
|
readonly factory: TypeDoc['factory'];
|
|
6
|
-
readonly debugPhysicsDrawerClass?: {
|
|
7
|
-
new (): IDebugPhysicsDrawer<D, R, TypeDoc>;
|
|
8
|
-
};
|
|
9
5
|
init(): Promise<void>;
|
|
10
6
|
}
|
|
@@ -34,7 +34,7 @@ export declare abstract class IEntity<D = any, R = any, VTypeDoc extends VisualT
|
|
|
34
34
|
/**
|
|
35
35
|
* The flag whether entity should listen to ticks. If set to false, ticks will not be propagated to this entity
|
|
36
36
|
* */
|
|
37
|
-
protected
|
|
37
|
+
protected _selfActive: boolean;
|
|
38
38
|
get active(): boolean;
|
|
39
39
|
set active(value: boolean);
|
|
40
40
|
parent: IEntity | null;
|
|
@@ -26,7 +26,7 @@ export class IEntity {
|
|
|
26
26
|
/**
|
|
27
27
|
* The flag whether entity should listen to ticks. If set to false, ticks will not be propagated to this entity
|
|
28
28
|
* */
|
|
29
|
-
this.
|
|
29
|
+
this._selfActive = true;
|
|
30
30
|
this.parent = null;
|
|
31
31
|
this._children = [];
|
|
32
32
|
this._components = [];
|
|
@@ -43,10 +43,10 @@ export class IEntity {
|
|
|
43
43
|
this._name = value;
|
|
44
44
|
}
|
|
45
45
|
get active() {
|
|
46
|
-
return this.
|
|
46
|
+
return this._selfActive && (!this.parent || this.parent.active);
|
|
47
47
|
}
|
|
48
48
|
set active(value) {
|
|
49
|
-
this.
|
|
49
|
+
this._selfActive = value;
|
|
50
50
|
}
|
|
51
51
|
get children() {
|
|
52
52
|
return [...this._children];
|
|
@@ -23,6 +23,10 @@ export declare abstract class IRendererEntity<D, R, TypeDoc extends VisualTypeDo
|
|
|
23
23
|
*/
|
|
24
24
|
get rendererSize(): Point2 | null;
|
|
25
25
|
get rendererOptions(): RendererOptions;
|
|
26
|
+
/** get flag whether renderer shows physics debugger view */
|
|
27
|
+
get physicsDebugViewActive(): boolean;
|
|
28
|
+
/** turns on/off physics debugger view for this renderer */
|
|
29
|
+
set physicsDebugViewActive(value: boolean);
|
|
26
30
|
/**
|
|
27
31
|
Initializes a new instance of the BaseGgRenderer class.
|
|
28
32
|
* @param renderer
|
|
@@ -38,6 +38,14 @@ export class IRendererEntity extends IEntity {
|
|
|
38
38
|
get rendererOptions() {
|
|
39
39
|
return this.renderer.rendererOptions;
|
|
40
40
|
}
|
|
41
|
+
/** get flag whether renderer shows physics debugger view */
|
|
42
|
+
get physicsDebugViewActive() {
|
|
43
|
+
return this.renderer.physicsDebugViewActive;
|
|
44
|
+
}
|
|
45
|
+
/** turns on/off physics debugger view for this renderer */
|
|
46
|
+
set physicsDebugViewActive(value) {
|
|
47
|
+
this.renderer.physicsDebugViewActive = value;
|
|
48
|
+
}
|
|
41
49
|
onSpawned(world) {
|
|
42
50
|
this._rendererSize$.next(null);
|
|
43
51
|
if (this.rendererOptions.size == 'fullscreen' || typeof this.rendererOptions.size === 'function') {
|
package/dist/base/gg-world.d.ts
CHANGED
|
@@ -34,6 +34,4 @@ export declare abstract class GgWorld<D, R, VTypeDoc extends VisualTypeDocRepo<D
|
|
|
34
34
|
position?: D, rotation?: R, material?: unknown): IPositionable<D, R> & IRenderableEntity<D, R, VTypeDoc>;
|
|
35
35
|
addEntity(entity: IEntity): void;
|
|
36
36
|
removeEntity(entity: IEntity, dispose?: boolean): void;
|
|
37
|
-
get physicsDebugViewActive(): boolean;
|
|
38
|
-
set physicsDebugViewActive(value: boolean);
|
|
39
37
|
}
|
package/dist/base/gg-world.js
CHANGED
|
@@ -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 { GgGlobalClock, KeyboardInput, TickOrder, } from '../base';
|
|
10
|
+
import { GgGlobalClock, IRendererEntity, KeyboardInput, TickOrder, } from '../base';
|
|
11
11
|
export class GgWorld {
|
|
12
12
|
constructor(visualScene, physicsWorld) {
|
|
13
13
|
this.visualScene = visualScene;
|
|
@@ -30,13 +30,32 @@ export class GgWorld {
|
|
|
30
30
|
return '' + window.ggstatic.showStats;
|
|
31
31
|
}), 'args: [0 or 1]; turn on/off stats. Default value is 0');
|
|
32
32
|
window.ggstatic.registerConsoleCommand(this, 'ph_timescale', (...args) => __awaiter(this, void 0, void 0, function* () {
|
|
33
|
-
this.
|
|
34
|
-
return JSON.stringify(this.
|
|
33
|
+
this.worldClock.timeScale = +args[0];
|
|
34
|
+
return JSON.stringify(this.worldClock.timeScale);
|
|
35
35
|
}), 'args: [float]; change time scale of physics engine. Default value is 1.0');
|
|
36
|
+
window.ggstatic.registerConsoleCommand(this, 'ls_renderers', () => __awaiter(this, void 0, void 0, function* () {
|
|
37
|
+
return this.children
|
|
38
|
+
.filter(e => e instanceof IRendererEntity)
|
|
39
|
+
.map(r => r.name)
|
|
40
|
+
.join('\n');
|
|
41
|
+
}), 'no args; print all renderers in selected world');
|
|
36
42
|
window.ggstatic.registerConsoleCommand(this, 'dr_drawphysics', (...args) => __awaiter(this, void 0, void 0, function* () {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
43
|
+
const value = ['1', 'true', '+'].includes(args[0]);
|
|
44
|
+
const rendererName = args[1];
|
|
45
|
+
let renderer;
|
|
46
|
+
if (rendererName) {
|
|
47
|
+
renderer = this.children.find(x => x instanceof IRendererEntity && x.name === rendererName);
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
renderer = this.children.find(x => x instanceof IRendererEntity);
|
|
51
|
+
}
|
|
52
|
+
if (renderer) {
|
|
53
|
+
renderer.physicsDebugViewActive = value;
|
|
54
|
+
return '' + value;
|
|
55
|
+
}
|
|
56
|
+
return 'false';
|
|
57
|
+
}), 'args: [0 or 1] or [0 or 1, string]; turn on/off physics debug view. Second argument expects renderer ' +
|
|
58
|
+
'name, if not provided first renderer will be picked. Look up for renderer names using command "ls_renderers"');
|
|
40
59
|
}
|
|
41
60
|
}
|
|
42
61
|
static get documentWorlds() {
|
|
@@ -56,7 +75,7 @@ export class GgWorld {
|
|
|
56
75
|
this.tickListeners[i].tick$.next([elapsed, delta]);
|
|
57
76
|
}
|
|
58
77
|
}
|
|
59
|
-
// run
|
|
78
|
+
// run physics simulation
|
|
60
79
|
this.physicsWorld.simulate(delta);
|
|
61
80
|
// emit tick to all remained entities
|
|
62
81
|
for (i; i < this.tickListeners.length; i++) {
|
|
@@ -126,24 +145,6 @@ export class GgWorld {
|
|
|
126
145
|
entity.dispose();
|
|
127
146
|
}
|
|
128
147
|
}
|
|
129
|
-
get physicsDebugViewActive() {
|
|
130
|
-
return this.physicsWorld.physicsDebugViewActive;
|
|
131
|
-
}
|
|
132
|
-
set physicsDebugViewActive(value) {
|
|
133
|
-
if (this.physicsDebugViewActive === value) {
|
|
134
|
-
return;
|
|
135
|
-
}
|
|
136
|
-
if (value) {
|
|
137
|
-
const cls = this.visualScene.debugPhysicsDrawerClass;
|
|
138
|
-
if (!cls) {
|
|
139
|
-
throw new Error('Debug drawer is not available');
|
|
140
|
-
}
|
|
141
|
-
this.physicsWorld.startDebugger(this, new cls());
|
|
142
|
-
}
|
|
143
|
-
else {
|
|
144
|
-
this.physicsWorld.stopDebugger(this);
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
148
|
}
|
|
148
149
|
GgWorld.default_name_counter = 0;
|
|
149
150
|
GgWorld._documentWorlds = [];
|
package/dist/base/index.d.ts
CHANGED
|
@@ -21,7 +21,6 @@ export * from './inputs/direction.keyboard.input';
|
|
|
21
21
|
export * from './inputs/i-input';
|
|
22
22
|
export * from './inputs/keyboard.input';
|
|
23
23
|
export * from './inputs/mouse.input';
|
|
24
|
-
export * from './interfaces/i-debug-physics-drawer';
|
|
25
24
|
export * from './interfaces/i-positionable';
|
|
26
25
|
export * from './models/axis-directions';
|
|
27
26
|
export * from './models/body-options';
|
package/dist/base/index.js
CHANGED
|
@@ -21,7 +21,6 @@ export * from './inputs/direction.keyboard.input';
|
|
|
21
21
|
export * from './inputs/i-input';
|
|
22
22
|
export * from './inputs/keyboard.input';
|
|
23
23
|
export * from './inputs/mouse.input';
|
|
24
|
-
export * from './interfaces/i-debug-physics-drawer';
|
|
25
24
|
export * from './interfaces/i-positionable';
|
|
26
25
|
export * from './models/axis-directions';
|
|
27
26
|
export * from './models/body-options';
|
|
@@ -7,3 +7,12 @@ export interface BodyOptions {
|
|
|
7
7
|
ownCollisionGroups: CollisionGroup[] | 'all';
|
|
8
8
|
interactWithCollisionGroups: CollisionGroup[] | 'all';
|
|
9
9
|
}
|
|
10
|
+
export declare type DebugBodySettings = {
|
|
11
|
+
shape: any;
|
|
12
|
+
ignoreTransform?: boolean;
|
|
13
|
+
} & ({
|
|
14
|
+
type: 'RIGID_STATIC' | 'TRIGGER';
|
|
15
|
+
} | {
|
|
16
|
+
type: 'RIGID_DYNAMIC';
|
|
17
|
+
sleeping: boolean;
|
|
18
|
+
});
|
|
@@ -67,31 +67,39 @@ List of available commands: `.replace(/ /g, ' ') + `<span style="color:yell
|
|
|
67
67
|
};
|
|
68
68
|
document.getElementById('gg-console-close-icon').onmousedown = () => this.destroyUI();
|
|
69
69
|
this.elements.input.onkeydown = event => {
|
|
70
|
-
|
|
70
|
+
var _a;
|
|
71
|
+
if ((event === null || event === void 0 ? void 0 : event.code) === 'Enter') {
|
|
71
72
|
event.preventDefault();
|
|
72
73
|
this.onInput().then();
|
|
73
74
|
}
|
|
74
|
-
else if ((event === null || event === void 0 ? void 0 : event.
|
|
75
|
+
else if ((event === null || event === void 0 ? void 0 : event.code) === 'ArrowUp') {
|
|
75
76
|
event.preventDefault();
|
|
76
77
|
this.onUsePreviousCommand();
|
|
77
78
|
}
|
|
78
|
-
else if ((event === null || event === void 0 ? void 0 : event.
|
|
79
|
+
else if ((event === null || event === void 0 ? void 0 : event.code) === 'ArrowDown') {
|
|
79
80
|
event.preventDefault();
|
|
80
81
|
this.onUseNextCommand();
|
|
81
82
|
}
|
|
83
|
+
else if ((event === null || event === void 0 ? void 0 : event.code) === 'Backspace') {
|
|
84
|
+
let input = (_a = this.elements) === null || _a === void 0 ? void 0 : _a.input;
|
|
85
|
+
if (input) {
|
|
86
|
+
let value = input.value || '';
|
|
87
|
+
// backspace pressed while input had completion selected.
|
|
88
|
+
// Native logic will remove selected text (completion part), we remove one additional character
|
|
89
|
+
if ((input.selectionStart || value.length) < value.length && input.selectionEnd == value.length) {
|
|
90
|
+
this.elements.input.value = value.substring(0, input.selectionStart || value.length - 1);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
82
94
|
};
|
|
83
95
|
this.elements.input.oninput = event => {
|
|
84
96
|
var _a;
|
|
85
97
|
let value = ((_a = this.elements) === null || _a === void 0 ? void 0 : _a.input.value) || '';
|
|
86
|
-
// backspace
|
|
87
|
-
if (value.length > 0 && event.data === null) {
|
|
88
|
-
value = value.substring(0, value.length - 1);
|
|
89
|
-
}
|
|
90
98
|
if (value.trim() === '') {
|
|
91
99
|
return;
|
|
92
100
|
}
|
|
93
101
|
let autocompletion = window.ggstatic.availableCommands.find((c) => c[0].startsWith(value));
|
|
94
|
-
if (autocompletion) {
|
|
102
|
+
if (autocompletion && autocompletion[0].length > value.length) {
|
|
95
103
|
this.elements.input.value = autocompletion[0];
|
|
96
104
|
this.elements.input.setSelectionRange(value.length, this.elements.input.value.length);
|
|
97
105
|
}
|
|
@@ -6,6 +6,10 @@ export declare class GgDebuggerUI {
|
|
|
6
6
|
private currentWorld;
|
|
7
7
|
setShowStats(selectedWorld: GgWorld<any, any>, value: boolean): void;
|
|
8
8
|
private debugControlsRemoved$;
|
|
9
|
+
private viewUpdated$;
|
|
9
10
|
get showDebugControls(): boolean;
|
|
10
11
|
setShowDebugControls(selectedWorld: GgWorld<any, any>, value: boolean): void;
|
|
12
|
+
private snapshot;
|
|
13
|
+
private makeSnapshot;
|
|
14
|
+
private renderControls;
|
|
11
15
|
}
|
|
@@ -1,6 +1,22 @@
|
|
|
1
|
-
import { createInlineTickController } from '../base';
|
|
2
|
-
import { fromEvent, Subject, takeUntil } from 'rxjs';
|
|
1
|
+
import { createInlineTickController, IRendererEntity } from '../base';
|
|
2
|
+
import { animationFrameScheduler, fromEvent, of, Subject, takeUntil } from 'rxjs';
|
|
3
3
|
import Stats from 'stats.js';
|
|
4
|
+
import { repeat } from 'rxjs/operators';
|
|
5
|
+
const snapshotEqual = (a, b) => {
|
|
6
|
+
if (a.timeScale !== b.timeScale)
|
|
7
|
+
return false;
|
|
8
|
+
if (a.renderers.length !== b.renderers.length)
|
|
9
|
+
return false;
|
|
10
|
+
for (let i = 0; i < a.renderers.length; i++) {
|
|
11
|
+
if (a.renderers[i].name !== b.renderers[i].name)
|
|
12
|
+
return false;
|
|
13
|
+
if (a.renderers[i].entity !== b.renderers[i].entity)
|
|
14
|
+
return false;
|
|
15
|
+
if (a.renderers[i].physicsDebugViewActive !== b.renderers[i].physicsDebugViewActive)
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
return true;
|
|
19
|
+
};
|
|
4
20
|
export class GgDebuggerUI {
|
|
5
21
|
constructor() {
|
|
6
22
|
this.ui = {
|
|
@@ -10,6 +26,11 @@ export class GgDebuggerUI {
|
|
|
10
26
|
this.statsRemoved$ = new Subject();
|
|
11
27
|
this.currentWorld = null;
|
|
12
28
|
this.debugControlsRemoved$ = new Subject();
|
|
29
|
+
this.viewUpdated$ = new Subject();
|
|
30
|
+
this.snapshot = {
|
|
31
|
+
timeScale: 1,
|
|
32
|
+
renderers: [],
|
|
33
|
+
};
|
|
13
34
|
}
|
|
14
35
|
get showStats() {
|
|
15
36
|
return !!this.ui.stats;
|
|
@@ -64,48 +85,78 @@ export class GgDebuggerUI {
|
|
|
64
85
|
this.currentWorld = selectedWorld;
|
|
65
86
|
if (value) {
|
|
66
87
|
const debugControlsContainer = document.createElement('div');
|
|
88
|
+
document.body.appendChild(debugControlsContainer);
|
|
67
89
|
this.ui.debugControlsContainer = debugControlsContainer;
|
|
68
|
-
const debugLabelCss = "style='display:flex;align-items:center;margin:0.25rem;'";
|
|
69
90
|
debugControlsContainer.style.cssText =
|
|
70
91
|
'position:fixed;top:48px;right:0;opacity:0.9;z-index:9999;background-color:#333;color:white;display:flex;flex-direction:column';
|
|
71
|
-
|
|
92
|
+
this.snapshot = this.makeSnapshot();
|
|
93
|
+
this.renderControls(debugControlsContainer);
|
|
94
|
+
of(undefined, animationFrameScheduler)
|
|
95
|
+
.pipe(repeat(), takeUntil(this.debugControlsRemoved$))
|
|
96
|
+
.subscribe(() => {
|
|
97
|
+
const newSnapshot = this.makeSnapshot();
|
|
98
|
+
if (!snapshotEqual(this.snapshot, newSnapshot)) {
|
|
99
|
+
this.snapshot = newSnapshot;
|
|
100
|
+
this.renderControls(debugControlsContainer);
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
this.debugControlsRemoved$.next();
|
|
106
|
+
document.body.removeChild(this.ui.debugControlsContainer);
|
|
107
|
+
this.ui.debugControlsContainer = null;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
makeSnapshot() {
|
|
111
|
+
return {
|
|
112
|
+
timeScale: this.currentWorld.worldClock.timeScale,
|
|
113
|
+
renderers: this.currentWorld.children
|
|
114
|
+
.filter(x => x instanceof IRendererEntity)
|
|
115
|
+
.map(r => ({
|
|
116
|
+
name: r.name,
|
|
117
|
+
entity: r,
|
|
118
|
+
physicsDebugViewActive: r.physicsDebugViewActive,
|
|
119
|
+
})),
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
renderControls(debugControlsContainer) {
|
|
123
|
+
const debugLabelCss = "style='display:flex;align-items:center;margin:0.25rem;'";
|
|
124
|
+
let html = '';
|
|
125
|
+
for (const { entity, physicsDebugViewActive } of this.snapshot.renderers) {
|
|
126
|
+
html += `
|
|
72
127
|
<div ${debugLabelCss}>
|
|
73
|
-
<input type='checkbox' name='checkbox' id='
|
|
74
|
-
<label for='
|
|
128
|
+
<input type='checkbox' name='checkbox' id='physics_debugger_checkbox_id_${entity.name}' value='1'${physicsDebugViewActive ? ' checked' : ''}>
|
|
129
|
+
<label for='physics_debugger_checkbox_id_${entity.name}' style='user-select: none;'>Physics debugger${this.snapshot.renderers.length > 1 ? ' (' + entity.name + ')' : ''}</label>
|
|
75
130
|
</div>`;
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
131
|
+
}
|
|
132
|
+
html += `
|
|
133
|
+
<div ${debugLabelCss}>
|
|
134
|
+
<input id='time_scale_slider' type='range' min='0' max='5' step='0.01' style='flex-grow:1' value='${this.snapshot.timeScale}'/>
|
|
135
|
+
<label for='time_scale_slider' style='user-select: none;'>Time scale</label>
|
|
136
|
+
</div>`;
|
|
137
|
+
debugControlsContainer.innerHTML = html;
|
|
138
|
+
this.viewUpdated$.next();
|
|
139
|
+
for (const { entity } of this.snapshot.renderers) {
|
|
140
|
+
fromEvent(document.getElementById('physics_debugger_checkbox_id_' + entity.name), 'change')
|
|
141
|
+
.pipe(takeUntil(this.debugControlsRemoved$), takeUntil(this.viewUpdated$))
|
|
85
142
|
.subscribe(e => {
|
|
86
143
|
try {
|
|
87
|
-
|
|
144
|
+
entity.physicsDebugViewActive = e.target.checked;
|
|
88
145
|
}
|
|
89
146
|
catch (err) {
|
|
90
147
|
console.error(err);
|
|
91
148
|
}
|
|
92
|
-
e.target.checked = this.currentWorld.physicsDebugViewActive;
|
|
93
149
|
});
|
|
94
|
-
// fromEvent(document.getElementById('time_scale_slider')! as HTMLInputElement, 'change')
|
|
95
|
-
// .pipe(takeUntil(this.debugControlsRemoved$))
|
|
96
|
-
// .subscribe(e => {
|
|
97
|
-
// try {
|
|
98
|
-
// this.currentWorld.physicsWorld.timeScale = +(e.target as HTMLInputElement).value;
|
|
99
|
-
// } catch (err) {
|
|
100
|
-
// console.error(err);
|
|
101
|
-
// }
|
|
102
|
-
// (e.target as HTMLInputElement).value = '' + ( this.currentWorld.physicsWorld.timeScale || 1);
|
|
103
|
-
// });
|
|
104
|
-
}
|
|
105
|
-
else {
|
|
106
|
-
this.debugControlsRemoved$.next();
|
|
107
|
-
document.body.removeChild(this.ui.debugControlsContainer);
|
|
108
|
-
this.ui.debugControlsContainer = null;
|
|
109
150
|
}
|
|
151
|
+
fromEvent(document.getElementById('time_scale_slider'), 'change')
|
|
152
|
+
.pipe(takeUntil(this.debugControlsRemoved$), takeUntil(this.viewUpdated$))
|
|
153
|
+
.subscribe(e => {
|
|
154
|
+
try {
|
|
155
|
+
this.currentWorld.worldClock.timeScale = +e.target.value;
|
|
156
|
+
}
|
|
157
|
+
catch (err) {
|
|
158
|
+
console.error(err);
|
|
159
|
+
}
|
|
160
|
+
});
|
|
110
161
|
}
|
|
111
162
|
}
|
package/dist/dev/gg-static.d.ts
CHANGED
package/dist/dev/gg-static.js
CHANGED
|
@@ -51,10 +51,10 @@ export class GgStatic {
|
|
|
51
51
|
}), 'args: [string]; select world by name');
|
|
52
52
|
}
|
|
53
53
|
static get instance() {
|
|
54
|
-
if (!
|
|
55
|
-
|
|
54
|
+
if (!window.ggstatic) {
|
|
55
|
+
window.ggstatic = new GgStatic();
|
|
56
56
|
}
|
|
57
|
-
return
|
|
57
|
+
return window.ggstatic;
|
|
58
58
|
}
|
|
59
59
|
get devConsoleEnabled() {
|
|
60
60
|
return this._devConsoleEnabled;
|
|
@@ -138,4 +138,3 @@ export class GgStatic {
|
|
|
138
138
|
});
|
|
139
139
|
}
|
|
140
140
|
}
|
|
141
|
-
window.ggstatic = GgStatic.instance;
|
package/package.json
CHANGED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { IDisplayObjectComponent } from '../components/rendering/i-display-object.component';
|
|
2
|
-
import { Point3 } from '../models/points';
|
|
3
|
-
import { VisualTypeDocRepo } from '../gg-world';
|
|
4
|
-
export interface IDebugPhysicsDrawer<D, R, TypeDoc extends VisualTypeDocRepo<D, R> = VisualTypeDocRepo<D, R>> extends IDisplayObjectComponent<D, R, TypeDoc> {
|
|
5
|
-
drawContactPoint(point: D, normal: D, color?: Point3): void;
|
|
6
|
-
drawLine(from: D, to: D, color?: Point3): void;
|
|
7
|
-
update(): void;
|
|
8
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|