@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,30 @@
1
+ import * as ENGINE from 'genesys.js';
2
+ import * as THREE from 'three';
3
+ import { FreeCameraPlayer } from './player.js';
4
+ import './auto-imports.js';
5
+ class MyGame extends ENGINE.BaseGameLoop {
6
+ pawn = null;
7
+ controller = null;
8
+ createLoadingScreen() {
9
+ // enable the default loading screen
10
+ return new ENGINE.DefaultLoadingScreen();
11
+ }
12
+ async preStart() {
13
+ // default spawn location
14
+ const position = new THREE.Vector3(0, ENGINE.CHARACTER_HEIGHT, 0);
15
+ // create the pawn with simple movement mechanics
16
+ this.pawn = new FreeCameraPlayer({ position });
17
+ // create the controller and possess the pawn
18
+ this.controller = new ENGINE.PlayerController();
19
+ this.controller.possess(this.pawn);
20
+ // add both to the world
21
+ this.world.addActors(this.pawn, this.controller);
22
+ }
23
+ }
24
+ export function main(container, gameId) {
25
+ const game = new MyGame(container, {
26
+ ...ENGINE.BaseGameLoop.DEFAULT_OPTIONS,
27
+ gameId
28
+ });
29
+ return game;
30
+ }
@@ -0,0 +1,43 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import * as ENGINE from 'genesys.js';
8
+ import * as THREE from 'three';
9
+ /**
10
+ * A free camera player class.
11
+ *
12
+ * Key points:
13
+ * - No need to provide movementComponent and camera, they are created internally
14
+ * - The pawn is set to be transient so it's never saved in the level
15
+ * - The directional light follows the player for consistent shadows
16
+ *
17
+ */
18
+ let FreeCameraPlayer = class FreeCameraPlayer extends ENGINE.Pawn {
19
+ constructor(options) {
20
+ // simple perspective camera
21
+ const camera = new THREE.PerspectiveCamera(ENGINE.CAMERA_FOV, 1, ENGINE.CAMERA_NEAR, ENGINE.CAMERA_FAR);
22
+ // simple movement component, do not use the character controller
23
+ const movementComponent = new ENGINE.CharacterMovementComponent({
24
+ ...ENGINE.CharacterMovementComponent.DEFAULT_OPTIONS,
25
+ // disable the character controller
26
+ characterControllerOptions: null,
27
+ });
28
+ // construct the pawn
29
+ super({
30
+ ...options,
31
+ camera,
32
+ movementComponent,
33
+ // make sure the directional light follows the player for consistent shadows
34
+ enableDirectionalLightFollowing: true,
35
+ });
36
+ // set the pawn to be transient so it's never saved in the level
37
+ this.setTransient(true);
38
+ }
39
+ };
40
+ FreeCameraPlayer = __decorate([
41
+ ENGINE.GameClass()
42
+ ], FreeCameraPlayer);
43
+ export { FreeCameraPlayer };
@@ -0,0 +1,43 @@
1
+ // Player Movement Configuration
2
+ export const PLAYER_MOVEMENT = {
3
+ JUMP_SPEED: 20,
4
+ MAX_SPEED: 8,
5
+ MAX_MID_AIR_JUMPS: 1,
6
+ ACCELERATION_LAMBDA: 15,
7
+ DECELERATION_LAMBDA: 10,
8
+ MID_AIR_ACCELERATION_LAMBDA: 8,
9
+ MID_AIR_DECELERATION_LAMBDA: 2,
10
+ };
11
+ // Camera Settings
12
+ export const CAMERA_SETTINGS = {
13
+ FOV: 60,
14
+ NEAR: 0.1,
15
+ FAR: 1000,
16
+ DAMP_FACTOR: 10,
17
+ POSITION: { x: 0, y: 1, z: 8 },
18
+ LOOK_AT: { x: 0, y: 0, z: 0 },
19
+ };
20
+ // Level Generation Configuration
21
+ export const LEVEL_CONFIG = {
22
+ DEPTH: 3,
23
+ CHUNK_SIZE: 50,
24
+ CHUNKS_AHEAD: 2,
25
+ CHUNKS_BEHIND: 2,
26
+ PLATFORM_HEIGHT_RANGE: { min: 1, max: 2 },
27
+ PLATFORM_WIDTH_RANGE: { min: 3, max: 6 },
28
+ OBSTACLE_HEIGHT_RANGE: { min: 3, max: 6 },
29
+ OBSTACLE_WIDTH_RANGE: { min: 1.5, max: 3.0 },
30
+ CHUNK_MARGIN: 0,
31
+ MIN_SPACING: 4,
32
+ DEBUG_VISUALIZATION_HEIGHT: 6,
33
+ DEBUG_VISUALIZATION_OPACITY: 0.3,
34
+ DEBUG_VISUALIZATION_COLOR: 0x00ff00,
35
+ GROUND_HEIGHT: 0.1,
36
+ GROUND_Y_POSITION: -0.05,
37
+ };
38
+ // Material colors
39
+ export const COLORS = {
40
+ PLATFORM: 0x90ee90, // Light green
41
+ OBSTACLE: 0xff4444, // Red
42
+ GROUND: 0x8b4513, // Brown
43
+ };
@@ -0,0 +1,103 @@
1
+ import * as ENGINE from 'genesys.js';
2
+ import * as THREE from 'three';
3
+ import './auto-imports.js';
4
+ import { SideScrollerLevelGenerator } from './level-generator.js';
5
+ import { SideScrollerPlayer } from './player.js';
6
+ // ============================================================================
7
+ // SIDE SCROLLER GAME
8
+ // ============================================================================
9
+ // A side-scroller game with animated character and infinite level generation
10
+ class SideScrollerGame extends ENGINE.BaseGameLoop {
11
+ player = null;
12
+ playerController = null;
13
+ levelGenerator = null;
14
+ createLoadingScreen() {
15
+ // enable the default loading screen
16
+ return new ENGINE.DefaultLoadingScreen();
17
+ }
18
+ async preStart() {
19
+ this.createLevel();
20
+ this.createPlayer();
21
+ }
22
+ tick(tickTime) {
23
+ super.tick(tickTime);
24
+ // Update level generation based on player position
25
+ if (this.player && this.levelGenerator) {
26
+ const playerPosition = this.player.getWorldPosition();
27
+ this.levelGenerator.updateLevel(playerPosition.x);
28
+ }
29
+ }
30
+ createPlayer() {
31
+ const spawnX = 1;
32
+ // Create the side-scroller player with animated character
33
+ this.player = new SideScrollerPlayer({
34
+ position: new THREE.Vector3(spawnX, ENGINE.CHARACTER_HEIGHT / 2, 0),
35
+ });
36
+ // Create the controller and possess the player
37
+ this.playerController = new ENGINE.PlayerController();
38
+ this.playerController.possess(this.player);
39
+ // Add both to the world
40
+ this.world.addActors(this.player, this.playerController);
41
+ this.setInitialPlayerPosition(spawnX);
42
+ }
43
+ /**
44
+ * Sets the initial position of the player.
45
+ * @param spawnX - The X coordinate to spawn the player at.
46
+ */
47
+ setInitialPlayerPosition(spawnX) {
48
+ const groundHeight = this.findGroundHeightAtX(spawnX);
49
+ if (groundHeight !== null) {
50
+ this.player?.setWorldPosition(new THREE.Vector3(spawnX, groundHeight + ENGINE.CHARACTER_HEIGHT / 2, 0));
51
+ }
52
+ else {
53
+ this.world.runInNextTick(() => {
54
+ this.setInitialPlayerPosition(spawnX);
55
+ });
56
+ }
57
+ }
58
+ /**
59
+ * Performs a hit test to find the ground height at a given X coordinate
60
+ * @param x - The X coordinate to test
61
+ * @returns The Y coordinate of the ground surface, or 0 if no ground is found
62
+ */
63
+ findGroundHeightAtX(x) {
64
+ // Start from a high position and cast downward
65
+ const rayOrigin = new THREE.Vector3(x, 50, 0);
66
+ const rayDirection = new THREE.Vector3(0, -1, 0); // Downward
67
+ const hitResults = this.world.getPhysicsEngine()?.performHitTest({
68
+ origin: rayOrigin,
69
+ direction: rayDirection,
70
+ maxDistance: 100, // Cast ray down 100 units
71
+ stopOnFirstHit: true,
72
+ });
73
+ if (hitResults && hitResults.length > 0) {
74
+ // Return the Y coordinate of the hit location (top surface of ground)
75
+ return hitResults[0].hitLocation.y;
76
+ }
77
+ return null;
78
+ }
79
+ createLevel() {
80
+ // Create the level generator
81
+ this.levelGenerator = new SideScrollerLevelGenerator(this.world, {
82
+ enableDebugVisualization: false,
83
+ createGroundMesh: true
84
+ });
85
+ // Generate initial level chunks
86
+ this.levelGenerator.updateLevel(0);
87
+ }
88
+ destroy() {
89
+ // Clean up level generator
90
+ if (this.levelGenerator) {
91
+ this.levelGenerator.cleanup();
92
+ this.levelGenerator = null;
93
+ }
94
+ super.destroy();
95
+ }
96
+ }
97
+ export function main(container, gameId) {
98
+ const game = new SideScrollerGame(container, {
99
+ ...ENGINE.BaseGameLoop.DEFAULT_OPTIONS,
100
+ gameId
101
+ });
102
+ return game;
103
+ }
@@ -0,0 +1,249 @@
1
+ import * as ENGINE from 'genesys.js';
2
+ import * as THREE from 'three';
3
+ import { COLORS, LEVEL_CONFIG } from './const.js';
4
+ // Simple level generator for infinite side-scrolling levels
5
+ export class SideScrollerLevelGenerator {
6
+ world;
7
+ // Map of chunk index to chunk
8
+ levelChunks = new Map();
9
+ // Configuration
10
+ chunkSize;
11
+ chunksAhead;
12
+ chunksBehind;
13
+ platformHeightRange;
14
+ platformWidthRange;
15
+ obstacleHeightRange;
16
+ chunkMargin;
17
+ minSpacing;
18
+ debugVisualizationEnabled = false;
19
+ createGroundMesh = false;
20
+ constructor(world, options = {}) {
21
+ this.world = world;
22
+ // Apply defaults
23
+ this.chunkSize = options.chunkSize ?? LEVEL_CONFIG.CHUNK_SIZE;
24
+ this.chunksAhead = options.chunksAhead ?? LEVEL_CONFIG.CHUNKS_AHEAD;
25
+ this.chunksBehind = options.chunksBehind ?? LEVEL_CONFIG.CHUNKS_BEHIND;
26
+ this.platformHeightRange = options.platformHeightRange ?? LEVEL_CONFIG.PLATFORM_HEIGHT_RANGE;
27
+ this.platformWidthRange = options.platformWidthRange ?? LEVEL_CONFIG.PLATFORM_WIDTH_RANGE;
28
+ this.obstacleHeightRange = options.obstacleHeightRange ?? LEVEL_CONFIG.OBSTACLE_HEIGHT_RANGE;
29
+ this.chunkMargin = options.chunkMargin ?? LEVEL_CONFIG.CHUNK_MARGIN;
30
+ this.minSpacing = options.minSpacing ?? LEVEL_CONFIG.MIN_SPACING;
31
+ this.debugVisualizationEnabled = options.enableDebugVisualization ?? false;
32
+ this.createGroundMesh = options.createGroundMesh ?? false;
33
+ }
34
+ updateLevel(playerX) {
35
+ const playerChunkIndex = this.getChunkIndex(playerX);
36
+ const validChunkIndices = [];
37
+ for (let i = playerChunkIndex - this.chunksBehind; i <= playerChunkIndex + this.chunksAhead; i++) {
38
+ this.generateChunk(i);
39
+ validChunkIndices.push(i);
40
+ }
41
+ for (const index of this.levelChunks.keys()) {
42
+ if (!validChunkIndices.includes(index)) {
43
+ this.removeChunk(index);
44
+ }
45
+ }
46
+ }
47
+ getChunkIndex(x) {
48
+ return Math.floor(x / this.chunkSize);
49
+ }
50
+ removeChunk(index) {
51
+ const chunk = this.levelChunks.get(index);
52
+ if (chunk) {
53
+ this.world.removeActors(...chunk.actors);
54
+ this.levelChunks.delete(index);
55
+ console.log(`[LevelGenerator] Removed chunk at index ${index}`);
56
+ }
57
+ }
58
+ generateChunk(index) {
59
+ if (this.levelChunks.has(index)) {
60
+ return;
61
+ }
62
+ const startX = index * this.chunkSize;
63
+ const endX = startX + this.chunkSize;
64
+ const actors = [];
65
+ // Generate positioned elements for this chunk
66
+ const elements = this.generatePositionedElements(startX);
67
+ // Create actors for each element
68
+ for (const element of elements) {
69
+ const actor = this.createElementActor(element);
70
+ actors.push(actor);
71
+ }
72
+ // Add ground mesh if enabled
73
+ if (this.createGroundMesh) {
74
+ const groundActor = this.createGroundMeshActor(startX);
75
+ actors.push(groundActor);
76
+ }
77
+ // Add debug visualization if enabled
78
+ if (this.debugVisualizationEnabled) {
79
+ const debugActor = this.createChunkDebugVisualization(startX);
80
+ actors.push(debugActor);
81
+ }
82
+ // Add all actors to the world
83
+ this.world.addActors(...actors);
84
+ // Track this chunk
85
+ const chunk = {
86
+ startX,
87
+ endX,
88
+ actors,
89
+ };
90
+ console.log(`[LevelGenerator] Generated chunk at index ${index}`);
91
+ this.levelChunks.set(index, chunk);
92
+ }
93
+ generatePositionedElements(startX) {
94
+ const elements = [];
95
+ const usableWidth = this.chunkSize - (this.chunkMargin * 2); // Leave margin on each side
96
+ const usableStartX = startX + this.chunkMargin;
97
+ // Simple alternating generation: platform -> obstacle -> platform -> obstacle...
98
+ const totalElements = Math.floor(usableWidth / this.minSpacing); // How many elements can fit
99
+ let currentX = usableStartX;
100
+ let isPlatform = true; // Start with platform
101
+ for (let i = 0; i < totalElements && currentX < (startX + this.chunkSize - this.chunkMargin); i++) {
102
+ if (isPlatform) {
103
+ // Generate platform with random dimensions
104
+ const width = this.platformWidthRange.min +
105
+ Math.random() * (this.platformWidthRange.max - this.platformWidthRange.min);
106
+ const height = this.platformHeightRange.min +
107
+ Math.random() * (this.platformHeightRange.max - this.platformHeightRange.min);
108
+ elements.push({
109
+ x: currentX + width / 2, // Center position
110
+ width: width,
111
+ height: height,
112
+ type: 'platform'
113
+ });
114
+ currentX += width + this.minSpacing; // Move past this platform plus spacing
115
+ }
116
+ else {
117
+ // Generate obstacle with random dimensions
118
+ const width = LEVEL_CONFIG.OBSTACLE_WIDTH_RANGE.min +
119
+ Math.random() * (LEVEL_CONFIG.OBSTACLE_WIDTH_RANGE.max - LEVEL_CONFIG.OBSTACLE_WIDTH_RANGE.min);
120
+ const height = this.obstacleHeightRange.min +
121
+ Math.random() * (this.obstacleHeightRange.max - this.obstacleHeightRange.min);
122
+ elements.push({
123
+ x: currentX + width / 2, // Center position
124
+ width: width,
125
+ height: height,
126
+ type: 'obstacle'
127
+ });
128
+ currentX += width + this.minSpacing; // Move past this obstacle plus spacing
129
+ }
130
+ // Alternate between platform and obstacle
131
+ isPlatform = !isPlatform;
132
+ }
133
+ return elements;
134
+ }
135
+ createElementActor(element) {
136
+ const geometry = new THREE.BoxGeometry(element.width, element.height, LEVEL_CONFIG.DEPTH);
137
+ const material = new THREE.MeshStandardMaterial({ color: element.type === 'platform' ? COLORS.PLATFORM : COLORS.OBSTACLE });
138
+ const meshComponent = new ENGINE.MeshComponent({
139
+ geometry: geometry,
140
+ material: material,
141
+ position: new THREE.Vector3(element.x, element.height / 2, 0), // Position at ground level
142
+ physicsOptions: {
143
+ enabled: true,
144
+ motionType: ENGINE.PhysicsMotionType.Static,
145
+ collisionProfile: ENGINE.DefaultCollisionProfile.BlockAll,
146
+ },
147
+ });
148
+ // Enable shadow casting and receiving
149
+ meshComponent.castShadow = true;
150
+ meshComponent.receiveShadow = true;
151
+ return new ENGINE.Actor({
152
+ rootComponent: meshComponent,
153
+ });
154
+ }
155
+ createChunkDebugVisualization(startX) {
156
+ // Create a wireframe box to visualize chunk boundaries
157
+ const chunkGeometry = new THREE.BoxGeometry(this.chunkSize, LEVEL_CONFIG.DEBUG_VISUALIZATION_HEIGHT, LEVEL_CONFIG.DEPTH);
158
+ const chunkMaterial = new THREE.MeshBasicMaterial({
159
+ color: LEVEL_CONFIG.DEBUG_VISUALIZATION_COLOR,
160
+ opacity: LEVEL_CONFIG.DEBUG_VISUALIZATION_OPACITY,
161
+ wireframe: true,
162
+ transparent: true,
163
+ });
164
+ const chunkBoundary = new ENGINE.Actor({
165
+ rootComponent: new ENGINE.MeshComponent({
166
+ geometry: chunkGeometry,
167
+ material: chunkMaterial,
168
+ position: new THREE.Vector3(startX + this.chunkSize / 2, LEVEL_CONFIG.DEBUG_VISUALIZATION_HEIGHT / 2, 0),
169
+ physicsOptions: {
170
+ enabled: false,
171
+ },
172
+ }),
173
+ });
174
+ return chunkBoundary;
175
+ }
176
+ createGroundMeshActor(startX) {
177
+ // Create a ground mesh that spans the entire chunk width
178
+ const groundGeometry = new THREE.BoxGeometry(this.chunkSize, LEVEL_CONFIG.GROUND_HEIGHT, LEVEL_CONFIG.DEPTH);
179
+ const groundMaterial = new THREE.MeshStandardMaterial({
180
+ color: COLORS.GROUND,
181
+ });
182
+ const groundMeshComponent = new ENGINE.MeshComponent({
183
+ geometry: groundGeometry,
184
+ material: groundMaterial,
185
+ position: new THREE.Vector3(startX + this.chunkSize / 2, LEVEL_CONFIG.GROUND_Y_POSITION, 0),
186
+ physicsOptions: {
187
+ enabled: true,
188
+ motionType: ENGINE.PhysicsMotionType.Static,
189
+ collisionProfile: ENGINE.DefaultCollisionProfile.BlockAll,
190
+ },
191
+ });
192
+ // Enable shadow receiving
193
+ groundMeshComponent.receiveShadow = true;
194
+ return new ENGINE.Actor({
195
+ rootComponent: groundMeshComponent,
196
+ });
197
+ }
198
+ /**
199
+ * Gets detailed geometry information at a given x location.
200
+ * @param x - The x coordinate to query
201
+ * @returns An array of geometry info objects at the given x location
202
+ */
203
+ getGeometryInfoAtX(x) {
204
+ const chunkIndex = this.getChunkIndex(x);
205
+ const chunk = this.levelChunks.get(chunkIndex);
206
+ if (!chunk) {
207
+ return [];
208
+ }
209
+ const geometries = [];
210
+ // Add ground mesh if enabled
211
+ if (this.createGroundMesh) {
212
+ const groundCenterY = LEVEL_CONFIG.GROUND_Y_POSITION;
213
+ const groundHalfHeight = LEVEL_CONFIG.GROUND_HEIGHT / 2;
214
+ geometries.push({
215
+ type: 'ground',
216
+ topY: groundCenterY + groundHalfHeight,
217
+ bottomY: groundCenterY - groundHalfHeight,
218
+ width: this.chunkSize,
219
+ centerX: chunk.startX + this.chunkSize / 2
220
+ });
221
+ }
222
+ // Add positioned elements (platforms and obstacles)
223
+ const elements = this.generatePositionedElements(chunk.startX);
224
+ for (const element of elements) {
225
+ const elementLeft = element.x - element.width / 2;
226
+ const elementRight = element.x + element.width / 2;
227
+ // Check if the x coordinate falls within this element's bounds
228
+ if (x >= elementLeft && x <= elementRight) {
229
+ geometries.push({
230
+ type: element.type,
231
+ topY: element.height,
232
+ bottomY: 0, // Elements are positioned at ground level (y=0 bottom)
233
+ width: element.width,
234
+ centerX: element.x
235
+ });
236
+ }
237
+ }
238
+ // Sort by top height (highest first)
239
+ geometries.sort((a, b) => b.topY - a.topY);
240
+ return geometries;
241
+ }
242
+ cleanup() {
243
+ for (const index of this.levelChunks.keys()) {
244
+ this.removeChunk(index);
245
+ }
246
+ this.levelChunks.clear();
247
+ console.log('[LevelGenerator] Cleaned up');
248
+ }
249
+ }
@@ -0,0 +1,105 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import * as ENGINE from 'genesys.js';
8
+ import * as THREE from 'three';
9
+ import { CAMERA_SETTINGS, PLAYER_MOVEMENT } from './const.js';
10
+ // ============================================================================
11
+ // PLAYER PAWN
12
+ // ============================================================================
13
+ // The side-scroller player pawn class using animated character.
14
+ let SideScrollerPlayer = class SideScrollerPlayer extends ENGINE.ThirdPersonCharacterPawn {
15
+ camera;
16
+ characterMesh = null;
17
+ smoothedCameraHeight = null;
18
+ smoothedLookAtHeight = null;
19
+ constructor(options) {
20
+ // Create directional movement component for side-scrolling
21
+ const movementComponent = new ENGINE.DirectionalCharacterMovementComponent({
22
+ ...ENGINE.DirectionalCharacterMovementComponent.DEFAULT_OPTIONS,
23
+ direction: ENGINE.CharacterMovementDirection.LeftRight, // Move left and right
24
+ autoMove: false, // Player controls movement manually
25
+ jumpSpeed: PLAYER_MOVEMENT.JUMP_SPEED,
26
+ maxSpeed: PLAYER_MOVEMENT.MAX_SPEED,
27
+ maxMidAirJumps: PLAYER_MOVEMENT.MAX_MID_AIR_JUMPS, // Allow double jump
28
+ // Physics and movement settings for platformer feel
29
+ accelerationLambda: PLAYER_MOVEMENT.ACCELERATION_LAMBDA,
30
+ decelerationLambda: PLAYER_MOVEMENT.DECELERATION_LAMBDA,
31
+ midAirAccelerationLambda: PLAYER_MOVEMENT.MID_AIR_ACCELERATION_LAMBDA,
32
+ midAirDecelerationLambda: PLAYER_MOVEMENT.MID_AIR_DECELERATION_LAMBDA,
33
+ });
34
+ // Physics options for the player
35
+ const physicsOptions = {
36
+ enabled: true,
37
+ motionType: ENGINE.PhysicsMotionType.KinematicVelocityBased,
38
+ collisionProfile: ENGINE.DefaultCollisionProfile.Character,
39
+ generateCollisionEvents: true,
40
+ };
41
+ // Create root component with physics (invisible capsule for collision)
42
+ const rootComponent = new ENGINE.MeshComponent({
43
+ geometry: new THREE.CapsuleGeometry(ENGINE.CHARACTER_WIDTH / 2, ENGINE.CHARACTER_HEIGHT - ENGINE.CHARACTER_WIDTH),
44
+ material: new THREE.MeshStandardMaterial({
45
+ color: 0xffff00,
46
+ visible: false, // Make invisible since we'll have the animated character mesh
47
+ transparent: true,
48
+ opacity: 0.5
49
+ }),
50
+ physicsOptions,
51
+ });
52
+ super({
53
+ ...options,
54
+ // Use default character model from engine assets
55
+ modelUrl: '@engine/assets/character/mannequinG.glb',
56
+ configUrl: '@engine/assets/character/config/mannequin-anim.json',
57
+ meshPosition: new THREE.Vector3(0, -ENGINE.CHARACTER_HEIGHT / 2, 0),
58
+ meshRotation: new THREE.Euler(0, Math.PI, 0), // Face right initially
59
+ meshScale: new THREE.Vector3(1, 1, 1),
60
+ movementComponent,
61
+ camera: null, // Do not attach the camera to the player directly
62
+ rootComponent,
63
+ enableDirectionalLightFollowing: true,
64
+ });
65
+ // Enable shadow casting for the character
66
+ this.rootComponent.castShadow = true;
67
+ this.camera = new THREE.PerspectiveCamera(CAMERA_SETTINGS.FOV, 1, CAMERA_SETTINGS.NEAR, CAMERA_SETTINGS.FAR);
68
+ }
69
+ async doBeginPlay() {
70
+ await super.doBeginPlay();
71
+ this.getWorld()?.setOverrideCamera(this.camera);
72
+ }
73
+ tickPrePhysics(deltaTime) {
74
+ super.tickPrePhysics(deltaTime);
75
+ // manually update the camera position
76
+ const desiredCameraPosition = this.rootComponent.localToWorld(new THREE.Vector3(CAMERA_SETTINGS.POSITION.x, CAMERA_SETTINGS.POSITION.y, CAMERA_SETTINGS.POSITION.z));
77
+ const desiredCameraLookAt = this.rootComponent.localToWorld(new THREE.Vector3(CAMERA_SETTINGS.LOOK_AT.x, CAMERA_SETTINGS.LOOK_AT.y, CAMERA_SETTINGS.LOOK_AT.z));
78
+ this.smoothedCameraHeight ??= desiredCameraPosition.y;
79
+ this.smoothedLookAtHeight ??= desiredCameraLookAt.y;
80
+ this.smoothedCameraHeight = THREE.MathUtils.damp(this.smoothedCameraHeight, desiredCameraPosition.y, CAMERA_SETTINGS.DAMP_FACTOR, deltaTime);
81
+ this.smoothedLookAtHeight = THREE.MathUtils.damp(this.smoothedLookAtHeight, desiredCameraLookAt.y, CAMERA_SETTINGS.DAMP_FACTOR, deltaTime);
82
+ this.camera.position.x = desiredCameraPosition.x;
83
+ this.camera.position.y = this.smoothedCameraHeight;
84
+ this.camera.position.z = desiredCameraPosition.z;
85
+ this.camera.lookAt(new THREE.Vector3(desiredCameraLookAt.x, this.smoothedLookAtHeight, desiredCameraLookAt.z));
86
+ // change the direction of the character mesh based on the movement direction
87
+ this.characterMesh ??= this.getComponent(ENGINE.GLTFMeshComponent);
88
+ if (this.characterMesh && this.movementComponent) {
89
+ const movementComponent = this.movementComponent;
90
+ const velocity = movementComponent.getVelocities();
91
+ if (velocity.right > 0.1) {
92
+ // Moving right - face right (90 degrees)
93
+ this.characterMesh.rotation.set(0, Math.PI / 2, 0);
94
+ }
95
+ else if (velocity.right < -0.1) {
96
+ // Moving left - face left (-90 degrees)
97
+ this.characterMesh.rotation.set(0, -Math.PI / 2, 0);
98
+ }
99
+ }
100
+ }
101
+ };
102
+ SideScrollerPlayer = __decorate([
103
+ ENGINE.GameClass()
104
+ ], SideScrollerPlayer);
105
+ export { SideScrollerPlayer };
@@ -0,0 +1,30 @@
1
+ import * as ENGINE from 'genesys.js';
2
+ import * as THREE from 'three';
3
+ import { ThirdPersonPlayer } from './player.js';
4
+ import './auto-imports.js';
5
+ class ThirdPersonGame extends ENGINE.BaseGameLoop {
6
+ pawn = null;
7
+ controller = null;
8
+ createLoadingScreen() {
9
+ // enable the default loading screen
10
+ return new ENGINE.DefaultLoadingScreen();
11
+ }
12
+ async preStart() {
13
+ // default spawn location
14
+ const position = new THREE.Vector3(0, ENGINE.CHARACTER_HEIGHT / 2, 0);
15
+ // create the pawn
16
+ this.pawn = new ThirdPersonPlayer({ position });
17
+ // create the controller and possess the pawn
18
+ this.controller = new ENGINE.PlayerController();
19
+ this.controller.possess(this.pawn);
20
+ // add both to the world
21
+ this.world.addActors(this.pawn, this.controller);
22
+ }
23
+ }
24
+ export function main(container, gameId) {
25
+ const game = new ThirdPersonGame(container, {
26
+ ...ENGINE.BaseGameLoop.DEFAULT_OPTIONS,
27
+ gameId
28
+ });
29
+ return game;
30
+ }
@@ -0,0 +1,63 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import * as ENGINE from 'genesys.js';
8
+ import * as THREE from 'three';
9
+ /**
10
+ * A third person player class.
11
+ *
12
+ * Key points:
13
+ * - No need to provide movementComponent and camera, they are created internally
14
+ * - The pawn is set to be transient so it's never saved in the level
15
+ * - The directional light follows the player for consistent shadows
16
+ *
17
+ */
18
+ let ThirdPersonPlayer = class ThirdPersonPlayer extends ENGINE.ThirdPersonCharacterPawn {
19
+ // Omit all the options that are created internally
20
+ constructor(options) {
21
+ // simple camera component - contains a perspective camera by default
22
+ const camera = new THREE.PerspectiveCamera(ENGINE.CAMERA_FOV, 1, 0.1, 1000);
23
+ // set camera position for third person view
24
+ camera.position.set(0, ENGINE.CHARACTER_HEIGHT * 1.3, ENGINE.CHARACTER_HEIGHT * 2);
25
+ camera.lookAt(0, 0, 0);
26
+ // use capsule root component for collision
27
+ const rootComponent = new ENGINE.MeshComponent({
28
+ geometry: ENGINE.GameBuilder.createDefaultPawnCapsuleGeometry(),
29
+ material: new THREE.MeshStandardMaterial({ color: ENGINE.Color.YELLOW, visible: false, transparent: true, opacity: 0.5 }),
30
+ physicsOptions: {
31
+ enabled: true,
32
+ // KinematicVelocityBased is required to use the physics character controller
33
+ motionType: ENGINE.PhysicsMotionType.KinematicVelocityBased,
34
+ collisionProfile: ENGINE.DefaultCollisionProfile.Character,
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
+ // construct the pawn
43
+ super({
44
+ ...options,
45
+ rootComponent,
46
+ movementComponent,
47
+ camera,
48
+ // make sure the directional light follows the player for consistent shadows
49
+ enableDirectionalLightFollowing: true,
50
+ modelUrl: '@engine/assets/character/mannequinG.glb',
51
+ configUrl: '@engine/assets/character/config/mannequin-anim.json',
52
+ meshPosition: new THREE.Vector3(0, -ENGINE.CHARACTER_HEIGHT / 2, 0),
53
+ meshRotation: new THREE.Euler(0, Math.PI, 0),
54
+ meshScale: new THREE.Vector3(1, 1, 1),
55
+ });
56
+ // set the pawn to be transient so it's never saved in the level
57
+ this.setTransient(true);
58
+ }
59
+ };
60
+ ThirdPersonPlayer = __decorate([
61
+ ENGINE.GameClass()
62
+ ], ThirdPersonPlayer);
63
+ export { ThirdPersonPlayer };