From 3e36662031bce6e1e3e285cd2d4a09ba06b3a534 Mon Sep 17 00:00:00 2001 From: Michael Mainguy Date: Fri, 31 Oct 2025 15:59:46 -0500 Subject: [PATCH] Refactor start base to use GLB model instead of procedural geometry MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Create buildStarBase function in src/starBase.ts - Load base.glb model asynchronously with SceneLoader - Extract child mesh from imported model similar to ship implementation - Pass position parameter to buildStarBase function - Update levelDeserializer to call buildStarBase instead of creating cylinder - Add static physics body with MESH shape for proper collision - Add debug logging for base mesh loading and bounds - Remove inline cylinder creation code from createStartBase The start base now uses a proper 3D model instead of a simple cylinder, providing better visual quality and more accurate collision detection. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- public/base.glb | Bin 0 -> 12104 bytes src/levelDeserializer.ts | 32 +++++++------------------------ src/starBase.ts | 40 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 47 insertions(+), 25 deletions(-) create mode 100644 public/base.glb create mode 100644 src/starBase.ts diff --git a/public/base.glb b/public/base.glb new file mode 100644 index 0000000000000000000000000000000000000000..5d2d2df139898e726260d5525c5b94d7c2d110ba GIT binary patch literal 12104 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 Pw1aT*_yUXuVgA1W<1Rl9 literal 0 HcmV?d00001 diff --git a/src/levelDeserializer.ts b/src/levelDeserializer.ts index 1ca44d7..d3b3d73 100644 --- a/src/levelDeserializer.ts +++ b/src/levelDeserializer.ts @@ -28,6 +28,7 @@ import { import { FireProceduralTexture } from "@babylonjs/procedural-textures"; import {createSphereLightmap} from "./sphereLightmap"; import { GameConfig } from "./gameConfig"; +import buildStarBase from "./starBase"; import { MaterialFactory } from "./materialFactory"; import debugLog from './debug'; @@ -60,7 +61,7 @@ export class LevelDeserializer { debugLog('Deserializing level:', this.config.difficulty); // Create entities - const startBase = this.createStartBase(); + const startBase = await this.createStartBase(); const sun = this.createSun(); const planets = this.createPlanets(); const asteroids = await this.createAsteroids(scoreObservable); @@ -76,33 +77,14 @@ export class LevelDeserializer { /** * Create the start base from config */ - private createStartBase(): AbstractMesh { + private async createStartBase(): Promise { const config = this.config.startBase; + const position = this.arrayToVector3(config.position); - const mesh = MeshBuilder.CreateCylinder("startBase", { - diameter: config.diameter, - height: config.height, - tessellation: 72 - }, this.scene); + // Call the buildStarBase function to load and configure the base + const baseMesh = await buildStarBase(position); - mesh.position = this.arrayToVector3(config.position); - - const material = new StandardMaterial("startBaseMaterial", this.scene); - if (config.color) { - material.diffuseColor = new Color3(config.color[0], config.color[1], config.color[2]); - } else { - material.diffuseColor = new Color3(1, 1, 0); // Default yellow - } - mesh.material = material; - - // Only create physics if enabled in config - const gameConfig = GameConfig.getInstance(); - if (gameConfig.physicsEnabled) { - const agg = new PhysicsAggregate(mesh, PhysicsShapeType.CONVEX_HULL, { mass: 0 }, this.scene); - agg.body.setMotionType(PhysicsMotionType.ANIMATED); - } - - return mesh; + return baseMesh; } /** diff --git a/src/starBase.ts b/src/starBase.ts new file mode 100644 index 0000000..92c934a --- /dev/null +++ b/src/starBase.ts @@ -0,0 +1,40 @@ +import { + AbstractMesh, + PhysicsAggregate, + PhysicsMotionType, + PhysicsShapeType, + SceneLoader, + Vector3 +} from "@babylonjs/core"; +import {DefaultScene} from "./defaultScene"; +import {GameConfig} from "./gameConfig"; +import {debug} from "openai/core"; +import debugLog from "./debug"; + +/** + * Create and load the star base mesh + * @param position - Position for the star base + * @returns Promise resolving to the loaded star base mesh + */ +export default async function buildStarBase(position: Vector3): Promise { + const scene = DefaultScene.MainScene; + + // Load the base model + const importMesh = await SceneLoader.ImportMeshAsync(null, "./", "base.glb", scene); + const baseMesh = importMesh.meshes[0].getChildMeshes()[0]; + debugLog('Star base mesh loaded:', baseMesh); + baseMesh.id = "starBase"; + baseMesh.name = "starBase"; + baseMesh.position = position; + debugLog('Ship Bounds radius', baseMesh.getBoundingInfo().boundingSphere.radiusWorld); + // Create physics if enabled + const config = GameConfig.getInstance(); + if (config.physicsEnabled) { + const agg = new PhysicsAggregate(baseMesh, PhysicsShapeType.MESH, { + mass: 0 + }, scene); + agg.body.setMotionType(PhysicsMotionType.STATIC); + } + + return baseMesh; +} \ No newline at end of file