@directivegames/genesys.sdk 3.2.2

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.
Files changed (181) hide show
  1. package/README.md +60 -0
  2. package/dist/src/asset-pack/eslint.config.js +43 -0
  3. package/dist/src/asset-pack/scripts/postinstall.js +64 -0
  4. package/dist/src/asset-pack/src/index.js +1 -0
  5. package/dist/src/core/cli.js +306 -0
  6. package/dist/src/core/common.js +324 -0
  7. package/dist/src/core/index.js +6 -0
  8. package/dist/src/core/tools/build-project.js +450 -0
  9. package/dist/src/core/tools/index.js +2 -0
  10. package/dist/src/core/tools/new-asset-pack.js +150 -0
  11. package/dist/src/core/tools/new-project.js +292 -0
  12. package/dist/src/core/types.js +1 -0
  13. package/dist/src/dependencies.js +82 -0
  14. package/dist/src/electron/IpcSerializableError.js +38 -0
  15. package/dist/src/electron/api.js +7 -0
  16. package/dist/src/electron/backend/actions.js +56 -0
  17. package/dist/src/electron/backend/handler.js +441 -0
  18. package/dist/src/electron/backend/logging.js +41 -0
  19. package/dist/src/electron/backend/main.js +315 -0
  20. package/dist/src/electron/backend/menu.js +208 -0
  21. package/dist/src/electron/backend/state.js +201 -0
  22. package/dist/src/electron/backend/tools/const.js +9 -0
  23. package/dist/src/electron/backend/tools/file-server.js +383 -0
  24. package/dist/src/electron/backend/tools/open-project.js +261 -0
  25. package/dist/src/electron/backend/window.js +161 -0
  26. package/dist/src/templates/eslint.config.js +43 -0
  27. package/dist/src/templates/scripts/genesys/build-project.js +42 -0
  28. package/dist/src/templates/scripts/genesys/calc-bounding-box.js +205 -0
  29. package/dist/src/templates/scripts/genesys/common.js +36 -0
  30. package/dist/src/templates/scripts/genesys/const.js +9 -0
  31. package/dist/src/templates/scripts/genesys/dev/dump-default-scene.js +8 -0
  32. package/dist/src/templates/scripts/genesys/dev/generate-manifest.js +116 -0
  33. package/dist/src/templates/scripts/genesys/dev/launcher.js +39 -0
  34. package/dist/src/templates/scripts/genesys/dev/storage-provider.js +188 -0
  35. package/dist/src/templates/scripts/genesys/dev/update-template-scenes.js +67 -0
  36. package/dist/src/templates/scripts/genesys/doc-server.js +12 -0
  37. package/dist/src/templates/scripts/genesys/genesys-mcp.js +413 -0
  38. package/dist/src/templates/scripts/genesys/mcp/doc-tools.js +70 -0
  39. package/dist/src/templates/scripts/genesys/mcp/editor-functions.js +123 -0
  40. package/dist/src/templates/scripts/genesys/mcp/editor-tools.js +51 -0
  41. package/dist/src/templates/scripts/genesys/mcp/get-scene-state.js +26 -0
  42. package/dist/src/templates/scripts/genesys/mcp/run-subprocess.js +23 -0
  43. package/dist/src/templates/scripts/genesys/mcp/search-actors.js +703 -0
  44. package/dist/src/templates/scripts/genesys/mcp/search-assets.js +296 -0
  45. package/dist/src/templates/scripts/genesys/mcp/utils.js +234 -0
  46. package/dist/src/templates/scripts/genesys/misc.js +32 -0
  47. package/dist/src/templates/scripts/genesys/mock.js +5 -0
  48. package/dist/src/templates/scripts/genesys/place-actors.js +112 -0
  49. package/dist/src/templates/scripts/genesys/post-install.js +25 -0
  50. package/dist/src/templates/scripts/genesys/remove-engine-comments.js +113 -0
  51. package/dist/src/templates/scripts/genesys/storageProvider.js +146 -0
  52. package/dist/src/templates/scripts/genesys/validate-prefabs.js +115 -0
  53. package/dist/src/templates/src/index.js +20 -0
  54. package/dist/src/templates/src/templates/firstPerson/src/auto-imports.js +1 -0
  55. package/dist/src/templates/src/templates/firstPerson/src/game.js +30 -0
  56. package/dist/src/templates/src/templates/firstPerson/src/player.js +60 -0
  57. package/dist/src/templates/src/templates/fps/src/auto-imports.js +1 -0
  58. package/dist/src/templates/src/templates/fps/src/game.js +30 -0
  59. package/dist/src/templates/src/templates/fps/src/player.js +64 -0
  60. package/dist/src/templates/src/templates/fps/src/weapon.js +62 -0
  61. package/dist/src/templates/src/templates/freeCamera/src/auto-imports.js +1 -0
  62. package/dist/src/templates/src/templates/freeCamera/src/game.js +30 -0
  63. package/dist/src/templates/src/templates/freeCamera/src/player.js +43 -0
  64. package/dist/src/templates/src/templates/sideScroller/src/auto-imports.js +1 -0
  65. package/dist/src/templates/src/templates/sideScroller/src/const.js +43 -0
  66. package/dist/src/templates/src/templates/sideScroller/src/game.js +103 -0
  67. package/dist/src/templates/src/templates/sideScroller/src/level-generator.js +249 -0
  68. package/dist/src/templates/src/templates/sideScroller/src/player.js +105 -0
  69. package/dist/src/templates/src/templates/thirdPerson/src/auto-imports.js +1 -0
  70. package/dist/src/templates/src/templates/thirdPerson/src/game.js +30 -0
  71. package/dist/src/templates/src/templates/thirdPerson/src/player.js +63 -0
  72. package/dist/src/templates/src/templates/vehicle/src/auto-imports.js +1 -0
  73. package/dist/src/templates/src/templates/vehicle/src/base-vehicle.js +122 -0
  74. package/dist/src/templates/src/templates/vehicle/src/game.js +33 -0
  75. package/dist/src/templates/src/templates/vehicle/src/mesh-vehicle.js +189 -0
  76. package/dist/src/templates/src/templates/vehicle/src/player.js +102 -0
  77. package/dist/src/templates/src/templates/vehicle/src/primitive-vehicle.js +259 -0
  78. package/dist/src/templates/src/templates/vehicle/src/ui-hints.js +100 -0
  79. package/dist/src/templates/src/templates/vr-game/src/auto-imports.js +1 -0
  80. package/dist/src/templates/src/templates/vr-game/src/game.js +55 -0
  81. package/dist/src/templates/src/templates/vr-game/src/sample-vr-actor.js +29 -0
  82. package/dist/src/templates/vite.config.js +46 -0
  83. package/package.json +176 -0
  84. package/scripts/post-install.ts +143 -0
  85. package/src/asset-pack/.gitattributes +89 -0
  86. package/src/asset-pack/eslint.config.js +45 -0
  87. package/src/asset-pack/gitignore +11 -0
  88. package/src/asset-pack/scripts/postinstall.ts +81 -0
  89. package/src/asset-pack/src/index.ts +0 -0
  90. package/src/asset-pack/tsconfig.json +34 -0
  91. package/src/templates/.cursor/mcp.json +20 -0
  92. package/src/templates/.cursorignore +2 -0
  93. package/src/templates/.gitattributes +89 -0
  94. package/src/templates/.vscode/settings.json +6 -0
  95. package/src/templates/AGENTS.md +86 -0
  96. package/src/templates/CLAUDE.md +1 -0
  97. package/src/templates/README.md +24 -0
  98. package/src/templates/eslint.config.js +45 -0
  99. package/src/templates/gitignore +11 -0
  100. package/src/templates/index.html +34 -0
  101. package/src/templates/pnpm-lock.yaml +3676 -0
  102. package/src/templates/scripts/genesys/build-project.ts +51 -0
  103. package/src/templates/scripts/genesys/calc-bounding-box.ts +272 -0
  104. package/src/templates/scripts/genesys/common.ts +46 -0
  105. package/src/templates/scripts/genesys/const.ts +9 -0
  106. package/src/templates/scripts/genesys/dev/dump-default-scene.ts +11 -0
  107. package/src/templates/scripts/genesys/dev/generate-manifest.ts +146 -0
  108. package/src/templates/scripts/genesys/dev/launcher.ts +46 -0
  109. package/src/templates/scripts/genesys/dev/storage-provider.ts +229 -0
  110. package/src/templates/scripts/genesys/dev/update-template-scenes.ts +84 -0
  111. package/src/templates/scripts/genesys/doc-server.ts +16 -0
  112. package/src/templates/scripts/genesys/genesys-mcp.ts +526 -0
  113. package/src/templates/scripts/genesys/mcp/doc-tools.ts +86 -0
  114. package/src/templates/scripts/genesys/mcp/editor-functions.ts +151 -0
  115. package/src/templates/scripts/genesys/mcp/editor-tools.ts +73 -0
  116. package/src/templates/scripts/genesys/mcp/get-scene-state.ts +35 -0
  117. package/src/templates/scripts/genesys/mcp/run-subprocess.ts +30 -0
  118. package/src/templates/scripts/genesys/mcp/search-actors.ts +858 -0
  119. package/src/templates/scripts/genesys/mcp/search-assets.ts +380 -0
  120. package/src/templates/scripts/genesys/mcp/utils.ts +281 -0
  121. package/src/templates/scripts/genesys/misc.ts +42 -0
  122. package/src/templates/scripts/genesys/mock.ts +6 -0
  123. package/src/templates/scripts/genesys/place-actors.ts +179 -0
  124. package/src/templates/scripts/genesys/post-install.ts +30 -0
  125. package/src/templates/scripts/genesys/prefab.schema.json +85 -0
  126. package/src/templates/scripts/genesys/remove-engine-comments.ts +135 -0
  127. package/src/templates/scripts/genesys/run-mcp-inspector.bat +5 -0
  128. package/src/templates/scripts/genesys/storageProvider.ts +182 -0
  129. package/src/templates/scripts/genesys/validate-prefabs.ts +138 -0
  130. package/src/templates/src/index.ts +22 -0
  131. package/src/templates/src/templates/firstPerson/assets/default.genesys-scene +166 -0
  132. package/src/templates/src/templates/firstPerson/src/auto-imports.ts +0 -0
  133. package/src/templates/src/templates/firstPerson/src/game.ts +39 -0
  134. package/src/templates/src/templates/firstPerson/src/player.ts +63 -0
  135. package/src/templates/src/templates/fps/assets/default.genesys-scene +9460 -0
  136. package/src/templates/src/templates/fps/assets/models/SM_Beam_400.glb +0 -0
  137. package/src/templates/src/templates/fps/assets/models/SM_ChamferCube.glb +0 -0
  138. package/src/templates/src/templates/fps/assets/models/SM_Floor_Thick_400x400.glb +0 -0
  139. package/src/templates/src/templates/fps/assets/models/SM_Floor_Thick_400x400_Orange.glb +0 -0
  140. package/src/templates/src/templates/fps/assets/models/SM_Floor_Thin_400x400.glb +0 -0
  141. package/src/templates/src/templates/fps/assets/models/SM_Floor_Thin_400x400_Orange.glb +0 -0
  142. package/src/templates/src/templates/fps/assets/models/SM_Ramp_400x400.glb +0 -0
  143. package/src/templates/src/templates/fps/assets/models/SM_Rifle.glb +0 -0
  144. package/src/templates/src/templates/fps/assets/models/SM_Wall_Thin_400x200.glb +0 -0
  145. package/src/templates/src/templates/fps/assets/models/SM_Wall_Thin_400x200_Orange.glb +0 -0
  146. package/src/templates/src/templates/fps/assets/models/SM_Wall_Thin_400x400.glb +0 -0
  147. package/src/templates/src/templates/fps/assets/models/SM_Wall_Thin_400x400_Orange.glb +0 -0
  148. package/src/templates/src/templates/fps/src/auto-imports.ts +0 -0
  149. package/src/templates/src/templates/fps/src/game.ts +39 -0
  150. package/src/templates/src/templates/fps/src/player.ts +69 -0
  151. package/src/templates/src/templates/fps/src/weapon.ts +54 -0
  152. package/src/templates/src/templates/freeCamera/assets/default.genesys-scene +166 -0
  153. package/src/templates/src/templates/freeCamera/src/auto-imports.ts +0 -0
  154. package/src/templates/src/templates/freeCamera/src/game.ts +39 -0
  155. package/src/templates/src/templates/freeCamera/src/player.ts +45 -0
  156. package/src/templates/src/templates/sideScroller/assets/default.genesys-scene +122 -0
  157. package/src/templates/src/templates/sideScroller/src/auto-imports.ts +0 -0
  158. package/src/templates/src/templates/sideScroller/src/const.ts +46 -0
  159. package/src/templates/src/templates/sideScroller/src/game.ts +122 -0
  160. package/src/templates/src/templates/sideScroller/src/level-generator.ts +361 -0
  161. package/src/templates/src/templates/sideScroller/src/player.ts +125 -0
  162. package/src/templates/src/templates/thirdPerson/assets/default.genesys-scene +166 -0
  163. package/src/templates/src/templates/thirdPerson/src/auto-imports.ts +0 -0
  164. package/src/templates/src/templates/thirdPerson/src/game.ts +39 -0
  165. package/src/templates/src/templates/thirdPerson/src/player.ts +61 -0
  166. package/src/templates/src/templates/vehicle/assets/default.genesys-scene +226 -0
  167. package/src/templates/src/templates/vehicle/assets/models/cyberTruck/chassis.glb +0 -0
  168. package/src/templates/src/templates/vehicle/assets/models/cyberTruck/wheel.glb +0 -0
  169. package/src/templates/src/templates/vehicle/src/auto-imports.ts +0 -0
  170. package/src/templates/src/templates/vehicle/src/base-vehicle.ts +145 -0
  171. package/src/templates/src/templates/vehicle/src/game.ts +43 -0
  172. package/src/templates/src/templates/vehicle/src/mesh-vehicle.ts +191 -0
  173. package/src/templates/src/templates/vehicle/src/player.ts +109 -0
  174. package/src/templates/src/templates/vehicle/src/primitive-vehicle.ts +266 -0
  175. package/src/templates/src/templates/vehicle/src/ui-hints.ts +101 -0
  176. package/src/templates/src/templates/vr-game/assets/default.genesys-scene +247 -0
  177. package/src/templates/src/templates/vr-game/src/auto-imports.ts +1 -0
  178. package/src/templates/src/templates/vr-game/src/game.ts +66 -0
  179. package/src/templates/src/templates/vr-game/src/sample-vr-actor.ts +26 -0
  180. package/src/templates/tsconfig.json +35 -0
  181. package/src/templates/vite.config.ts +52 -0
