@gg-web-engine/core 0.0.1
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/.prettierrc +8 -0
- package/README.md +8 -0
- package/blender_exporter/build_blender_scene.py +180 -0
- package/blender_exporter/spherical_to_cube_texture.py +116 -0
- package/dist/2d/entities/gg-2d-entity.d.ts +20 -0
- package/dist/2d/entities/gg-2d-entity.js +84 -0
- package/dist/2d/entities/gg-2d-trigger.entity.d.ts +10 -0
- package/dist/2d/entities/gg-2d-trigger.entity.js +17 -0
- package/dist/2d/entities/gg-positionable-2d-entity.d.ts +7 -0
- package/dist/2d/entities/gg-positionable-2d-entity.js +16 -0
- package/dist/2d/factories.d.ts +18 -0
- package/dist/2d/factories.js +13 -0
- package/dist/2d/gg-2d-world.d.ts +9 -0
- package/dist/2d/gg-2d-world.js +34 -0
- package/dist/2d/interfaces.d.ts +26 -0
- package/dist/2d/interfaces.js +7 -0
- package/dist/2d/models/body-options.d.ts +3 -0
- package/dist/2d/models/body-options.js +2 -0
- package/dist/2d/models/shapes.d.ts +13 -0
- package/dist/2d/models/shapes.js +2 -0
- package/dist/3d/controllers/car-keyboard.controller.d.ts +25 -0
- package/dist/3d/controllers/car-keyboard.controller.js +98 -0
- package/dist/3d/controllers/free-camera.controller.d.ts +23 -0
- package/dist/3d/controllers/free-camera.controller.js +79 -0
- package/dist/3d/entities/controllers/entity-motion.controller.d.ts +32 -0
- package/dist/3d/entities/controllers/entity-motion.controller.js +100 -0
- package/dist/3d/entities/gg-3d-camera.entity.d.ts +7 -0
- package/dist/3d/entities/gg-3d-camera.entity.js +12 -0
- package/dist/3d/entities/gg-3d-entity.d.ts +25 -0
- package/dist/3d/entities/gg-3d-entity.js +108 -0
- package/dist/3d/entities/gg-3d-map-graph.entity.d.ts +51 -0
- package/dist/3d/entities/gg-3d-map-graph.entity.js +164 -0
- package/dist/3d/entities/gg-3d-raycast-vehicle.entity.d.ts +107 -0
- package/dist/3d/entities/gg-3d-raycast-vehicle.entity.js +372 -0
- package/dist/3d/entities/gg-3d-trigger.entity.d.ts +10 -0
- package/dist/3d/entities/gg-3d-trigger.entity.js +21 -0
- package/dist/3d/entities/gg-positionable-3d-entity.d.ts +11 -0
- package/dist/3d/entities/gg-positionable-3d-entity.js +27 -0
- package/dist/3d/factories.d.ts +21 -0
- package/dist/3d/factories.js +22 -0
- package/dist/3d/gg-3d-world.d.ts +11 -0
- package/dist/3d/gg-3d-world.js +36 -0
- package/dist/3d/interfaces.d.ts +65 -0
- package/dist/3d/interfaces.js +40 -0
- package/dist/3d/loader.d.ts +40 -0
- package/dist/3d/loader.js +129 -0
- package/dist/3d/models/body-options.d.ts +3 -0
- package/dist/3d/models/body-options.js +2 -0
- package/dist/3d/models/gg-meta.d.ts +22 -0
- package/dist/3d/models/gg-meta.js +2 -0
- package/dist/3d/models/shapes.d.ts +35 -0
- package/dist/3d/models/shapes.js +2 -0
- package/dist/base/clock.d.ts +26 -0
- package/dist/base/clock.js +82 -0
- package/dist/base/controllers/common.d.ts +8 -0
- package/dist/base/controllers/common.js +32 -0
- package/dist/base/controllers/i-controller.d.ts +4 -0
- package/dist/base/controllers/i-controller.js +2 -0
- package/dist/base/controllers/keyboard.controller.d.ts +16 -0
- package/dist/base/controllers/keyboard.controller.js +109 -0
- package/dist/base/controllers/mouse.controller.d.ts +24 -0
- package/dist/base/controllers/mouse.controller.js +68 -0
- package/dist/base/data-structures/graph.d.ts +20 -0
- package/dist/base/data-structures/graph.js +118 -0
- package/dist/base/entities/base-gg-renderer.d.ts +28 -0
- package/dist/base/entities/base-gg-renderer.js +49 -0
- package/dist/base/entities/gg-entity.d.ts +14 -0
- package/dist/base/entities/gg-entity.js +55 -0
- package/dist/base/entities/gg-positionable-entity.d.ts +23 -0
- package/dist/base/entities/gg-positionable-entity.js +47 -0
- package/dist/base/entities/inline-controller.d.ts +3 -0
- package/dist/base/entities/inline-controller.js +25 -0
- package/dist/base/entities/interfaces/i-tick-listener.d.ts +7 -0
- package/dist/base/entities/interfaces/i-tick-listener.js +6 -0
- package/dist/base/gg-static.d.ts +9 -0
- package/dist/base/gg-static.js +40 -0
- package/dist/base/gg-viewport-manager.d.ts +14 -0
- package/dist/base/gg-viewport-manager.js +125 -0
- package/dist/base/gg-viewport.d.ts +23 -0
- package/dist/base/gg-viewport.js +123 -0
- package/dist/base/gg-world.d.ts +32 -0
- package/dist/base/gg-world.js +172 -0
- package/dist/base/interfaces/gg-body.d.ts +15 -0
- package/dist/base/interfaces/gg-body.js +2 -0
- package/dist/base/interfaces/gg-debug-physics-drawer.d.ts +7 -0
- package/dist/base/interfaces/gg-debug-physics-drawer.js +2 -0
- package/dist/base/interfaces/gg-object.d.ts +16 -0
- package/dist/base/interfaces/gg-object.js +2 -0
- package/dist/base/interfaces/gg-physics-world.d.ts +18 -0
- package/dist/base/interfaces/gg-physics-world.js +2 -0
- package/dist/base/interfaces/gg-trigger.d.ts +8 -0
- package/dist/base/interfaces/gg-trigger.js +2 -0
- package/dist/base/interfaces/gg-visual-scene.d.ts +9 -0
- package/dist/base/interfaces/gg-visual-scene.js +2 -0
- package/dist/base/math/box.d.ts +5 -0
- package/dist/base/math/box.js +21 -0
- package/dist/base/math/matrix4.d.ts +5 -0
- package/dist/base/math/matrix4.js +33 -0
- package/dist/base/math/numbers.d.ts +2 -0
- package/dist/base/math/numbers.js +14 -0
- package/dist/base/math/point2.d.ts +15 -0
- package/dist/base/math/point2.js +40 -0
- package/dist/base/math/point3.d.ts +25 -0
- package/dist/base/math/point3.js +104 -0
- package/dist/base/math/quaternion.d.ts +28 -0
- package/dist/base/math/quaternion.js +145 -0
- package/dist/base/models/axis-directions.d.ts +3 -0
- package/dist/base/models/axis-directions.js +2 -0
- package/dist/base/models/body-options.d.ts +6 -0
- package/dist/base/models/body-options.js +2 -0
- package/dist/base/models/geometry-nodes.d.ts +7 -0
- package/dist/base/models/geometry-nodes.js +2 -0
- package/dist/base/models/points.d.ts +15 -0
- package/dist/base/models/points.js +2 -0
- package/dist/base/ui/gg-console.ui.d.ts +21 -0
- package/dist/base/ui/gg-console.ui.js +162 -0
- package/dist/base/ui/gg-debugger.ui.d.ts +10 -0
- package/dist/base/ui/gg-debugger.ui.js +68 -0
- package/dist/index.d.ts +51 -0
- package/dist/index.js +67 -0
- package/package.json +64 -0
- package/src/2d/entities/gg-2d-entity.ts +86 -0
- package/src/2d/entities/gg-2d-trigger.entity.ts +17 -0
- package/src/2d/entities/gg-positionable-2d-entity.ts +16 -0
- package/src/2d/factories.ts +20 -0
- package/src/2d/gg-2d-world.ts +32 -0
- package/src/2d/interfaces.ts +31 -0
- package/src/2d/models/body-options.ts +3 -0
- package/src/2d/models/shapes.ts +7 -0
- package/src/3d/controllers/car-keyboard.controller.ts +128 -0
- package/src/3d/controllers/free-camera.controller.ts +86 -0
- package/src/3d/entities/controllers/entity-motion.controller.ts +122 -0
- package/src/3d/entities/gg-3d-camera.entity.ts +8 -0
- package/src/3d/entities/gg-3d-entity.ts +116 -0
- package/src/3d/entities/gg-3d-map-graph.entity.ts +204 -0
- package/src/3d/entities/gg-3d-raycast-vehicle.entity.ts +468 -0
- package/src/3d/entities/gg-3d-trigger.entity.ts +22 -0
- package/src/3d/entities/gg-positionable-3d-entity.ts +31 -0
- package/src/3d/factories.ts +29 -0
- package/src/3d/gg-3d-world.ts +36 -0
- package/src/3d/interfaces.ts +96 -0
- package/src/3d/loader.ts +165 -0
- package/src/3d/models/body-options.ts +3 -0
- package/src/3d/models/gg-meta.ts +12 -0
- package/src/3d/models/shapes.ts +13 -0
- package/src/base/clock.ts +97 -0
- package/src/base/controllers/common.ts +37 -0
- package/src/base/controllers/i-controller.ts +5 -0
- package/src/base/controllers/keyboard.controller.ts +109 -0
- package/src/base/controllers/mouse.controller.ts +73 -0
- package/src/base/data-structures/graph.ts +125 -0
- package/src/base/entities/base-gg-renderer.ts +77 -0
- package/src/base/entities/gg-entity.ts +61 -0
- package/src/base/entities/gg-positionable-entity.ts +64 -0
- package/src/base/entities/inline-controller.ts +31 -0
- package/src/base/entities/interfaces/i-tick-listener.ts +15 -0
- package/src/base/gg-static.ts +30 -0
- package/src/base/gg-viewport-manager.ts +122 -0
- package/src/base/gg-viewport.ts +159 -0
- package/src/base/gg-world.ts +198 -0
- package/src/base/interfaces/gg-body.ts +23 -0
- package/src/base/interfaces/gg-debug-physics-drawer.ts +10 -0
- package/src/base/interfaces/gg-object.ts +26 -0
- package/src/base/interfaces/gg-physics-world.ts +24 -0
- package/src/base/interfaces/gg-trigger.ts +10 -0
- package/src/base/interfaces/gg-visual-scene.ts +11 -0
- package/src/base/math/box.ts +19 -0
- package/src/base/math/matrix4.ts +29 -0
- package/src/base/math/numbers.ts +10 -0
- package/src/base/math/point2.ts +43 -0
- package/src/base/math/point3.ts +119 -0
- package/src/base/math/quaternion.ts +172 -0
- package/src/base/models/axis-directions.ts +3 -0
- package/src/base/models/body-options.ts +6 -0
- package/src/base/models/geometry-nodes.ts +5 -0
- package/src/base/models/points.ts +3 -0
- package/src/base/ui/gg-console.ui.ts +165 -0
- package/src/base/ui/gg-debugger.ui.ts +69 -0
- package/src/index.ts +53 -0
- package/test/base/data-structures/graph.spec.ts +76 -0
- package/tsconfig.json +9 -0
package/.prettierrc
ADDED
package/README.md
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="../../documentation/assets/logo.png" style="height: 400px; width:400px;" alt=''/>
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
## Core package for [gg-web-engine](https://github.com/AndyGura/gg-web-engine)
|
|
6
|
+
|
|
7
|
+
### Installation:
|
|
8
|
+
1) `npm install --save @gg-web-engine/core`
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import sys
|
|
3
|
+
import tempfile
|
|
4
|
+
|
|
5
|
+
from string import Template
|
|
6
|
+
|
|
7
|
+
__blender_script_template = Template("""
|
|
8
|
+
import bpy
|
|
9
|
+
import json
|
|
10
|
+
import os
|
|
11
|
+
from rna_prop_ui import rna_idprop_value_to_python
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def parse_curve_obj(object):
|
|
15
|
+
curve = bpy.data.curves[object.data.name]
|
|
16
|
+
spline = curve.splines[0]
|
|
17
|
+
is_cyclic = spline.use_cyclic_u
|
|
18
|
+
points = list(map(lambda p: {
|
|
19
|
+
"x": p.co.x + object.location.x,
|
|
20
|
+
"y": p.co.y + object.location.y,
|
|
21
|
+
"z": p.co.z + object.location.z
|
|
22
|
+
}, spline.points))
|
|
23
|
+
return {
|
|
24
|
+
"name": object.name,
|
|
25
|
+
"cyclic": is_cyclic,
|
|
26
|
+
"points": points,
|
|
27
|
+
**{x: rna_idprop_value_to_python(object[x]) for x in object.keys() if x != '_RNA_UI'}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
def parse_dummy_obj(object):
|
|
31
|
+
object.rotation_mode = 'QUATERNION'
|
|
32
|
+
return {
|
|
33
|
+
"name": object.name,
|
|
34
|
+
"position": {
|
|
35
|
+
"x": object.location.x,
|
|
36
|
+
"y": object.location.y,
|
|
37
|
+
"z": object.location.z,
|
|
38
|
+
},
|
|
39
|
+
"rotation": {
|
|
40
|
+
"x": object.rotation_quaternion.x,
|
|
41
|
+
"y": object.rotation_quaternion.y,
|
|
42
|
+
"z": object.rotation_quaternion.z,
|
|
43
|
+
"w": object.rotation_quaternion.w,
|
|
44
|
+
},
|
|
45
|
+
**{x: object[x] for x in object.keys() if x != '_RNA_UI'}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
def get_rigid_body_description(obj, export_body_parameters=True):
|
|
49
|
+
body = obj.rigid_body
|
|
50
|
+
obj.rotation_mode = 'QUATERNION'
|
|
51
|
+
meta = {
|
|
52
|
+
"name": obj.name,
|
|
53
|
+
"position": {
|
|
54
|
+
'x': obj.location.x,
|
|
55
|
+
'y': obj.location.y,
|
|
56
|
+
'z': obj.location.z,
|
|
57
|
+
},
|
|
58
|
+
# FIXME relative rotation
|
|
59
|
+
"rotation": { 'x': obj.rotation_quaternion.x, 'y': obj.rotation_quaternion.y, 'z': obj.rotation_quaternion.z, 'w': obj.rotation_quaternion.w },
|
|
60
|
+
"shape": {
|
|
61
|
+
"shape": body.collision_shape,
|
|
62
|
+
},
|
|
63
|
+
}
|
|
64
|
+
if (export_body_parameters):
|
|
65
|
+
meta['body'] = {
|
|
66
|
+
"dynamic": body.type == "ACTIVE",
|
|
67
|
+
"mass": body.mass,
|
|
68
|
+
"restitution": body.restitution,
|
|
69
|
+
"friction": body.friction,
|
|
70
|
+
}
|
|
71
|
+
parent = obj.parent
|
|
72
|
+
while parent:
|
|
73
|
+
meta['position']['x'] -= parent.location.x
|
|
74
|
+
meta['position']['y'] -= parent.location.y
|
|
75
|
+
meta['position']['z'] -= parent.location.z
|
|
76
|
+
parent = parent.parent
|
|
77
|
+
meta['position']['x'] = round(meta['position']['x'], 6)
|
|
78
|
+
meta['position']['y'] = round(meta['position']['y'], 6)
|
|
79
|
+
meta['position']['z'] = round(meta['position']['z'], 6)
|
|
80
|
+
if meta['shape']['shape'] == 'SPHERE':
|
|
81
|
+
meta['shape']['radius'] = max(obj.dimensions.x, obj.dimensions.y, obj.dimensions.z) / 2
|
|
82
|
+
elif meta['shape']['shape'] == 'BOX':
|
|
83
|
+
meta['shape']['dimensions'] = { 'x': obj.dimensions.x, 'y': obj.dimensions.y, 'z': obj.dimensions.z }
|
|
84
|
+
elif meta['shape']['shape'] in ['CONE', 'CYLINDER']:
|
|
85
|
+
meta['shape']['radius'] = max(obj.dimensions.x, obj.dimensions.y) / 2
|
|
86
|
+
meta['shape']['height'] = obj.dimensions.z
|
|
87
|
+
elif meta['shape']['shape'] == 'CAPSULE':
|
|
88
|
+
meta['shape']['radius'] = max(obj.dimensions.x, obj.dimensions.y) / 2
|
|
89
|
+
meta['shape']['centersDistance'] = obj.dimensions.z - max(obj.dimensions.x, obj.dimensions.y)
|
|
90
|
+
elif meta['shape']['shape'] == 'CONVEX_HULL':
|
|
91
|
+
meta['shape']['vertices'] = [{ 'x': v.co.x, 'y': v.co.y, 'z': v.co.z } for v in obj.data.vertices]
|
|
92
|
+
elif meta['shape']['shape'] == 'MESH':
|
|
93
|
+
meta['shape']['vertices'] = [{ 'x': v.co.x, 'y': v.co.y, 'z': v.co.z } for v in obj.data.vertices]
|
|
94
|
+
import bmesh
|
|
95
|
+
bm = bmesh.new()
|
|
96
|
+
bm.from_mesh(obj.data)
|
|
97
|
+
bmesh.ops.triangulate(bm, faces=bm.faces[:])
|
|
98
|
+
meta['shape']['faces'] = [[v.index for v in f.verts] for f in bm.faces]
|
|
99
|
+
bm.free()
|
|
100
|
+
elif meta['shape']['shape'] == 'COMPOUND':
|
|
101
|
+
meta['shape']['children'] = [get_rigid_body_description(sub_obj, export_body_parameters=False)
|
|
102
|
+
for sub_obj in bpy.context.scene.objects
|
|
103
|
+
if sub_obj.rigid_body is not None and sub_obj.parent == obj]
|
|
104
|
+
else:
|
|
105
|
+
raise NotImplementedError(f'GG does not support exporting rigid body {meta["shape"]["shape"]} shape')
|
|
106
|
+
return meta
|
|
107
|
+
|
|
108
|
+
if "$src_file":
|
|
109
|
+
bpy.ops.wm.open_mainfile(filepath="$src_file")
|
|
110
|
+
|
|
111
|
+
# compound metadata
|
|
112
|
+
metadata = {"curves": [], "dummies": [], "rigidBodies": []}
|
|
113
|
+
for obj in filter(lambda x: x.type == "CURVE", bpy.data.objects):
|
|
114
|
+
metadata["curves"].append(parse_curve_obj(obj))
|
|
115
|
+
for obj in filter(lambda x: x.type == "EMPTY", bpy.data.objects):
|
|
116
|
+
metadata["dummies"].append(parse_dummy_obj(obj))
|
|
117
|
+
|
|
118
|
+
# saving scene
|
|
119
|
+
for obj in bpy.context.scene.objects:
|
|
120
|
+
include_in_export = obj.type in ["MESH", "LIGHT", "CURVE"]
|
|
121
|
+
include_in_glb = not obj.hide_render
|
|
122
|
+
obj.select_set(state=include_in_export and include_in_glb)
|
|
123
|
+
if not include_in_export:
|
|
124
|
+
continue
|
|
125
|
+
for modifier in obj.modifiers:
|
|
126
|
+
bpy.ops.object.modifier_apply(modifier=modifier.name)
|
|
127
|
+
if obj.rigid_body is not None and (obj.parent is None or obj.parent.rigid_body is None or obj.parent.rigid_body.collision_shape != 'COMPOUND'):
|
|
128
|
+
metadata["rigidBodies"].append(get_rigid_body_description(obj))
|
|
129
|
+
|
|
130
|
+
bpy.ops.export_scene.gltf(export_format="GLB",
|
|
131
|
+
export_copyright="Gurakl Games",
|
|
132
|
+
export_texcoords=True,
|
|
133
|
+
export_normals=True,
|
|
134
|
+
export_tangents=True,
|
|
135
|
+
export_materials='$export_materials',
|
|
136
|
+
export_colors=True,
|
|
137
|
+
export_cameras=False,
|
|
138
|
+
export_lights=True,
|
|
139
|
+
export_extras=True,
|
|
140
|
+
export_yup=False,
|
|
141
|
+
export_apply=False,
|
|
142
|
+
export_animations=False,
|
|
143
|
+
use_selection=True,
|
|
144
|
+
export_skins=False,
|
|
145
|
+
export_morph=False,
|
|
146
|
+
filepath="$file_name.glb")
|
|
147
|
+
# saving metadata
|
|
148
|
+
with open("$file_name.meta", 'w') as outfile:
|
|
149
|
+
json.dump(metadata, outfile)""")
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def construct_blender_export_script(file_name, src_file="", export_materials="EXPORT") -> str:
|
|
153
|
+
return __blender_script_template.substitute({
|
|
154
|
+
'src_file': src_file,
|
|
155
|
+
'file_name': file_name,
|
|
156
|
+
'export_materials': export_materials
|
|
157
|
+
})
|
|
158
|
+
|
|
159
|
+
if __name__ == "__main__":
|
|
160
|
+
# will be invoked if this module is being run directly, but not via import
|
|
161
|
+
skip_textures = sys.argv[1] == '--skip-textures'
|
|
162
|
+
if skip_textures:
|
|
163
|
+
files = sys.argv[2:]
|
|
164
|
+
else:
|
|
165
|
+
files = sys.argv[1:]
|
|
166
|
+
|
|
167
|
+
script = ""
|
|
168
|
+
for file in files:
|
|
169
|
+
if file.startswith('./'):
|
|
170
|
+
file = file[2:]
|
|
171
|
+
full_path = os.path.join(os.getcwd(), file)
|
|
172
|
+
script += '\n\n\n' + construct_blender_export_script(src_file=full_path,
|
|
173
|
+
file_name=full_path[:full_path.rindex('.')],
|
|
174
|
+
export_materials="NONE" if skip_textures else "EXPORT")
|
|
175
|
+
|
|
176
|
+
script_file = tempfile.NamedTemporaryFile(delete=False, mode='w')
|
|
177
|
+
script_file.write(script)
|
|
178
|
+
script_file.flush()
|
|
179
|
+
os.system(f"blender --python {script_file.name} --background")
|
|
180
|
+
os.unlink(script_file.name)
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
from math import pi, atan2, hypot, floor, ceil
|
|
3
|
+
|
|
4
|
+
from PIL import Image
|
|
5
|
+
from numpy import clip, average
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
# get x,y,z coords from out image pixels coords
|
|
9
|
+
# i,j are pixel coords
|
|
10
|
+
# face is face number
|
|
11
|
+
# edge is edge length
|
|
12
|
+
def outImgToXYZ(i, j, face, edge):
|
|
13
|
+
a = 2.0 * float(i) / edge
|
|
14
|
+
b = 2.0 * float(j) / edge
|
|
15
|
+
if face == 0: # back
|
|
16
|
+
(x, y, z) = (-1.0, 1.0 - a, 3.0 - b)
|
|
17
|
+
elif face == 1: # left
|
|
18
|
+
(x, y, z) = (a - 3.0, -1.0, 3.0 - b)
|
|
19
|
+
elif face == 2: # front
|
|
20
|
+
(x, y, z) = (1.0, a - 5.0, 3.0 - b)
|
|
21
|
+
elif face == 3: # right
|
|
22
|
+
(x, y, z) = (7.0 - a, 1.0, 3.0 - b)
|
|
23
|
+
elif face == 4: # top
|
|
24
|
+
(x, y, z) = (b - 1.0, a - 5.0, 1.0)
|
|
25
|
+
elif face == 5: # bottom
|
|
26
|
+
(x, y, z) = (5.0 - b, a - 5.0, -1.0)
|
|
27
|
+
return (x, y, z)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
# convert using an inverse transformation
|
|
31
|
+
def convertBack(imgIn, imgOut):
|
|
32
|
+
inSize = imgIn.size
|
|
33
|
+
outSize = imgOut.size
|
|
34
|
+
inPix = imgIn.load()
|
|
35
|
+
outPix = imgOut.load()
|
|
36
|
+
edge = int(inSize[0] / 4) # the length of each edge in pixels
|
|
37
|
+
for i in range(outSize[0]):
|
|
38
|
+
face = int(i / edge) # 0 - back, 1 - left 2 - front, 3 - right
|
|
39
|
+
if face == 2:
|
|
40
|
+
rng = range(0, edge * 3)
|
|
41
|
+
else:
|
|
42
|
+
rng = range(edge, edge * 2)
|
|
43
|
+
|
|
44
|
+
for j in rng:
|
|
45
|
+
if j < edge:
|
|
46
|
+
face2 = 4 # top
|
|
47
|
+
elif j >= 2 * edge:
|
|
48
|
+
face2 = 5 # bottom
|
|
49
|
+
else:
|
|
50
|
+
face2 = face
|
|
51
|
+
|
|
52
|
+
(x, y, z) = outImgToXYZ(i, j, face2, edge)
|
|
53
|
+
theta = atan2(y, x) # range -pi to pi
|
|
54
|
+
r = hypot(x, y)
|
|
55
|
+
phi = atan2(z, r) # range -pi/2 to pi/2
|
|
56
|
+
# source img coords
|
|
57
|
+
uf = (2.0 * edge * (theta + pi) / pi)
|
|
58
|
+
vf = (2.0 * edge * (pi / 2 - phi) / pi)
|
|
59
|
+
# Use bilinear interpolation between the four surrounding pixels
|
|
60
|
+
ui = floor(uf) # coord of pixel to bottom left
|
|
61
|
+
vi = floor(vf)
|
|
62
|
+
u2 = ui + 1 # coords of pixel to top right
|
|
63
|
+
v2 = vi + 1
|
|
64
|
+
mu = uf - ui # fraction of way across pixel
|
|
65
|
+
nu = vf - vi
|
|
66
|
+
# Pixel values of four corners
|
|
67
|
+
A = inPix[ui % inSize[0], clip(vi, 0, inSize[1] - 1)]
|
|
68
|
+
B = inPix[u2 % inSize[0], clip(vi, 0, inSize[1] - 1)]
|
|
69
|
+
C = inPix[ui % inSize[0], clip(v2, 0, inSize[1] - 1)]
|
|
70
|
+
D = inPix[u2 % inSize[0], clip(v2, 0, inSize[1] - 1)]
|
|
71
|
+
# interpolate
|
|
72
|
+
(r, g, b) = (
|
|
73
|
+
A[0] * (1 - mu) * (1 - nu) + B[0] * (mu) * (1 - nu) + C[0] * (1 - mu) * nu + D[0] * mu * nu,
|
|
74
|
+
A[1] * (1 - mu) * (1 - nu) + B[1] * (mu) * (1 - nu) + C[1] * (1 - mu) * nu + D[1] * mu * nu,
|
|
75
|
+
A[2] * (1 - mu) * (1 - nu) + B[2] * (mu) * (1 - nu) + C[2] * (1 - mu) * nu + D[2] * mu * nu)
|
|
76
|
+
|
|
77
|
+
outPix[i, j] = (int(round(r)), int(round(g)), int(round(b)))
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
files = sys.argv[1:]
|
|
81
|
+
for file_name in files:
|
|
82
|
+
imgIn = Image.open(file_name)
|
|
83
|
+
width, height = imgIn.size
|
|
84
|
+
if width < height * 2:
|
|
85
|
+
imgIn = imgIn.resize((height * 2, height), Image.ANTIALIAS)
|
|
86
|
+
elif width > height * 2:
|
|
87
|
+
imgIn = imgIn.resize((width, width / 2), Image.ANTIALIAS)
|
|
88
|
+
imgOut = Image.new("RGB", (imgIn.size[0], int(imgIn.size[0] * 3 / 4)), "black")
|
|
89
|
+
convertBack(imgIn, imgOut)
|
|
90
|
+
# imgOut.save('cubemap.png')
|
|
91
|
+
# split squares
|
|
92
|
+
file_extension = ".png"
|
|
93
|
+
|
|
94
|
+
name_map = [["", "", "pz", ""],
|
|
95
|
+
["ny", "nx", "py", "px"],
|
|
96
|
+
["", "", "nz", ""]]
|
|
97
|
+
rotation = [[0, 0, 180, 0],
|
|
98
|
+
[0, 90, 180, -90],
|
|
99
|
+
[0, 0, 0, 0]]
|
|
100
|
+
width, height = imgOut.size
|
|
101
|
+
|
|
102
|
+
cube_size = width / 4
|
|
103
|
+
|
|
104
|
+
filelist = []
|
|
105
|
+
for row in range(3):
|
|
106
|
+
for col in range(4):
|
|
107
|
+
if name_map[row][col] != "":
|
|
108
|
+
sx = cube_size * col
|
|
109
|
+
sy = cube_size * row
|
|
110
|
+
fn = file_name[:-4] + '_' + name_map[row][col] + file_extension
|
|
111
|
+
filelist.append(fn)
|
|
112
|
+
print("%s --> %s" % (str((sx, sy, sx + cube_size, sy + cube_size)), fn))
|
|
113
|
+
img = imgOut.crop((sx, sy, sx + cube_size, sy + cube_size))
|
|
114
|
+
if rotation[row][col]:
|
|
115
|
+
img = img.rotate(rotation[row][col])
|
|
116
|
+
img.save(fn)
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Subject } from 'rxjs';
|
|
2
|
+
import { GgPositionable2dEntity } from './gg-positionable-2d-entity';
|
|
3
|
+
import { ITickListener } from '../../base/entities/interfaces/i-tick-listener';
|
|
4
|
+
import { Point2 } from '../../base/models/points';
|
|
5
|
+
import { IGg2dBody, IGg2dObject } from '../interfaces';
|
|
6
|
+
import { Gg2dWorld } from '../gg-2d-world';
|
|
7
|
+
export declare class Gg2dEntity extends GgPositionable2dEntity implements ITickListener {
|
|
8
|
+
readonly object2D: IGg2dObject | null;
|
|
9
|
+
readonly objectBody: IGg2dBody | null;
|
|
10
|
+
readonly tick$: Subject<[number, number]>;
|
|
11
|
+
readonly tickOrder = 750;
|
|
12
|
+
private tickSub;
|
|
13
|
+
set position(value: Point2);
|
|
14
|
+
set rotation(value: number);
|
|
15
|
+
set scale(value: Point2);
|
|
16
|
+
constructor(object2D: IGg2dObject | null, objectBody: IGg2dBody | null);
|
|
17
|
+
onSpawned(world: Gg2dWorld): void;
|
|
18
|
+
onRemoved(): void;
|
|
19
|
+
dispose(): void;
|
|
20
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Gg2dEntity = void 0;
|
|
4
|
+
const rxjs_1 = require("rxjs");
|
|
5
|
+
const gg_positionable_2d_entity_1 = require("./gg-positionable-2d-entity");
|
|
6
|
+
class Gg2dEntity extends gg_positionable_2d_entity_1.GgPositionable2dEntity {
|
|
7
|
+
constructor(object2D, objectBody) {
|
|
8
|
+
super();
|
|
9
|
+
this.object2D = object2D;
|
|
10
|
+
this.objectBody = objectBody;
|
|
11
|
+
this.tick$ = new rxjs_1.Subject();
|
|
12
|
+
this.tickOrder = 750;
|
|
13
|
+
this.tickSub = null;
|
|
14
|
+
if (objectBody && object2D) {
|
|
15
|
+
this.tickSub = this.tick$.subscribe(() => {
|
|
16
|
+
// bind physics body transform to object transform
|
|
17
|
+
const pos = objectBody.position;
|
|
18
|
+
const rot = objectBody.rotation;
|
|
19
|
+
object2D.position = pos;
|
|
20
|
+
object2D.rotation = rot;
|
|
21
|
+
this._position$.next(pos);
|
|
22
|
+
this._rotation$.next(rot);
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
else if (!objectBody && !object2D) {
|
|
26
|
+
throw new Error('Cannot create entity without a sprite and a body');
|
|
27
|
+
}
|
|
28
|
+
if (objectBody) {
|
|
29
|
+
objectBody.entity = this;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
set position(value) {
|
|
33
|
+
if (this.object2D) {
|
|
34
|
+
this.object2D.position = value;
|
|
35
|
+
}
|
|
36
|
+
if (this.objectBody) {
|
|
37
|
+
this.objectBody.position = value;
|
|
38
|
+
}
|
|
39
|
+
super.position = value;
|
|
40
|
+
}
|
|
41
|
+
set rotation(value) {
|
|
42
|
+
if (this.object2D) {
|
|
43
|
+
this.object2D.rotation = value;
|
|
44
|
+
}
|
|
45
|
+
if (this.objectBody) {
|
|
46
|
+
this.objectBody.rotation = value;
|
|
47
|
+
}
|
|
48
|
+
super.rotation = value;
|
|
49
|
+
}
|
|
50
|
+
set scale(value) {
|
|
51
|
+
if (this.object2D) {
|
|
52
|
+
this.object2D.scale = value;
|
|
53
|
+
}
|
|
54
|
+
if (this.objectBody) {
|
|
55
|
+
this.objectBody.scale = value;
|
|
56
|
+
}
|
|
57
|
+
super.scale = value;
|
|
58
|
+
}
|
|
59
|
+
onSpawned(world) {
|
|
60
|
+
var _a, _b;
|
|
61
|
+
super.onSpawned(world);
|
|
62
|
+
(_a = this.object2D) === null || _a === void 0 ? void 0 : _a.addToWorld(world.visualScene);
|
|
63
|
+
(_b = this.objectBody) === null || _b === void 0 ? void 0 : _b.addToWorld(world.physicsWorld);
|
|
64
|
+
}
|
|
65
|
+
onRemoved() {
|
|
66
|
+
var _a, _b;
|
|
67
|
+
(_a = this.object2D) === null || _a === void 0 ? void 0 : _a.removeFromWorld(this.world.visualScene);
|
|
68
|
+
(_b = this.objectBody) === null || _b === void 0 ? void 0 : _b.removeFromWorld(this.world.physicsWorld);
|
|
69
|
+
super.onRemoved();
|
|
70
|
+
}
|
|
71
|
+
dispose() {
|
|
72
|
+
var _a;
|
|
73
|
+
super.dispose();
|
|
74
|
+
(_a = this.tickSub) === null || _a === void 0 ? void 0 : _a.unsubscribe();
|
|
75
|
+
this.tickSub = null;
|
|
76
|
+
if (this.object2D) {
|
|
77
|
+
this.object2D.dispose();
|
|
78
|
+
}
|
|
79
|
+
if (this.objectBody) {
|
|
80
|
+
this.objectBody.dispose();
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
exports.Gg2dEntity = Gg2dEntity;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { IGg2dTrigger } from '../interfaces';
|
|
2
|
+
import { Gg2dEntity } from './gg-2d-entity';
|
|
3
|
+
import { Observable } from 'rxjs';
|
|
4
|
+
import { GgPositionable2dEntity } from './gg-positionable-2d-entity';
|
|
5
|
+
export declare class Gg2dTriggerEntity extends Gg2dEntity {
|
|
6
|
+
readonly objectBody: IGg2dTrigger;
|
|
7
|
+
get onEntityEntered(): Observable<GgPositionable2dEntity>;
|
|
8
|
+
get onEntityLeft(): Observable<GgPositionable2dEntity | null>;
|
|
9
|
+
constructor(objectBody: IGg2dTrigger);
|
|
10
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Gg2dTriggerEntity = void 0;
|
|
4
|
+
const gg_2d_entity_1 = require("./gg-2d-entity");
|
|
5
|
+
class Gg2dTriggerEntity extends gg_2d_entity_1.Gg2dEntity {
|
|
6
|
+
constructor(objectBody) {
|
|
7
|
+
super(null, objectBody);
|
|
8
|
+
this.objectBody = objectBody;
|
|
9
|
+
}
|
|
10
|
+
get onEntityEntered() {
|
|
11
|
+
return this.objectBody.onEntityEntered;
|
|
12
|
+
}
|
|
13
|
+
get onEntityLeft() {
|
|
14
|
+
return this.objectBody.onEntityLeft;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
exports.Gg2dTriggerEntity = Gg2dTriggerEntity;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Point2 } from '../../base/models/points';
|
|
2
|
+
import { GgPositionableEntity } from '../../base/entities/gg-positionable-entity';
|
|
3
|
+
export declare abstract class GgPositionable2dEntity extends GgPositionableEntity<Point2, number> {
|
|
4
|
+
getDefaultPosition(): Point2;
|
|
5
|
+
getDefaultRotation(): number;
|
|
6
|
+
getDefaultScale(): Point2;
|
|
7
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.GgPositionable2dEntity = void 0;
|
|
4
|
+
const gg_positionable_entity_1 = require("../../base/entities/gg-positionable-entity");
|
|
5
|
+
class GgPositionable2dEntity extends gg_positionable_entity_1.GgPositionableEntity {
|
|
6
|
+
getDefaultPosition() {
|
|
7
|
+
return { x: 0, y: 0 };
|
|
8
|
+
}
|
|
9
|
+
getDefaultRotation() {
|
|
10
|
+
return 0;
|
|
11
|
+
}
|
|
12
|
+
getDefaultScale() {
|
|
13
|
+
return { x: 1, y: 1 };
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
exports.GgPositionable2dEntity = GgPositionable2dEntity;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { BodyShape2DDescriptor, Shape2DDescriptor } from './models/shapes';
|
|
2
|
+
import { Point2 } from '../base/models/points';
|
|
3
|
+
import { IGg2dBody, IGg2dObject, IGg2dTrigger } from './interfaces';
|
|
4
|
+
export declare abstract class IGg2dObjectFactory<T extends IGg2dObject = IGg2dObject> {
|
|
5
|
+
abstract createPrimitive(descriptor: Shape2DDescriptor): T;
|
|
6
|
+
createSquare(dimensions: Point2): T;
|
|
7
|
+
createCircle(radius: number): T;
|
|
8
|
+
}
|
|
9
|
+
export interface IGg2dBodyFactory<T extends IGg2dBody = IGg2dBody, K extends IGg2dTrigger = IGg2dTrigger> {
|
|
10
|
+
createRigidBody(descriptor: BodyShape2DDescriptor, transform?: {
|
|
11
|
+
position?: Point2;
|
|
12
|
+
rotation?: number;
|
|
13
|
+
}): T;
|
|
14
|
+
createTrigger(descriptor: Shape2DDescriptor, transform?: {
|
|
15
|
+
position?: Point2;
|
|
16
|
+
rotation?: number;
|
|
17
|
+
}): K;
|
|
18
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.IGg2dObjectFactory = void 0;
|
|
4
|
+
class IGg2dObjectFactory {
|
|
5
|
+
// shortcuts
|
|
6
|
+
createSquare(dimensions) {
|
|
7
|
+
return this.createPrimitive({ shape: 'SQUARE', dimensions });
|
|
8
|
+
}
|
|
9
|
+
createCircle(radius) {
|
|
10
|
+
return this.createPrimitive({ shape: 'CIRCLE', radius });
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
exports.IGg2dObjectFactory = IGg2dObjectFactory;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { GgWorld } from '../base/gg-world';
|
|
2
|
+
import { Point2 } from '../base/models/points';
|
|
3
|
+
import { IGg2dPhysicsWorld, IGg2dVisualScene } from './interfaces';
|
|
4
|
+
export declare class Gg2dWorld<V extends IGg2dVisualScene = IGg2dVisualScene, P extends IGg2dPhysicsWorld = IGg2dPhysicsWorld> extends GgWorld<Point2, number, V, P> {
|
|
5
|
+
readonly visualScene: V;
|
|
6
|
+
readonly physicsWorld: P;
|
|
7
|
+
protected readonly consoleEnabled: boolean;
|
|
8
|
+
constructor(visualScene: V, physicsWorld: P, consoleEnabled?: boolean);
|
|
9
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.Gg2dWorld = void 0;
|
|
13
|
+
const gg_world_1 = require("../base/gg-world");
|
|
14
|
+
class Gg2dWorld extends gg_world_1.GgWorld {
|
|
15
|
+
constructor(visualScene, physicsWorld, consoleEnabled = false) {
|
|
16
|
+
super(visualScene, physicsWorld, consoleEnabled);
|
|
17
|
+
this.visualScene = visualScene;
|
|
18
|
+
this.physicsWorld = physicsWorld;
|
|
19
|
+
this.consoleEnabled = consoleEnabled;
|
|
20
|
+
if (consoleEnabled) {
|
|
21
|
+
this.registerConsoleCommand('ph_gravity', (...args) => __awaiter(this, void 0, void 0, function* () {
|
|
22
|
+
if (args.length == 1) {
|
|
23
|
+
args = ['0', args[0]]; // mean Y axis
|
|
24
|
+
}
|
|
25
|
+
if (args.length > 0) {
|
|
26
|
+
this.physicsWorld.gravity = { x: +args[0], y: +args[1] };
|
|
27
|
+
}
|
|
28
|
+
return JSON.stringify(this.physicsWorld.gravity);
|
|
29
|
+
}), 'args: [float] or [float float]; change 2D world gravity vector. 1 argument means ' +
|
|
30
|
+
'{x: 0, y: value}, 2 arguments set the whole vector. Default value is "9.82" or "0 9.82"');
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
exports.Gg2dWorld = Gg2dWorld;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { GgBody } from '../base/interfaces/gg-body';
|
|
2
|
+
import { Point2 } from '../base/models/points';
|
|
3
|
+
import { GgObject } from '../base/interfaces/gg-object';
|
|
4
|
+
import { GgPhysicsWorld } from '../base/interfaces/gg-physics-world';
|
|
5
|
+
import { GgVisualScene } from '../base/interfaces/gg-visual-scene';
|
|
6
|
+
import { BaseGgRenderer } from '../base/entities/base-gg-renderer';
|
|
7
|
+
import { GgTrigger } from '../base/interfaces/gg-trigger';
|
|
8
|
+
import { Observable } from 'rxjs';
|
|
9
|
+
import { GgPositionable2dEntity } from './entities/gg-positionable-2d-entity';
|
|
10
|
+
import { IGg2dBodyFactory, IGg2dObjectFactory } from './factories';
|
|
11
|
+
export interface IGg2dPhysicsWorld extends GgPhysicsWorld<Point2, number> {
|
|
12
|
+
readonly factory: IGg2dBodyFactory;
|
|
13
|
+
}
|
|
14
|
+
export declare abstract class Gg2dRenderer extends BaseGgRenderer {
|
|
15
|
+
}
|
|
16
|
+
export interface IGg2dBody extends GgBody<Point2, number> {
|
|
17
|
+
}
|
|
18
|
+
export interface IGg2dTrigger extends GgTrigger<Point2, number> {
|
|
19
|
+
get onEntityEntered(): Observable<GgPositionable2dEntity>;
|
|
20
|
+
get onEntityLeft(): Observable<GgPositionable2dEntity | null>;
|
|
21
|
+
}
|
|
22
|
+
export interface IGg2dVisualScene extends GgVisualScene<Point2, number> {
|
|
23
|
+
readonly factory: IGg2dObjectFactory;
|
|
24
|
+
}
|
|
25
|
+
export interface IGg2dObject extends GgObject<Point2, number> {
|
|
26
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Gg2dRenderer = void 0;
|
|
4
|
+
const base_gg_renderer_1 = require("../base/entities/base-gg-renderer");
|
|
5
|
+
class Gg2dRenderer extends base_gg_renderer_1.BaseGgRenderer {
|
|
6
|
+
}
|
|
7
|
+
exports.Gg2dRenderer = Gg2dRenderer;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Point2 } from '../../base/models/points';
|
|
2
|
+
import { Body2DOptions } from './body-options';
|
|
3
|
+
export declare type Shape2DDescriptor = {
|
|
4
|
+
shape: 'SQUARE';
|
|
5
|
+
dimensions: Point2;
|
|
6
|
+
} | {
|
|
7
|
+
shape: 'CIRCLE';
|
|
8
|
+
radius: number;
|
|
9
|
+
};
|
|
10
|
+
export declare type BodyShape2DDescriptor = {
|
|
11
|
+
shape: Shape2DDescriptor;
|
|
12
|
+
body: Partial<Body2DOptions>;
|
|
13
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { BehaviorSubject } from 'rxjs';
|
|
2
|
+
import { IController } from '../../base/controllers/i-controller';
|
|
3
|
+
import { KeyboardController } from '../../base/controllers/keyboard.controller';
|
|
4
|
+
import { Gg3dRaycastVehicleEntity } from '../entities/gg-3d-raycast-vehicle.entity';
|
|
5
|
+
import { DirectionKeymap } from '../../base/controllers/common';
|
|
6
|
+
declare type CarKeyboardControllerOptions = {
|
|
7
|
+
keymap: DirectionKeymap;
|
|
8
|
+
gearUpDownKeys: [string, string];
|
|
9
|
+
};
|
|
10
|
+
export declare class CarKeyboardController implements IController {
|
|
11
|
+
private readonly keyboardController;
|
|
12
|
+
private readonly options;
|
|
13
|
+
private readonly x$;
|
|
14
|
+
private readonly y$;
|
|
15
|
+
private lastX;
|
|
16
|
+
private readonly stop$;
|
|
17
|
+
protected readonly car$: BehaviorSubject<Gg3dRaycastVehicleEntity>;
|
|
18
|
+
pairTickerPipe: import("rxjs").UnaryFunction<import("rxjs").Observable<number>, import("rxjs").Observable<number>>;
|
|
19
|
+
set car(value: Gg3dRaycastVehicleEntity);
|
|
20
|
+
get car(): Gg3dRaycastVehicleEntity;
|
|
21
|
+
constructor(keyboardController: KeyboardController, car: Gg3dRaycastVehicleEntity, options?: CarKeyboardControllerOptions);
|
|
22
|
+
start(): Promise<void>;
|
|
23
|
+
stop(): Promise<void>;
|
|
24
|
+
}
|
|
25
|
+
export {};
|