@gg-web-engine/core 0.0.56 → 0.0.58
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-physics-world-2d.component.d.ts +1 -1
- package/dist/2d/components/physics/i-rigid-body-2d.component.d.ts +1 -1
- package/dist/2d/components/physics/i-trigger-2d.component.d.ts +3 -3
- package/dist/2d/components/rendering/i-display-object-2d.component.d.ts +1 -1
- package/dist/2d/components/rendering/i-renderer-2d.component.d.ts +1 -1
- package/dist/2d/components/rendering/i-visual-scene-2d.component.d.ts +2 -2
- package/dist/2d/entities/controllers/entity-2d-positioning.animator.d.ts +2 -2
- package/dist/2d/entities/entity-2d.d.ts +7 -7
- package/dist/2d/entities/i-renderable-2d.entity.d.ts +4 -4
- package/dist/2d/entities/renderer-2d.entity.d.ts +1 -1
- package/dist/2d/entities/trigger-2d.entity.d.ts +8 -4
- package/dist/2d/factories.d.ts +7 -7
- package/dist/2d/gg-2d-world.d.ts +34 -6
- package/dist/2d/gg-2d-world.js +23 -19
- package/dist/2d/models/body-options.d.ts +4 -4
- package/dist/2d/models/body-options.js +6 -1
- package/dist/3d/components/physics/i-physics-world-3d.component.d.ts +5 -5
- package/dist/3d/components/physics/i-raycast-vehicle.component.d.ts +1 -1
- package/dist/3d/components/physics/i-rigid-body-3d.component.d.ts +1 -1
- package/dist/3d/components/physics/i-trigger-3d.component.d.ts +3 -3
- package/dist/3d/components/rendering/i-camera.component.d.ts +1 -1
- package/dist/3d/components/rendering/i-display-object-3d.component.d.ts +1 -1
- package/dist/3d/components/rendering/i-renderer-3d.component.d.ts +2 -2
- package/dist/3d/components/rendering/i-visual-scene-3d.component.d.ts +3 -3
- package/dist/3d/entities/controllers/animators/camera-3d.animator.d.ts +3 -3
- package/dist/3d/entities/controllers/animators/entity-3d-positioning.animator.d.ts +2 -2
- package/dist/3d/entities/entity-3d.d.ts +6 -6
- package/dist/3d/entities/gg-car/gg-car.entity.d.ts +5 -5
- package/dist/3d/entities/i-renderable-3d.entity.d.ts +4 -4
- package/dist/3d/entities/map-graph-3d.entity.d.ts +6 -6
- package/dist/3d/entities/raycast-vehicle-3d.entity.d.ts +3 -3
- package/dist/3d/entities/renderer-3d.entity.d.ts +2 -2
- package/dist/3d/entities/surface-following.entity.d.ts +96 -0
- package/dist/3d/entities/surface-following.entity.js +299 -0
- package/dist/3d/entities/trigger-3d.entity.d.ts +8 -4
- package/dist/3d/factories.d.ts +14 -14
- package/dist/3d/gg-3d-world.d.ts +35 -7
- package/dist/3d/gg-3d-world.js +23 -19
- package/dist/3d/index.d.ts +1 -0
- package/dist/3d/index.js +1 -0
- package/dist/3d/loader.d.ts +12 -12
- package/dist/3d/loader.js +6 -5
- package/dist/3d/loaders.d.ts +4 -4
- package/dist/3d/models/body-options.d.ts +4 -4
- package/dist/3d/models/body-options.js +6 -1
- package/dist/base/components/i-world-component.d.ts +5 -5
- package/dist/base/components/physics/i-body.component.d.ts +10 -10
- package/dist/base/components/physics/i-physics-world.component.d.ts +56 -10
- package/dist/base/components/physics/i-rigid-body.component.d.ts +2 -2
- package/dist/base/components/physics/i-trigger.component.d.ts +4 -4
- package/dist/base/components/rendering/i-display-object.component.d.ts +6 -6
- package/dist/base/components/rendering/i-renderer.component.d.ts +4 -4
- package/dist/base/components/rendering/i-visual-scene.component.d.ts +2 -2
- package/dist/base/data-structures/bitmask.d.ts +5 -4
- package/dist/base/data-structures/bitmask.js +4 -3
- package/dist/base/entities/controllers/animation-mixer.d.ts +3 -3
- package/dist/base/entities/i-entity.d.ts +8 -8
- package/dist/base/entities/i-renderable.entity.d.ts +2 -2
- package/dist/base/entities/i-renderer.entity.d.ts +5 -5
- package/dist/base/gg-world.d.ts +31 -6
- package/dist/base/gg-world.js +27 -14
- package/dist/base/index.d.ts +1 -0
- package/dist/base/index.js +1 -0
- package/dist/base/math/numbers.d.ts +2 -1
- package/dist/base/math/numbers.js +7 -1
- package/dist/base/math/point2.d.ts +19 -1
- package/dist/base/math/point2.js +41 -3
- package/dist/base/math/point3.d.ts +4 -0
- package/dist/base/math/point3.js +20 -3
- package/dist/base/models/body-options.d.ts +27 -9
- package/dist/base/models/body-options.js +65 -1
- package/dist/base/models/points.d.ts +20 -16
- package/dist/base/models/raycasting.d.ts +52 -0
- package/dist/base/models/raycasting.js +1 -0
- package/dist/dev/gg-debugger.ui.js +5 -13
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { BodyOptions, IEntity, Point3, Point4 } from '../../base';
|
|
2
|
+
import { Gg3dWorld, Gg3dWorldTypeDocPPatch, PhysicsTypeDocRepo3D } from '../gg-3d-world';
|
|
3
|
+
import { Shape3DDescriptor } from '../models/shapes';
|
|
4
|
+
/**
|
|
5
|
+
* Represents a function that calculates the surface position and normal
|
|
6
|
+
* for a given point in 3D space.
|
|
7
|
+
*/
|
|
8
|
+
export type SurfaceFollowFunc = (p: Point3) => {
|
|
9
|
+
position: Point3;
|
|
10
|
+
normal: Point3;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Represents an entity that follows a surface dynamically by adjusting
|
|
14
|
+
* its position and orientation based on a given surface function.
|
|
15
|
+
*
|
|
16
|
+
* @template PTypeDoc - The physics type document repository.
|
|
17
|
+
*/
|
|
18
|
+
export declare class SurfaceFollowingEntity<PTypeDoc extends PhysicsTypeDocRepo3D = PhysicsTypeDocRepo3D> extends IEntity<Point3, Point4, Gg3dWorldTypeDocPPatch<PTypeDoc>> {
|
|
19
|
+
/** Function that determines surface position and normal. */
|
|
20
|
+
followFunc: SurfaceFollowFunc;
|
|
21
|
+
/** Optional body configuration. */
|
|
22
|
+
protected bodyOptions: Partial<Omit<BodyOptions, 'dynamic' | 'mass' | 'ownCollisionGroups' | 'interactWithCollisionGroups'>>;
|
|
23
|
+
/**
|
|
24
|
+
* Determines the execution order for physics simulation.
|
|
25
|
+
*/
|
|
26
|
+
readonly tickOrder: number;
|
|
27
|
+
/**
|
|
28
|
+
* Debugging settings for the surface-following entity.
|
|
29
|
+
*/
|
|
30
|
+
readonly debugBodySettings: SurfaceFollowingEntityDebugSettings;
|
|
31
|
+
constructor(
|
|
32
|
+
/** Function that determines surface position and normal. */
|
|
33
|
+
followFunc: SurfaceFollowFunc,
|
|
34
|
+
/** Optional body configuration. */
|
|
35
|
+
bodyOptions?: Partial<Omit<BodyOptions, 'dynamic' | 'mass' | 'ownCollisionGroups' | 'interactWithCollisionGroups'>>);
|
|
36
|
+
/**
|
|
37
|
+
* Stores colliders and their associated metadata.
|
|
38
|
+
*/
|
|
39
|
+
private colliders;
|
|
40
|
+
/**
|
|
41
|
+
* Sets up a collider by assigning it a collision group and a dynamic plane.
|
|
42
|
+
*
|
|
43
|
+
* @param collider - The physics rigid body to configure.
|
|
44
|
+
*/
|
|
45
|
+
private setupCollider;
|
|
46
|
+
/**
|
|
47
|
+
* Adds a collider to the entity, registering it immediately if the entity
|
|
48
|
+
* is already in a world.
|
|
49
|
+
*
|
|
50
|
+
* @param collider - The physics rigid body to add.
|
|
51
|
+
*/
|
|
52
|
+
addCollider(collider: PTypeDoc['rigidBody']): void;
|
|
53
|
+
/**
|
|
54
|
+
* Removes a collider and deregisters its associated collision group.
|
|
55
|
+
*
|
|
56
|
+
* @param collider - The physics rigid body to remove.
|
|
57
|
+
*/
|
|
58
|
+
removeCollider(collider: PTypeDoc['rigidBody']): void;
|
|
59
|
+
/**
|
|
60
|
+
* Called when the entity is added to a world.
|
|
61
|
+
*
|
|
62
|
+
* @param world - The game world instance.
|
|
63
|
+
*/
|
|
64
|
+
onSpawned(world: Gg3dWorld<Gg3dWorldTypeDocPPatch<PTypeDoc>>): void;
|
|
65
|
+
private customGlobalDebugDummyBody;
|
|
66
|
+
/**
|
|
67
|
+
* Updates debug visualization if active.
|
|
68
|
+
*/
|
|
69
|
+
private updateDebugView;
|
|
70
|
+
/**
|
|
71
|
+
* Called when the entity is removed from the world.
|
|
72
|
+
*/
|
|
73
|
+
onRemoved(): void;
|
|
74
|
+
/**
|
|
75
|
+
* Positions planes based on the surface-follow function.
|
|
76
|
+
*/
|
|
77
|
+
protected positionPlanes(): void;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Stores debug settings for a SurfaceFollowingEntity, allowing customization
|
|
81
|
+
* of the debug mesh.
|
|
82
|
+
*/
|
|
83
|
+
export declare class SurfaceFollowingEntityDebugSettings {
|
|
84
|
+
private _hexMeshStepDistance;
|
|
85
|
+
private _hexMeshDepth;
|
|
86
|
+
private _customGlobalShape;
|
|
87
|
+
private _revision;
|
|
88
|
+
get revision(): number;
|
|
89
|
+
get hexMeshStepDistance(): number;
|
|
90
|
+
set hexMeshStepDistance(value: number);
|
|
91
|
+
get hexMeshDepth(): number;
|
|
92
|
+
set hexMeshDepth(value: number);
|
|
93
|
+
get customGlobalShape(): Shape3DDescriptor | null;
|
|
94
|
+
set customGlobalShape(value: Shape3DDescriptor | null);
|
|
95
|
+
constructor(_hexMeshStepDistance?: number, _hexMeshDepth?: number, _customGlobalShape?: Shape3DDescriptor | null);
|
|
96
|
+
}
|
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
import { takeUntil } from 'rxjs';
|
|
2
|
+
import { IEntity, Pnt2, Pnt3, Qtrn, TickOrder } from '../../base';
|
|
3
|
+
/**
|
|
4
|
+
* Represents an entity that follows a surface dynamically by adjusting
|
|
5
|
+
* its position and orientation based on a given surface function.
|
|
6
|
+
*
|
|
7
|
+
* @template PTypeDoc - The physics type document repository.
|
|
8
|
+
*/
|
|
9
|
+
export class SurfaceFollowingEntity extends IEntity {
|
|
10
|
+
constructor(
|
|
11
|
+
/** Function that determines surface position and normal. */
|
|
12
|
+
followFunc,
|
|
13
|
+
/** Optional body configuration. */
|
|
14
|
+
bodyOptions = {}) {
|
|
15
|
+
super();
|
|
16
|
+
this.followFunc = followFunc;
|
|
17
|
+
this.bodyOptions = bodyOptions;
|
|
18
|
+
/**
|
|
19
|
+
* Determines the execution order for physics simulation.
|
|
20
|
+
*/
|
|
21
|
+
this.tickOrder = TickOrder.PHYSICS_SIMULATION - 1;
|
|
22
|
+
/**
|
|
23
|
+
* Debugging settings for the surface-following entity.
|
|
24
|
+
*/
|
|
25
|
+
this.debugBodySettings = new SurfaceFollowingEntityDebugSettings();
|
|
26
|
+
/**
|
|
27
|
+
* Stores colliders and their associated metadata.
|
|
28
|
+
*/
|
|
29
|
+
this.colliders = new Map();
|
|
30
|
+
this.customGlobalDebugDummyBody = null;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Sets up a collider by assigning it a collision group and a dynamic plane.
|
|
34
|
+
*
|
|
35
|
+
* @param collider - The physics rigid body to configure.
|
|
36
|
+
*/
|
|
37
|
+
setupCollider(collider) {
|
|
38
|
+
if (!this.world) {
|
|
39
|
+
throw new Error('Cannot setup collider if not added to the world');
|
|
40
|
+
}
|
|
41
|
+
let cg = this.world.physicsWorld.registerCollisionGroup();
|
|
42
|
+
collider.ownCollisionGroups = [...collider.ownCollisionGroups, cg];
|
|
43
|
+
collider.interactWithCollisionGroups = [...collider.ownCollisionGroups, cg];
|
|
44
|
+
let plane = this.world.physicsWorld.factory.createRigidBody({
|
|
45
|
+
shape: { shape: 'PLANE' },
|
|
46
|
+
body: Object.assign(Object.assign({}, this.bodyOptions), { dynamic: false, ownCollisionGroups: [cg], interactWithCollisionGroups: [cg] }),
|
|
47
|
+
});
|
|
48
|
+
if (this.debugBodySettings.customGlobalShape) {
|
|
49
|
+
plane.debugBodySettings.shape = { shape: 'SPHERE', radius: 0.25 };
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
plane.debugBodySettings.ignoreTransform = true;
|
|
53
|
+
}
|
|
54
|
+
this.addComponents(plane);
|
|
55
|
+
this.colliders.set(collider, [cg, plane, {}]);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Adds a collider to the entity, registering it immediately if the entity
|
|
59
|
+
* is already in a world.
|
|
60
|
+
*
|
|
61
|
+
* @param collider - The physics rigid body to add.
|
|
62
|
+
*/
|
|
63
|
+
addCollider(collider) {
|
|
64
|
+
if (this.world) {
|
|
65
|
+
this.setupCollider(collider);
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
this.colliders.set(collider, null);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Removes a collider and deregisters its associated collision group.
|
|
73
|
+
*
|
|
74
|
+
* @param collider - The physics rigid body to remove.
|
|
75
|
+
*/
|
|
76
|
+
removeCollider(collider) {
|
|
77
|
+
if (!this.colliders.has(collider)) {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
const item = this.colliders.get(collider);
|
|
81
|
+
if (item) {
|
|
82
|
+
const [cg, plane] = item;
|
|
83
|
+
this.removeComponents([plane], true);
|
|
84
|
+
collider.ownCollisionGroups = collider.ownCollisionGroups.filter(g => g !== cg);
|
|
85
|
+
collider.interactWithCollisionGroups = collider.interactWithCollisionGroups.filter(g => g !== cg);
|
|
86
|
+
this.world.physicsWorld.deregisterCollisionGroup(cg);
|
|
87
|
+
}
|
|
88
|
+
this.colliders.delete(collider);
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Called when the entity is added to a world.
|
|
92
|
+
*
|
|
93
|
+
* @param world - The game world instance.
|
|
94
|
+
*/
|
|
95
|
+
onSpawned(world) {
|
|
96
|
+
if (!world.physicsWorld) {
|
|
97
|
+
throw new Error('Cannot add surface following entity to the world without physics');
|
|
98
|
+
}
|
|
99
|
+
super.onSpawned(world);
|
|
100
|
+
for (const [collider] of this.colliders.entries()) {
|
|
101
|
+
this.setupCollider(collider);
|
|
102
|
+
}
|
|
103
|
+
world.physicsWorld.removed$.pipe(takeUntil(this.onRemoved$)).subscribe(c => {
|
|
104
|
+
if (this.colliders.has(c)) {
|
|
105
|
+
this.removeCollider(c);
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
this.tick$.pipe(takeUntil(this.onRemoved$)).subscribe(() => {
|
|
109
|
+
this.positionPlanes();
|
|
110
|
+
this.updateDebugView();
|
|
111
|
+
});
|
|
112
|
+
this.positionPlanes();
|
|
113
|
+
this.updateDebugView();
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Updates debug visualization if active.
|
|
117
|
+
*/
|
|
118
|
+
updateDebugView() {
|
|
119
|
+
const updateDebugView = !!this.world.renderers.find(r => r.physicsDebugViewActive);
|
|
120
|
+
if (updateDebugView) {
|
|
121
|
+
if (this.debugBodySettings.customGlobalShape) {
|
|
122
|
+
if (!this.customGlobalDebugDummyBody) {
|
|
123
|
+
this.customGlobalDebugDummyBody = this.world.physicsWorld.factory.createRigidBody({
|
|
124
|
+
shape: { shape: 'BOX', dimensions: Pnt3.O },
|
|
125
|
+
body: { dynamic: false },
|
|
126
|
+
});
|
|
127
|
+
this.customGlobalDebugDummyBody.ownCollisionGroups = [];
|
|
128
|
+
this.customGlobalDebugDummyBody.interactWithCollisionGroups = [];
|
|
129
|
+
this.customGlobalDebugDummyBody.debugBodySettings.type = { type: 'RIGID_STATIC' };
|
|
130
|
+
this.customGlobalDebugDummyBody.debugBodySettings.shape = this.debugBodySettings.customGlobalShape;
|
|
131
|
+
this.addComponents(this.customGlobalDebugDummyBody);
|
|
132
|
+
for (const item of this.colliders.values()) {
|
|
133
|
+
if (item) {
|
|
134
|
+
let [_, plane] = item;
|
|
135
|
+
plane.debugBodySettings.shape = { shape: 'SPHERE', radius: 0.25 };
|
|
136
|
+
plane.debugBodySettings.ignoreTransform = false;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
this.customGlobalDebugDummyBody.debugBodySettings.shape = this.debugBodySettings.customGlobalShape;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
if (this.customGlobalDebugDummyBody) {
|
|
146
|
+
this.removeComponents([this.customGlobalDebugDummyBody], true);
|
|
147
|
+
this.customGlobalDebugDummyBody = null;
|
|
148
|
+
// reset caches
|
|
149
|
+
for (const item of this.colliders.values()) {
|
|
150
|
+
if (item) {
|
|
151
|
+
item[2] = {};
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
for (const [collider, item] of this.colliders.entries()) {
|
|
156
|
+
let [_, plane, debugCache] = item;
|
|
157
|
+
const { position, normal } = this.followFunc(collider.position);
|
|
158
|
+
let xThreshold = this.debugBodySettings.hexMeshStepDistance;
|
|
159
|
+
let yThreshold = this.debugBodySettings.hexMeshStepDistance * Math.sqrt(3);
|
|
160
|
+
let zThreshold = this.debugBodySettings.hexMeshStepDistance * 2;
|
|
161
|
+
let hexMeshStartPosition = {
|
|
162
|
+
x: Math.round(position.x / xThreshold) * xThreshold,
|
|
163
|
+
y: Math.round(position.y / yThreshold) * yThreshold,
|
|
164
|
+
z: Math.round(position.z / zThreshold) * zThreshold,
|
|
165
|
+
};
|
|
166
|
+
if (debugCache.lastDebugSettingsRev != this.debugBodySettings.revision ||
|
|
167
|
+
!debugCache.lastDebugStartPos ||
|
|
168
|
+
Pnt3.dist(debugCache.lastDebugStartPos, hexMeshStartPosition) > 1) {
|
|
169
|
+
let { vertices, faces } = buildHexMeshAlongSurface(hexMeshStartPosition, this.followFunc, this.debugBodySettings.hexMeshDepth, this.debugBodySettings.hexMeshStepDistance);
|
|
170
|
+
plane.debugBodySettings.shape = {
|
|
171
|
+
shape: 'MESH',
|
|
172
|
+
vertices,
|
|
173
|
+
faces,
|
|
174
|
+
};
|
|
175
|
+
plane.debugBodySettings.ignoreTransform = true;
|
|
176
|
+
debugCache.lastDebugStartPos = hexMeshStartPosition;
|
|
177
|
+
debugCache.lastDebugSettingsRev = this.debugBodySettings.revision;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Called when the entity is removed from the world.
|
|
185
|
+
*/
|
|
186
|
+
onRemoved() {
|
|
187
|
+
for (const [collider, item] of this.colliders) {
|
|
188
|
+
if (item) {
|
|
189
|
+
const [cg, plane] = item;
|
|
190
|
+
this.removeComponents([plane], true);
|
|
191
|
+
collider.ownCollisionGroups = collider.ownCollisionGroups.filter(g => g !== cg);
|
|
192
|
+
collider.interactWithCollisionGroups = collider.interactWithCollisionGroups.filter(g => g !== cg);
|
|
193
|
+
this.world.physicsWorld.deregisterCollisionGroup(cg);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
this.colliders.clear();
|
|
197
|
+
super.onRemoved();
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Positions planes based on the surface-follow function.
|
|
201
|
+
*/
|
|
202
|
+
positionPlanes() {
|
|
203
|
+
if (!this.world) {
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
for (const [collider, item] of this.colliders.entries()) {
|
|
207
|
+
let [_, plane] = item;
|
|
208
|
+
const { position, normal } = this.followFunc(collider.position);
|
|
209
|
+
plane.position = position;
|
|
210
|
+
plane.rotation = Qtrn.lookAt(normal, Pnt3.O);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Stores debug settings for a SurfaceFollowingEntity, allowing customization
|
|
216
|
+
* of the debug mesh.
|
|
217
|
+
*/
|
|
218
|
+
export class SurfaceFollowingEntityDebugSettings {
|
|
219
|
+
get revision() {
|
|
220
|
+
return this._revision;
|
|
221
|
+
}
|
|
222
|
+
get hexMeshStepDistance() {
|
|
223
|
+
return this._hexMeshStepDistance;
|
|
224
|
+
}
|
|
225
|
+
set hexMeshStepDistance(value) {
|
|
226
|
+
this._hexMeshStepDistance = value;
|
|
227
|
+
this._revision++;
|
|
228
|
+
}
|
|
229
|
+
get hexMeshDepth() {
|
|
230
|
+
return this._hexMeshDepth;
|
|
231
|
+
}
|
|
232
|
+
set hexMeshDepth(value) {
|
|
233
|
+
this._hexMeshDepth = value;
|
|
234
|
+
this._revision++;
|
|
235
|
+
}
|
|
236
|
+
get customGlobalShape() {
|
|
237
|
+
return this._customGlobalShape;
|
|
238
|
+
}
|
|
239
|
+
set customGlobalShape(value) {
|
|
240
|
+
this._customGlobalShape = value;
|
|
241
|
+
this._revision++;
|
|
242
|
+
}
|
|
243
|
+
constructor(_hexMeshStepDistance = 4, _hexMeshDepth = 6, _customGlobalShape = null) {
|
|
244
|
+
this._hexMeshStepDistance = _hexMeshStepDistance;
|
|
245
|
+
this._hexMeshDepth = _hexMeshDepth;
|
|
246
|
+
this._customGlobalShape = _customGlobalShape;
|
|
247
|
+
this._revision = 0;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
const buildHexMeshAlongSurface = (start, surfaceFunc, depth, stepDistance) => {
|
|
251
|
+
let startPoint = surfaceFunc(start);
|
|
252
|
+
const vertices = [startPoint.position];
|
|
253
|
+
const faces = [];
|
|
254
|
+
let lastLoop = [
|
|
255
|
+
{
|
|
256
|
+
position: startPoint.position,
|
|
257
|
+
normal: startPoint.normal,
|
|
258
|
+
vertexIndex: 0,
|
|
259
|
+
},
|
|
260
|
+
];
|
|
261
|
+
const traverse = (point, angle) => {
|
|
262
|
+
let pnt2 = Pnt2.rot(Pnt2.scalarMult(Pnt2.X, stepDistance), angle);
|
|
263
|
+
let snorm = Pnt3.toSpherical(point.normal);
|
|
264
|
+
let spnt = Pnt3.toSpherical(Object.assign(Object.assign({}, pnt2), { z: 0 }));
|
|
265
|
+
return Pnt3.add(point.position, Pnt3.fromSpherical(Object.assign(Object.assign({}, spnt), { phi: spnt.phi + Math.cos(snorm.theta - spnt.theta) * snorm.phi })));
|
|
266
|
+
};
|
|
267
|
+
for (let i = 0; i < depth; i++) {
|
|
268
|
+
let newLoop = [];
|
|
269
|
+
if (i == 0) {
|
|
270
|
+
for (let j = 0; j < 6; j++) {
|
|
271
|
+
let point = surfaceFunc(traverse(startPoint, (j * Math.PI) / 3));
|
|
272
|
+
newLoop.push(Object.assign(Object.assign({}, point), { vertexIndex: j + 1 }));
|
|
273
|
+
faces.push([0, j + 1, j < 5 ? j + 2 : 1]);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
else {
|
|
277
|
+
for (let j = 0; j < lastLoop.length; j++) {
|
|
278
|
+
let startPoint = lastLoop[j];
|
|
279
|
+
let angle = (Math.floor((j * 6) / lastLoop.length) * Math.PI) / 3;
|
|
280
|
+
let rightNeighbour = lastLoop[j < lastLoop.length - 1 ? j + 1 : 0];
|
|
281
|
+
if (j % (lastLoop.length / 6) == 0) {
|
|
282
|
+
// hex corner vertex, add new vertex in this loop. Each next loop has +6 vertices
|
|
283
|
+
let pointF = surfaceFunc(traverse(startPoint, angle));
|
|
284
|
+
let vi = vertices.length + newLoop.length;
|
|
285
|
+
newLoop.push(Object.assign(Object.assign({}, pointF), { vertexIndex: vi }));
|
|
286
|
+
faces.push([startPoint.vertexIndex, j > 0 ? vi - 1 : vi + lastLoop.length + 5, vi]);
|
|
287
|
+
}
|
|
288
|
+
let pointR = surfaceFunc(Pnt3.avg(traverse(startPoint, angle + Math.PI / 3), traverse(rightNeighbour, angle)));
|
|
289
|
+
let vi = vertices.length + newLoop.length;
|
|
290
|
+
newLoop.push(Object.assign(Object.assign({}, pointR), { vertexIndex: vi }));
|
|
291
|
+
faces.push([startPoint.vertexIndex, vi - 1, vi]);
|
|
292
|
+
faces.push([rightNeighbour.vertexIndex, startPoint.vertexIndex, vi]);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
vertices.push(...newLoop.map(({ position }) => position));
|
|
296
|
+
lastLoop = newLoop;
|
|
297
|
+
}
|
|
298
|
+
return { vertices, faces };
|
|
299
|
+
};
|
|
@@ -2,12 +2,16 @@ import { Observable } from 'rxjs';
|
|
|
2
2
|
import { ITrigger3dComponent } from '../components/physics/i-trigger-3d.component';
|
|
3
3
|
import { IPositionable3d } from '../interfaces/i-positionable-3d';
|
|
4
4
|
import { IEntity, Point3, Point4, TickOrder } from '../../base';
|
|
5
|
-
import {
|
|
6
|
-
export declare class Trigger3dEntity<
|
|
5
|
+
import { Gg3dWorldTypeDocPPatch, Gg3dWorldTypeDocRepo, PhysicsTypeDocRepo3D } from '../gg-3d-world';
|
|
6
|
+
export declare class Trigger3dEntity<PTypeDoc extends PhysicsTypeDocRepo3D = PhysicsTypeDocRepo3D> extends IEntity<Point3, Point4, Gg3dWorldTypeDocPPatch<PTypeDoc>> implements IPositionable3d {
|
|
7
7
|
readonly objectBody: ITrigger3dComponent;
|
|
8
8
|
readonly tickOrder = TickOrder.OBJECTS_BINDING;
|
|
9
|
-
get onEntityEntered(): Observable<IEntity<Point3, Point4,
|
|
10
|
-
|
|
9
|
+
get onEntityEntered(): Observable<IEntity<Point3, Point4, Gg3dWorldTypeDocRepo & {
|
|
10
|
+
pTypeDoc: PTypeDoc;
|
|
11
|
+
}> & IPositionable3d>;
|
|
12
|
+
get onEntityLeft(): Observable<(IEntity<Point3, Point4, Gg3dWorldTypeDocRepo & {
|
|
13
|
+
pTypeDoc: PTypeDoc;
|
|
14
|
+
}> & IPositionable3d) | null>;
|
|
11
15
|
private _position;
|
|
12
16
|
get position(): Point3;
|
|
13
17
|
set position(value: Point3);
|
package/dist/3d/factories.d.ts
CHANGED
|
@@ -8,32 +8,32 @@ export type DisplayObject3dOpts<Tex> = {
|
|
|
8
8
|
castShadow?: boolean;
|
|
9
9
|
receiveShadow?: boolean;
|
|
10
10
|
};
|
|
11
|
-
export declare abstract class IDisplayObject3dComponentFactory<
|
|
12
|
-
abstract createPrimitive(descriptor: Shape3DMeshDescriptor, material?: DisplayObject3dOpts<
|
|
13
|
-
abstract createPerspectiveCamera(settings
|
|
11
|
+
export declare abstract class IDisplayObject3dComponentFactory<VTypeDoc extends VisualTypeDocRepo3D = VisualTypeDocRepo3D> {
|
|
12
|
+
abstract createPrimitive(descriptor: Shape3DMeshDescriptor, material?: DisplayObject3dOpts<VTypeDoc['texture']>): VTypeDoc['displayObject'];
|
|
13
|
+
abstract createPerspectiveCamera(settings?: {
|
|
14
14
|
fov?: number;
|
|
15
15
|
aspectRatio?: number;
|
|
16
16
|
frustrum?: {
|
|
17
17
|
near: number;
|
|
18
18
|
far: number;
|
|
19
19
|
};
|
|
20
|
-
}):
|
|
20
|
+
}): VTypeDoc['camera'];
|
|
21
21
|
randomColor(): number;
|
|
22
|
-
createPlane(material?: DisplayObject3dOpts<
|
|
23
|
-
createBox(dimensions: Point3, material?: DisplayObject3dOpts<
|
|
24
|
-
createCapsule(radius: number, centersDistance: number, material?: DisplayObject3dOpts<
|
|
25
|
-
createCylinder(radius: number, height: number, material?: DisplayObject3dOpts<
|
|
26
|
-
createCone(radius: number, height: number, material?: DisplayObject3dOpts<
|
|
27
|
-
createSphere(radius: number, material?: DisplayObject3dOpts<
|
|
22
|
+
createPlane(material?: DisplayObject3dOpts<VTypeDoc['texture']>): VTypeDoc['displayObject'];
|
|
23
|
+
createBox(dimensions: Point3, material?: DisplayObject3dOpts<VTypeDoc['texture']>): VTypeDoc['displayObject'];
|
|
24
|
+
createCapsule(radius: number, centersDistance: number, material?: DisplayObject3dOpts<VTypeDoc['texture']>): VTypeDoc['displayObject'];
|
|
25
|
+
createCylinder(radius: number, height: number, material?: DisplayObject3dOpts<VTypeDoc['texture']>): VTypeDoc['displayObject'];
|
|
26
|
+
createCone(radius: number, height: number, material?: DisplayObject3dOpts<VTypeDoc['texture']>): VTypeDoc['displayObject'];
|
|
27
|
+
createSphere(radius: number, material?: DisplayObject3dOpts<VTypeDoc['texture']>): VTypeDoc['displayObject'];
|
|
28
28
|
}
|
|
29
|
-
export interface IPhysicsBody3dComponentFactory<
|
|
29
|
+
export interface IPhysicsBody3dComponentFactory<PTypeDoc extends PhysicsTypeDocRepo3D = PhysicsTypeDocRepo3D> {
|
|
30
30
|
createRigidBody(descriptor: BodyShape3DDescriptor, transform?: {
|
|
31
31
|
position?: Point3;
|
|
32
32
|
rotation?: Point4;
|
|
33
|
-
}):
|
|
33
|
+
}): PTypeDoc['rigidBody'];
|
|
34
34
|
createTrigger(descriptor: Shape3DDescriptor, transform?: {
|
|
35
35
|
position?: Point3;
|
|
36
36
|
rotation?: Point4;
|
|
37
|
-
}):
|
|
38
|
-
createRaycastVehicle(chassis:
|
|
37
|
+
}): PTypeDoc['trigger'];
|
|
38
|
+
createRaycastVehicle(chassis: PTypeDoc['rigidBody']): PTypeDoc['raycastVehicle'];
|
|
39
39
|
}
|
package/dist/3d/gg-3d-world.d.ts
CHANGED
|
@@ -29,13 +29,41 @@ export type PhysicsTypeDocRepo3D = {
|
|
|
29
29
|
trigger: ITrigger3dComponent;
|
|
30
30
|
raycastVehicle: IRaycastVehicleComponent;
|
|
31
31
|
};
|
|
32
|
-
export
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
32
|
+
export type Gg3dWorldTypeDocRepo = {
|
|
33
|
+
vTypeDoc: VisualTypeDocRepo3D;
|
|
34
|
+
pTypeDoc: PhysicsTypeDocRepo3D;
|
|
35
|
+
};
|
|
36
|
+
export type Gg3dWorldTypeDocVPatch<VTypeDoc extends VisualTypeDocRepo3D> = Omit<Gg3dWorldTypeDocRepo, 'vTypeDoc'> & {
|
|
37
|
+
vTypeDoc: VTypeDoc;
|
|
38
|
+
};
|
|
39
|
+
export type Gg3dWorldTypeDocPPatch<PTypeDoc extends PhysicsTypeDocRepo3D> = Omit<Gg3dWorldTypeDocRepo, 'pTypeDoc'> & {
|
|
40
|
+
pTypeDoc: PTypeDoc;
|
|
41
|
+
};
|
|
42
|
+
export type Gg3dWorldSceneTypeRepo<TypeDoc extends Gg3dWorldTypeDocRepo = Gg3dWorldTypeDocRepo> = {
|
|
43
|
+
visualScene: IVisualScene3dComponent<TypeDoc['vTypeDoc']> | null;
|
|
44
|
+
physicsWorld: IPhysicsWorld3dComponent<TypeDoc['pTypeDoc']> | null;
|
|
45
|
+
};
|
|
46
|
+
export type Gg3dWorldSceneTypeDocVPatch<VTypeDoc extends VisualTypeDocRepo3D, VS extends IVisualScene3dComponent<VTypeDoc> | null> = Omit<Gg3dWorldSceneTypeRepo, 'visualScene'> & {
|
|
47
|
+
visualScene: VS;
|
|
48
|
+
};
|
|
49
|
+
export type Gg3dWorldSceneTypeDocPPatch<PTypeDoc extends PhysicsTypeDocRepo3D, PW extends IPhysicsWorld3dComponent<PTypeDoc> | null> = Omit<Gg3dWorldSceneTypeRepo, 'physicsWorld'> & {
|
|
50
|
+
physicsWorld: PW;
|
|
51
|
+
};
|
|
52
|
+
export type TypedGg3dWorld<VW extends Gg3dWorld<any> | null, PW extends Gg3dWorld<any> | null> = VW extends Gg3dWorld<infer VTD, infer VSTD> | null ? PW extends Gg3dWorld<infer PTD, infer PSTD> | null ? Gg3dWorld<{
|
|
53
|
+
vTypeDoc: VTD['vTypeDoc'];
|
|
54
|
+
pTypeDoc: PTD['pTypeDoc'];
|
|
55
|
+
}, {
|
|
56
|
+
visualScene: VSTD['visualScene'];
|
|
57
|
+
physicsWorld: PSTD['physicsWorld'];
|
|
58
|
+
}> : never : never;
|
|
59
|
+
export declare class Gg3dWorld<TypeDoc extends Gg3dWorldTypeDocRepo = Gg3dWorldTypeDocRepo, SceneTypeDoc extends Gg3dWorldSceneTypeRepo<TypeDoc> = Gg3dWorldSceneTypeRepo<TypeDoc>> extends GgWorld<Point3, Point4, TypeDoc, SceneTypeDoc> {
|
|
60
|
+
readonly loader: Gg3dLoader<TypeDoc>;
|
|
61
|
+
constructor(args: {
|
|
62
|
+
visualScene?: SceneTypeDoc['visualScene'];
|
|
63
|
+
physicsWorld?: SceneTypeDoc['physicsWorld'];
|
|
64
|
+
});
|
|
65
|
+
addPrimitiveRigidBody(descr: BodyShape3DDescriptor, position?: Point3, rotation?: Point4, material?: DisplayObject3dOpts<TypeDoc['vTypeDoc']['texture']>): Entity3d<TypeDoc>;
|
|
66
|
+
addRenderer(camera: TypeDoc['vTypeDoc']['camera'], canvas?: HTMLCanvasElement, rendererOptions?: Partial<RendererOptions & TypeDoc['vTypeDoc']['rendererExtraOpts']>): Renderer3dEntity<TypeDoc['vTypeDoc']>;
|
|
39
67
|
protected registerConsoleCommands(ggstatic: {
|
|
40
68
|
registerConsoleCommand: (world: GgWorld<any, any> | null, command: string, handler: (...args: string[]) => Promise<string>, doc?: string) => void;
|
|
41
69
|
}): void;
|
package/dist/3d/gg-3d-world.js
CHANGED
|
@@ -12,16 +12,15 @@ import { Gg3dLoader } from './loader';
|
|
|
12
12
|
import { Entity3d } from './entities/entity-3d';
|
|
13
13
|
import { Renderer3dEntity } from './entities/renderer-3d.entity';
|
|
14
14
|
export class Gg3dWorld extends GgWorld {
|
|
15
|
-
constructor(
|
|
16
|
-
super(
|
|
17
|
-
this.visualScene = visualScene;
|
|
18
|
-
this.physicsWorld = physicsWorld;
|
|
15
|
+
constructor(args) {
|
|
16
|
+
super(args);
|
|
19
17
|
this.loader = new Gg3dLoader(this);
|
|
20
18
|
}
|
|
21
19
|
addPrimitiveRigidBody(descr, position = Pnt3.O, rotation = Qtrn.O, material = {}) {
|
|
20
|
+
var _a, _b;
|
|
22
21
|
const entity = new Entity3d({
|
|
23
|
-
object3D: this.visualScene.factory.createPrimitive(descr.shape, material),
|
|
24
|
-
objectBody: this.physicsWorld.factory.createRigidBody(descr),
|
|
22
|
+
object3D: (_a = this.visualScene) === null || _a === void 0 ? void 0 : _a.factory.createPrimitive(descr.shape, material),
|
|
23
|
+
objectBody: (_b = this.physicsWorld) === null || _b === void 0 ? void 0 : _b.factory.createRigidBody(descr),
|
|
25
24
|
});
|
|
26
25
|
entity.position = position;
|
|
27
26
|
entity.rotation = rotation;
|
|
@@ -29,25 +28,30 @@ export class Gg3dWorld extends GgWorld {
|
|
|
29
28
|
return entity;
|
|
30
29
|
}
|
|
31
30
|
addRenderer(camera, canvas, rendererOptions) {
|
|
31
|
+
if (!this.visualScene) {
|
|
32
|
+
throw new Error('Cannot add renderer to the world without visual scene');
|
|
33
|
+
}
|
|
32
34
|
const entity = new Renderer3dEntity(this.visualScene.createRenderer(camera, canvas, rendererOptions));
|
|
33
35
|
this.addEntity(entity);
|
|
34
36
|
return entity;
|
|
35
37
|
}
|
|
36
38
|
registerConsoleCommands(ggstatic) {
|
|
37
39
|
super.registerConsoleCommands(ggstatic);
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
if (args.length > 0) {
|
|
43
|
-
if (isNaN(+args[0]) || isNaN(+args[1]) || isNaN(+args[2])) {
|
|
44
|
-
throw new Error('Wrong arguments');
|
|
40
|
+
if (this.physicsWorld) {
|
|
41
|
+
ggstatic.registerConsoleCommand(this, 'gravity', (...args) => __awaiter(this, void 0, void 0, function* () {
|
|
42
|
+
if (args.length == 1) {
|
|
43
|
+
args = ['0', '0', '' + -+args[0]]; // mean -Z axis
|
|
45
44
|
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
45
|
+
if (args.length > 0) {
|
|
46
|
+
if (isNaN(+args[0]) || isNaN(+args[1]) || isNaN(+args[2])) {
|
|
47
|
+
throw new Error('Wrong arguments');
|
|
48
|
+
}
|
|
49
|
+
this.physicsWorld.gravity = { x: +args[0], y: +args[1], z: +args[2] };
|
|
50
|
+
}
|
|
51
|
+
return JSON.stringify(this.physicsWorld.gravity);
|
|
52
|
+
}), 'args: [ ?float, ?float, ?float ]; Get or set 3D world gravity vector. 1 argument sets ' +
|
|
53
|
+
'vector {x: 0, y: 0, z: -value}, 3 arguments set the whole vector.' +
|
|
54
|
+
' Default value is "9.82" or "0 0 -9.82"');
|
|
55
|
+
}
|
|
52
56
|
}
|
|
53
57
|
}
|
package/dist/3d/index.d.ts
CHANGED
|
@@ -19,6 +19,7 @@ export * from './entities/controllers/input/car-keyboard-handling.controller';
|
|
|
19
19
|
export * from './entities/controllers/input/gg-car-keyboard-handling.controller';
|
|
20
20
|
export * from './entities/controllers/input/free-camera.controller';
|
|
21
21
|
export * from './entities/controllers/input/orbit-camera.controller';
|
|
22
|
+
export * from './entities/surface-following.entity';
|
|
22
23
|
export * from './interfaces/i-positionable-3d';
|
|
23
24
|
export * from './models/body-options';
|
|
24
25
|
export * from './models/gg-meta';
|
package/dist/3d/index.js
CHANGED
|
@@ -19,6 +19,7 @@ export * from './entities/controllers/input/car-keyboard-handling.controller';
|
|
|
19
19
|
export * from './entities/controllers/input/gg-car-keyboard-handling.controller';
|
|
20
20
|
export * from './entities/controllers/input/free-camera.controller';
|
|
21
21
|
export * from './entities/controllers/input/orbit-camera.controller';
|
|
22
|
+
export * from './entities/surface-following.entity';
|
|
22
23
|
export * from './interfaces/i-positionable-3d';
|
|
23
24
|
export * from './models/body-options';
|
|
24
25
|
export * from './models/gg-meta';
|
package/dist/3d/loader.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Gg3dWorld,
|
|
1
|
+
import { Gg3dWorld, Gg3dWorldTypeDocRepo } from './gg-3d-world';
|
|
2
2
|
import { GgMeta } from './models/gg-meta';
|
|
3
3
|
import { Entity3d } from './entities/entity-3d';
|
|
4
4
|
import { Point3, Point4 } from '../base';
|
|
@@ -14,26 +14,26 @@ export type LoadOptions = {
|
|
|
14
14
|
loadProps: boolean;
|
|
15
15
|
propsPath?: string;
|
|
16
16
|
};
|
|
17
|
-
export type LoadResourcesResult<
|
|
17
|
+
export type LoadResourcesResult<TypeDoc extends Gg3dWorldTypeDocRepo = Gg3dWorldTypeDocRepo> = {
|
|
18
18
|
resources: {
|
|
19
|
-
object3D:
|
|
20
|
-
body:
|
|
19
|
+
object3D: TypeDoc['vTypeDoc']['displayObject'] | null;
|
|
20
|
+
body: TypeDoc['pTypeDoc']['rigidBody'] | null;
|
|
21
21
|
}[];
|
|
22
22
|
meta: GgMeta;
|
|
23
23
|
};
|
|
24
|
-
export type LoadResult<
|
|
25
|
-
entities: Entity3d<
|
|
24
|
+
export type LoadResult<TypeDoc extends Gg3dWorldTypeDocRepo = Gg3dWorldTypeDocRepo> = {
|
|
25
|
+
entities: Entity3d<TypeDoc>[];
|
|
26
26
|
meta: GgMeta;
|
|
27
27
|
};
|
|
28
|
-
export type LoadResultWithProps<
|
|
29
|
-
props?: LoadResult<
|
|
28
|
+
export type LoadResultWithProps<TypeDoc extends Gg3dWorldTypeDocRepo = Gg3dWorldTypeDocRepo> = LoadResult<TypeDoc> & {
|
|
29
|
+
props?: LoadResult<TypeDoc>[];
|
|
30
30
|
};
|
|
31
|
-
export declare class Gg3dLoader<
|
|
31
|
+
export declare class Gg3dLoader<TypeDoc extends Gg3dWorldTypeDocRepo = Gg3dWorldTypeDocRepo> {
|
|
32
32
|
protected readonly world: Gg3dWorld;
|
|
33
33
|
readonly filesCache: Map<string, [ArrayBuffer, GgMeta] | Promise<[ArrayBuffer, GgMeta]>>;
|
|
34
|
-
readonly loadResultCache: Map<string, LoadResourcesResult<
|
|
34
|
+
readonly loadResultCache: Map<string, LoadResourcesResult<TypeDoc> | Promise<LoadResourcesResult<TypeDoc>>>;
|
|
35
35
|
constructor(world: Gg3dWorld);
|
|
36
36
|
loadGgGlbFiles(path: string, useCache?: boolean): Promise<[ArrayBuffer, GgMeta]>;
|
|
37
|
-
loadGgGlbResources(path: string, cachingStrategy?: CachingStrategy): Promise<LoadResourcesResult<
|
|
38
|
-
loadGgGlb(path: string, options?: Partial<LoadOptions>): Promise<LoadResultWithProps<
|
|
37
|
+
loadGgGlbResources(path: string, cachingStrategy?: CachingStrategy): Promise<LoadResourcesResult<TypeDoc>>;
|
|
38
|
+
loadGgGlb(path: string, options?: Partial<LoadOptions>): Promise<LoadResultWithProps<TypeDoc>>;
|
|
39
39
|
}
|