@@ -0,0 +1,166 @@
1
+ {
2
+ "$version": 0,
3
+ "class": "ENGINE.World",
4
+ "uuid": "c0ae85792bc3b946",
5
+ "ctor": {
6
+ "backgroundColor": 3026478,
7
+ "navigationOptions": {
8
+ "engine": "recast-navigation",
9
+ "debug": false,
10
+ "generateOnStartUp": false
11
+ },
12
+ "physicsOptions": {
13
+ "gravity": [
14
+ 0,
15
+ -9.81,
16
+ 0,
17
+ "v"
18
+ ],
19
+ "engine": "rapier"
20
+ },
21
+ "useManifold": true
22
+ },
23
+ "actors": [
24
+ {
25
+ "uuid": "9a86d389088b361c",
26
+ "class": "ENGINE.Actor",
27
+ "properties": {
28
+ "editorData": {
29
+ "displayName": "Directional Light",
30
+ "hidden": false
31
+ }
32
+ },
33
+ "ctor": {
34
+ "rootComponent": {
35
+ "class": "ENGINE.DirectionalLightComponent",
36
+ "uuid": "cfe05433-9edc-4dfe-a535-c71f33e92d78",
37
+ "ctor": {
38
+ "color": 16777215,
39
+ "intensity": 1,
40
+ "castShadow": true,
41
+ "shadowMapSize": 2048,
42
+ "shadowBias": 0,
43
+ "shadowNormalBias": 0,
44
+ "shadowNear": 0.1,
45
+ "shadowFar": 100
46
+ },
47
+ "properties": {
48
+ "position": [
49
+ 10,
50
+ 50,
51
+ -10,
52
+ "v"
53
+ ],
54
+ "castShadow": true
55
+ }
56
+ }
57
+ }
58
+ },
59
+ {
60
+ "uuid": "9d428f2a16e5374a",
61
+ "class": "ENGINE.Actor",
62
+ "properties": {
63
+ "editorData": {
64
+ "displayName": "Ground",
65
+ "hidden": false
66
+ }
67
+ },
68
+ "ctor": {
69
+ "rootComponent": {
70
+ "class": "ENGINE.MeshComponent",
71
+ "uuid": "71caea24-62d7-4e45-a76e-4c7519de2c3c",
72
+ "ctor": {
73
+ "geometry": {
74
+ "class": "THREE.BoxGeometry",
75
+ "ctor": [
76
+ 500,
77
+ 0.1,
78
+ 500
79
+ ]
80
+ },
81
+ "material": {
82
+ "@external": "DefaultMaterial"
83
+ },
84
+ "uvScaleTilesPerUnit": 0.2,
85
+ "physicsOptions": {
86
+ "enabled": true,
87
+ "motionType": "static",
88
+ "collisionProfile": "BlockAll"
89
+ }
90
+ },
91
+ "properties": {
92
+ "position": [
93
+ 0,
94
+ -0.9,
95
+ 0,
96
+ "v"
97
+ ],
98
+ "receiveShadow": true
99
+ }
100
+ }
101
+ }
102
+ },
103
+ {
104
+ "uuid": "b87cbc5e60a2e54c",
105
+ "class": "ENGINE.PlayerStart",
106
+ "properties": {
107
+ "editorData": {
108
+ "displayName": "Player Start",
109
+ "hidden": false
110
+ }
111
+ },
112
+ "ctor": {
113
+ "rootComponent": {
114
+ "class": "ENGINE.SceneComponent",
115
+ "uuid": "b4d5f8f7-2512-45e1-9157-c7ff6772402d",
116
+ "ctor": {},
117
+ "properties": {
118
+ "position": [
119
+ 0,
120
+ 0.9,
121
+ 0,
122
+ "v"
123
+ ]
124
+ }
125
+ }
126
+ }
127
+ },
128
+ {
129
+ "uuid": "0ba1f4677e8370d1",
130
+ "class": "ENGINE.Actor",
131
+ "properties": {
132
+ "editorData": {
133
+ "displayName": "Skybox",
134
+ "hidden": false
135
+ }
136
+ },
137
+ "ctor": {
138
+ "rootComponent": {
139
+ "class": "ENGINE.SceneComponent",
140
+ "uuid": "195e88df-73ff-4f4b-82ae-7fb58671463d",
141
+ "ctor": {},
142
+ "properties": {},
143
+ "children": [
144
+ {
145
+ "class": "ENGINE.SkyboxComponent",
146
+ "uuid": "a6cea5af-a972-4031-97b4-cd9218198a2f",
147
+ "ctor": {
148
+ "textureUrl": "@engine/assets/textures/skybox/citrus_orchard_road_puresky_2k.hdr",
149
+ "width": 2048,
150
+ "height": 1024,
151
+ "bottomColor": "#E6F3FF",
152
+ "middleColor": "#4A90E2",
153
+ "topColor": "#0F1B3C",
154
+ "envMapIntensity": 1
155
+ },
156
+ "properties": {}
157
+ }
158
+ ]
159
+ }
160
+ }
161
+ }
162
+ ],
163
+ "properties": {
164
+ "editorData": {}
165
+ }
166
+ }
@@ -0,0 +1,39 @@
1
+
2
+ import * as ENGINE from 'genesys.js';
3
+ import * as THREE from 'three';
4
+
5
+ import { ThirdPersonPlayer } from './player.js';
6
+ import './auto-imports.js';
7
+
8
+ class ThirdPersonGame extends ENGINE.BaseGameLoop {
9
+ private pawn: ThirdPersonPlayer | null = null;
10
+ private controller: ENGINE.PlayerController | null = null;
11
+
12
+ protected override createLoadingScreen(): ENGINE.ILoadingScreen | null {
13
+ // enable the default loading screen
14
+ return new ENGINE.DefaultLoadingScreen();
15
+ }
16
+
17
+ protected override async preStart(): Promise<void> {
18
+ // default spawn location
19
+ const position = new THREE.Vector3(0, ENGINE.CHARACTER_HEIGHT / 2, 0);
20
+
21
+ // create the pawn
22
+ this.pawn = new ThirdPersonPlayer({ position });
23
+
24
+ // create the controller and possess the pawn
25
+ this.controller = new ENGINE.PlayerController();
26
+ this.controller.possess(this.pawn);
27
+
28
+ // add both to the world
29
+ this.world.addActors(this.pawn, this.controller);
30
+ }
31
+ }
32
+
33
+ export function main(container: HTMLElement, gameId: string): ENGINE.IGameLoop {
34
+ const game = new ThirdPersonGame(container, {
35
+ ...ENGINE.BaseGameLoop.DEFAULT_OPTIONS,
36
+ gameId
37
+ });
38
+ return game;
39
+ }
@@ -0,0 +1,61 @@
1
+ import * as ENGINE from 'genesys.js';
2
+ import * as THREE from 'three';
3
+
4
+
5
+ /**
6
+ * A third person player class.
7
+ *
8
+ * Key points:
9
+ * - No need to provide movementComponent and camera, they are created internally
10
+ * - The pawn is set to be transient so it's never saved in the level
11
+ * - The directional light follows the player for consistent shadows
12
+ *
13
+ */
14
+ @ENGINE.GameClass()
15
+ export class ThirdPersonPlayer extends ENGINE.ThirdPersonCharacterPawn {
16
+ // Omit all the options that are created internally
17
+ constructor(options: Omit<ENGINE.ThirdPersonCharacterPawnOptions,
18
+ 'rootComponent' | 'movementComponent' | 'camera' | 'modelUrl' | 'configUrl' | 'meshPosition' | 'meshRotation' | 'meshScale'>) {
19
+ // simple camera component - contains a perspective camera by default
20
+ const camera = new THREE.PerspectiveCamera(ENGINE.CAMERA_FOV, 1, 0.1, 1000);
21
+ // set camera position for third person view
22
+ camera.position.set(0, ENGINE.CHARACTER_HEIGHT * 1.3, ENGINE.CHARACTER_HEIGHT * 2);
23
+ camera.lookAt(0, 0, 0);
24
+
25
+ // use capsule root component for collision
26
+ const rootComponent = new ENGINE.MeshComponent({
27
+ geometry: ENGINE.GameBuilder.createDefaultPawnCapsuleGeometry(),
28
+ material: new THREE.MeshStandardMaterial({ color: ENGINE.Color.YELLOW, visible: false, transparent: true, opacity: 0.5 }),
29
+ physicsOptions: {
30
+ enabled: true,
31
+ // KinematicVelocityBased is required to use the physics character controller
32
+ motionType: ENGINE.PhysicsMotionType.KinematicVelocityBased,
33
+ collisionProfile: ENGINE.DefaultCollisionProfile.Character,
34
+ },
35
+ });
36
+
37
+ // use third person movement mechanics
38
+ const movementComponent = new ENGINE.CharacterMovementComponent({
39
+ ...ENGINE.CharacterMovementComponent.DEFAULT_OPTIONS,
40
+ movementType: ENGINE.CharacterMovementType.ThirdPerson,
41
+ });
42
+
43
+ // construct the pawn
44
+ super({
45
+ ...options,
46
+ rootComponent,
47
+ movementComponent,
48
+ camera,
49
+ // make sure the directional light follows the player for consistent shadows
50
+ enableDirectionalLightFollowing: true,
51
+ modelUrl: '@engine/assets/character/mannequinG.glb',
52
+ configUrl: '@engine/assets/character/config/mannequin-anim.json',
53
+ meshPosition: new THREE.Vector3(0, -ENGINE.CHARACTER_HEIGHT / 2, 0),
54
+ meshRotation: new THREE.Euler(0, Math.PI, 0),
55
+ meshScale: new THREE.Vector3(1, 1, 1),
56
+ });
57
+
58
+ // set the pawn to be transient so it's never saved in the level
59
+ this.setTransient(true);
60
+ }
61
+ }
@@ -0,0 +1,226 @@
1
+ {
2
+ "$version": 0,
3
+ "class": "ENGINE.World",
4
+ "uuid": "c0ae85792bc3b946",
5
+ "ctor": {
6
+ "backgroundColor": 3026478,
7
+ "navigationOptions": {
8
+ "engine": "recast-navigation",
9
+ "debug": false,
10
+ "generateOnStartUp": false
11
+ },
12
+ "physicsOptions": {
13
+ "gravity": [
14
+ 0,
15
+ -9.81,
16
+ 0,
17
+ "v"
18
+ ],
19
+ "engine": "rapier"
20
+ },
21
+ "useManifold": true
22
+ },
23
+ "actors": [
24
+ {
25
+ "uuid": "9a86d389088b361c",
26
+ "class": "ENGINE.Actor",
27
+ "properties": {
28
+ "editorData": {
29
+ "displayName": "Directional Light",
30
+ "hidden": false
31
+ }
32
+ },
33
+ "ctor": {
34
+ "rootComponent": {
35
+ "class": "ENGINE.DirectionalLightComponent",
36
+ "uuid": "cfe05433-9edc-4dfe-a535-c71f33e92d78",
37
+ "ctor": {
38
+ "color": 16777215,
39
+ "intensity": 1,
40
+ "castShadow": true,
41
+ "shadowMapSize": 2048,
42
+ "shadowBias": 0,
43
+ "shadowNormalBias": 0,
44
+ "shadowNear": 0.1,
45
+ "shadowFar": 100
46
+ },
47
+ "properties": {
48
+ "position": [
49
+ 10,
50
+ 50,
51
+ -10,
52
+ "v"
53
+ ],
54
+ "castShadow": true
55
+ }
56
+ }
57
+ }
58
+ },
59
+ {
60
+ "uuid": "9d428f2a16e5374a",
61
+ "class": "ENGINE.Actor",
62
+ "properties": {
63
+ "editorData": {
64
+ "displayName": "Ground",
65
+ "hidden": false
66
+ }
67
+ },
68
+ "ctor": {
69
+ "rootComponent": {
70
+ "class": "ENGINE.MeshComponent",
71
+ "uuid": "71caea24-62d7-4e45-a76e-4c7519de2c3c",
72
+ "ctor": {
73
+ "geometry": {
74
+ "class": "THREE.BoxGeometry",
75
+ "ctor": [
76
+ 500,
77
+ 0.1,
78
+ 500
79
+ ]
80
+ },
81
+ "material": {
82
+ "@external": "DefaultMaterial"
83
+ },
84
+ "uvScaleTilesPerUnit": 0.2,
85
+ "physicsOptions": {
86
+ "enabled": true,
87
+ "motionType": "static",
88
+ "collisionProfile": "BlockAll"
89
+ }
90
+ },
91
+ "properties": {
92
+ "position": [
93
+ 0,
94
+ -0.9,
95
+ 0,
96
+ "v"
97
+ ],
98
+ "receiveShadow": true
99
+ }
100
+ }
101
+ }
102
+ },
103
+ {
104
+ "uuid": "b87cbc5e60a2e54c",
105
+ "class": "ENGINE.PlayerStart",
106
+ "properties": {
107
+ "editorData": {
108
+ "displayName": "Player Start",
109
+ "hidden": false
110
+ }
111
+ },
112
+ "ctor": {
113
+ "rootComponent": {
114
+ "class": "ENGINE.SceneComponent",
115
+ "uuid": "b4d5f8f7-2512-45e1-9157-c7ff6772402d",
116
+ "ctor": {},
117
+ "properties": {
118
+ "position": [
119
+ 0,
120
+ 0.9,
121
+ 0,
122
+ "v"
123
+ ]
124
+ }
125
+ }
126
+ }
127
+ },
128
+ {
129
+ "uuid": "0ba1f4677e8370d1",
130
+ "class": "ENGINE.Actor",
131
+ "properties": {
132
+ "editorData": {
133
+ "displayName": "Skybox",
134
+ "hidden": false
135
+ }
136
+ },
137
+ "ctor": {
138
+ "rootComponent": {
139
+ "class": "ENGINE.SceneComponent",
140
+ "uuid": "195e88df-73ff-4f4b-82ae-7fb58671463d",
141
+ "ctor": {},
142
+ "properties": {},
143
+ "children": [
144
+ {
145
+ "class": "ENGINE.SkyboxComponent",
146
+ "uuid": "15d8d439-a7dd-49a1-800e-f1f893812293",
147
+ "ctor": {
148
+ "textureUrl": "@engine/assets/textures/skybox/citrus_orchard_road_puresky_2k.hdr",
149
+ "width": 2048,
150
+ "height": 1024,
151
+ "bottomColor": "#E6F3FF",
152
+ "middleColor": "#4A90E2",
153
+ "topColor": "#0F1B3C",
154
+ "envMapIntensity": 1
155
+ },
156
+ "properties": {}
157
+ }
158
+ ]
159
+ }
160
+ }
161
+ },
162
+ {
163
+ "uuid": "f527684a997f6384",
164
+ "class": "GAME.MeshVehicle",
165
+ "properties": {
166
+ "editorData": {
167
+ "hidden": false
168
+ }
169
+ },
170
+ "ctor": {
171
+ "enableDirectionalLightFollowing": true,
172
+ "position": [
173
+ -4.2,
174
+ 2.5,
175
+ -8.2,
176
+ "v"
177
+ ],
178
+ "rotation": [
179
+ 0,
180
+ 0,
181
+ 0,
182
+ "e"
183
+ ],
184
+ "scale": [
185
+ 1,
186
+ 1,
187
+ 1,
188
+ "v"
189
+ ]
190
+ }
191
+ },
192
+ {
193
+ "uuid": "2aa7b313363fa7b2",
194
+ "class": "GAME.PrimitiveVehicle",
195
+ "properties": {
196
+ "editorData": {
197
+ "hidden": false
198
+ }
199
+ },
200
+ "ctor": {
201
+ "enableDirectionalLightFollowing": true,
202
+ "position": [
203
+ 3.1,
204
+ 2.3,
205
+ -7.7,
206
+ "v"
207
+ ],
208
+ "rotation": [
209
+ 0,
210
+ 0,
211
+ 0,
212
+ "e"
213
+ ],
214
+ "scale": [
215
+ 1,
216
+ 1,
217
+ 1,
218
+ "v"
219
+ ]
220
+ }
221
+ }
222
+ ],
223
+ "properties": {
224
+ "editorData": {}
225
+ }
226
+ }
@@ -0,0 +1,145 @@
1
+ import * as ENGINE from 'genesys.js';
2
+ import * as THREE from 'three';
3
+
4
+ import { VehiclePlayer } from './player.js';
5
+
6
+ /**
7
+ * Base vehicle class that provides common vehicle functionality
8
+ *
9
+ * Key points:
10
+ * - Handles camera setup with follow component for smooth third-person view
11
+ * - Manages player interaction (enter/exit vehicle with proximity detection)
12
+ * - Provides E key input handler for vehicle exit
13
+ * - Calculates safe exit position when player leaves vehicle
14
+ * - Automatically switches possession between player and vehicle
15
+ *
16
+ */
17
+ export abstract class BaseVehicle extends ENGINE.Pawn {
18
+ protected readonly interactionDistance = 5;
19
+ protected nearbyPlayer: ENGINE.Pawn | null = null;
20
+ protected enteredPlayer: ENGINE.Pawn | null = null;
21
+
22
+ protected override doBeginPlay(): void {
23
+ super.doBeginPlay();
24
+ this.setupCamera();
25
+ this.setupVicinityCheck();
26
+ this.setupExitHandler();
27
+ }
28
+
29
+ protected setupCamera(): void {
30
+ // create a follow component for smooth camera movement
31
+ const followComponent = new ENGINE.FollowComponent({
32
+ positionOffset: new THREE.Vector3(0, 4, 10),
33
+ positionDamping: 0.02,
34
+ lookAtOffset: new THREE.Vector3(0, 0, 0),
35
+ target: this.rootComponent,
36
+ useCameraLookAtConvention: true,
37
+ });
38
+ this.rootComponent.add(followComponent);
39
+
40
+ // create a camera and add it to the follow component
41
+ const camera = new THREE.PerspectiveCamera(ENGINE.CAMERA_FOV, 1, ENGINE.CAMERA_NEAR, ENGINE.CAMERA_FAR);
42
+ followComponent.add(camera);
43
+ }
44
+
45
+ protected setupVicinityCheck(): void {
46
+ // Check every frame for nearby players using tick delegate
47
+ this.onTickPostPhysics.add(() => {
48
+ this.checkForNearbyPlayer();
49
+ });
50
+ }
51
+
52
+ protected checkForNearbyPlayer(): void {
53
+ const players = this.world!.getActors(VehiclePlayer);
54
+
55
+ let foundNearbyPlayer = false;
56
+ for (const player of players) {
57
+ const distance = this.rootComponent.position.distanceTo(player.rootComponent.position);
58
+ if (distance <= this.interactionDistance) {
59
+ this.nearbyPlayer = player;
60
+ foundNearbyPlayer = true;
61
+ break;
62
+ }
63
+ }
64
+
65
+ if (!foundNearbyPlayer) {
66
+ this.nearbyPlayer = null;
67
+ }
68
+ }
69
+
70
+ public canBeEntered(): boolean {
71
+ return this.nearbyPlayer !== null;
72
+ }
73
+
74
+ public getNearbyPlayer(): ENGINE.Pawn | null {
75
+ return this.nearbyPlayer;
76
+ }
77
+
78
+ protected setupExitHandler(): void {
79
+ // Add E key input handler for vehicle exit
80
+ this.onKeyDown.add((e: KeyboardEvent) => {
81
+ if (e.key.toLowerCase() === 'e' && this.enteredPlayer) {
82
+ this.exitVehicle();
83
+ return true;
84
+ } else if (e.key.toLowerCase() === 'f') {
85
+ if (this.movementComponent instanceof ENGINE.VehicleMovementComponent) {
86
+ this.movementComponent.flipVehicle(false);
87
+ }
88
+ return true;
89
+ }
90
+ return false;
91
+ });
92
+ }
93
+
94
+ public setEnteredPlayer(player: ENGINE.Pawn | null): void {
95
+ this.enteredPlayer = player;
96
+ }
97
+
98
+ protected exitVehicle(): void {
99
+ if (!this.enteredPlayer) return;
100
+
101
+ // Calculate exit position (to the side of the vehicle)
102
+ const exitPosition = this.calculateExitPosition();
103
+
104
+ // Get the current player controller
105
+ const controller = this.getPlayerController();
106
+
107
+ if (controller) {
108
+ // Move player to exit position
109
+ this.enteredPlayer.rootComponent.position.copy(exitPosition);
110
+
111
+ // Make player face the same direction as the vehicle (yaw only)
112
+ this.enteredPlayer.rootComponent.rotation.x = 0;
113
+ this.enteredPlayer.rootComponent.rotation.z = 0;
114
+ this.enteredPlayer.rootComponent.rotation.y = this.rootComponent.rotation.y;
115
+
116
+ // Restore player visibility and physics
117
+ this.enteredPlayer.rootComponent.visible = true;
118
+ // Only the root component has physics, do not propagate to children
119
+ this.enteredPlayer.rootComponent.setPhysicsEnabled(true, false);
120
+
121
+ // Switch possession back to player
122
+ controller.unpossess();
123
+ controller.possess(this.enteredPlayer);
124
+
125
+ // Clear entered player reference
126
+ this.enteredPlayer = null;
127
+ }
128
+ }
129
+
130
+ protected calculateExitPosition(): THREE.Vector3 {
131
+ // Calculate a position to the right side of the vehicle
132
+ const vehiclePosition = this.rootComponent.position.clone();
133
+ const vehicleRotation = this.rootComponent.rotation;
134
+
135
+ // Create a vector pointing to the right of the vehicle
136
+ const rightVector = new THREE.Vector3(1, 0, 0);
137
+ rightVector.applyEuler(vehicleRotation);
138
+
139
+ // Position the player 2 units to the right and slightly forward
140
+ const exitOffset = rightVector.multiplyScalar(2);
141
+ exitOffset.y = 1; // Raise slightly above ground
142
+
143
+ return vehiclePosition.add(exitOffset);
144
+ }
145
+ }
@@ -0,0 +1,43 @@
1
+
2
+ import * as ENGINE from 'genesys.js';
3
+ import * as THREE from 'three';
4
+
5
+ import './auto-imports.js';
6
+ import { VehiclePlayer } from './player.js';
7
+ import { UIHints } from './ui-hints.js';
8
+
9
+ class MyGame extends ENGINE.BaseGameLoop {
10
+ private pawn: VehiclePlayer | null = null;
11
+ private controller: ENGINE.PlayerController | null = null;
12
+
13
+ protected override createLoadingScreen(): ENGINE.ILoadingScreen | null {
14
+ // enable the default loading screen
15
+ return new ENGINE.DefaultLoadingScreen();
16
+ }
17
+
18
+ protected override async preStart(): Promise<void> {
19
+ // default spawn location
20
+ const position = new THREE.Vector3(0, ENGINE.CHARACTER_HEIGHT / 2, 0);
21
+
22
+ // create the pawn
23
+ this.pawn = new VehiclePlayer({ position });
24
+
25
+ // create the controller and possess the pawn
26
+ this.controller = new ENGINE.PlayerController();
27
+ this.controller.possess(this.pawn);
28
+
29
+ // create UI hints
30
+ const uiHints = new UIHints();
31
+
32
+ // add all actors to the world
33
+ this.world.addActors(this.pawn, this.controller, uiHints);
34
+ }
35
+ }
36
+
37
+ export function main(container: HTMLElement, gameId: string): ENGINE.IGameLoop {
38
+ const game = new MyGame(container, {
39
+ ...ENGINE.BaseGameLoop.DEFAULT_OPTIONS,
40
+ gameId
41
+ });
42
+ return game;
43
+ }