diff --git a/index.html b/index.html index 28e99b1..55f478f 100644 --- a/index.html +++ b/index.html @@ -301,47 +301,6 @@

Configure graphics quality and physics settings

- -
-

🎨 Graphics Quality

-

- Higher quality settings may impact performance on lower-end devices. -

- -
- - -
Controls planet rendering quality and detail
-
- -
- - -
Controls asteroid rendering quality and detail
-
- -
- - -
Controls sun rendering quality
-
-
-

⚛️ Physics

diff --git a/public/assets/themes/default/models/base.glb b/public/assets/themes/default/models/base.glb index ecdea59..be5e245 100644 Binary files a/public/assets/themes/default/models/base.glb and b/public/assets/themes/default/models/base.glb differ diff --git a/public/assets/themes/default/models/ship.glb b/public/assets/themes/default/models/ship.glb index 2d0ae63..cd81881 100644 Binary files a/public/assets/themes/default/models/ship.glb and b/public/assets/themes/default/models/ship.glb differ diff --git a/public/ship1.stl b/public/ship1.stl deleted file mode 100644 index c23cb96..0000000 Binary files a/public/ship1.stl and /dev/null differ diff --git a/src/gameConfig.ts b/src/gameConfig.ts index 5ca80b7..4c0feba 100644 --- a/src/gameConfig.ts +++ b/src/gameConfig.ts @@ -1,13 +1,3 @@ -/** - * Texture detail levels for game objects - */ -export enum TextureLevel { - WIREFRAME = 'WIREFRAME', - SIMPLE_MATERIAL = 'SIMPLE_MATERIAL', - FULL_TEXTURE = 'FULL_TEXTURE', - PBR_TEXTURE = 'PBR_TEXTURE' -} - /** * Global game configuration settings * Singleton class for managing game-wide settings @@ -15,10 +5,6 @@ export enum TextureLevel { export class GameConfig { private static _instance: GameConfig; - // Texture detail settings - public planetTextureLevel: TextureLevel = TextureLevel.FULL_TEXTURE; - public asteroidTextureLevel: TextureLevel = TextureLevel.FULL_TEXTURE; - public sunTextureLevel: TextureLevel = TextureLevel.FULL_TEXTURE; public debug: boolean = false; // Physics settings public physicsEnabled: boolean = true; @@ -46,9 +32,6 @@ export class GameConfig { */ public save(): void { const config = { - planetTextureLevel: this.planetTextureLevel, - asteroidTextureLevel: this.asteroidTextureLevel, - sunTextureLevel: this.sunTextureLevel, physicsEnabled: this.physicsEnabled, debug: this.debug }; @@ -63,9 +46,6 @@ export class GameConfig { const stored = localStorage.getItem('game-config'); if (stored) { const config = JSON.parse(stored); - this.planetTextureLevel = config.planetTextureLevel ?? TextureLevel.FULL_TEXTURE; - this.asteroidTextureLevel = config.asteroidTextureLevel ?? TextureLevel.FULL_TEXTURE; - this.sunTextureLevel = config.sunTextureLevel ?? TextureLevel.FULL_TEXTURE; this.physicsEnabled = config.physicsEnabled ?? true; this.debug = config.debug ?? false; } else { @@ -80,9 +60,6 @@ export class GameConfig { * Reset to default settings */ public reset(): void { - this.planetTextureLevel = TextureLevel.FULL_TEXTURE; - this.asteroidTextureLevel = TextureLevel.FULL_TEXTURE; - this.sunTextureLevel = TextureLevel.FULL_TEXTURE; this.physicsEnabled = true; this.debug = false; this.save(); diff --git a/src/level1.ts b/src/level1.ts index 4753e2f..0b52817 100644 --- a/src/level1.ts +++ b/src/level1.ts @@ -30,6 +30,7 @@ export class Level1 implements Level { this._deserializer = new LevelDeserializer(levelConfig); this._ship = new Ship(audioEngine); + const xr = DefaultScene.XR; debugLog('Level1 constructor - Setting up XR observables'); @@ -45,7 +46,7 @@ export class Level1 implements Level { this._ship.addController(controller); }); }); - this.initialize(); + // Don't call initialize here - let Main call it after registering the observable } getReadyObservable(): Observable { @@ -92,9 +93,10 @@ export class Level1 implements Level { public async initialize() { debugLog('Initializing level from config:', this._levelConfig.difficulty); if (this._initialized) { + console.error('Initialize called twice'); return; } - + await this._ship.initialize(); setLoadingMessage("Loading level from configuration..."); // Use deserializer to create all entities from config diff --git a/src/levelDeserializer.ts b/src/levelDeserializer.ts index 8fc0c1c..0ac5084 100644 --- a/src/levelDeserializer.ts +++ b/src/levelDeserializer.ts @@ -2,6 +2,8 @@ import { AbstractMesh, MeshBuilder, Observable, + PBRMaterial, + Texture, Vector3 } from "@babylonjs/core"; import { DefaultScene } from "./defaultScene"; @@ -14,7 +16,8 @@ import { validateLevelConfig } from "./levelConfig"; import { GameConfig } from "./gameConfig"; -import { MaterialFactory } from "./materialFactory"; +import { FireProceduralTexture } from "@babylonjs/procedural-textures"; +import { createSphereLightmap } from "./sphereLightmap"; import debugLog from './debug'; import StarBase from "./starBase"; @@ -71,8 +74,7 @@ export class LevelDeserializer { * Create the start base from config */ private async createStartBase(): Promise { - const position = this?.config?.startBase?.position?this.arrayToVector3(this?.config?.startBase?.position):null; - return await StarBase.buildStarBase(position); + return await StarBase.buildStarBase(); } /** @@ -85,18 +87,13 @@ export class LevelDeserializer { segments: 32 }, this.scene); sun.position = this.arrayToVector3(config.position); - // Create material using GameConfig texture level - const gameConfig = GameConfig.getInstance(); - const material = MaterialFactory.createSunMaterial( - "sunMaterial", - gameConfig.sunTextureLevel, - this.scene - ); - sun.material = material; - // Create glow layer - //const gl = new GlowLayer("glow", this.scene); - //gl.intensity = 1; + // Create PBR sun material with fire texture + const material = new PBRMaterial("sunMaterial", this.scene); + material.emissiveTexture = new FireProceduralTexture("fire", 1024, this.scene); + material.emissiveColor.set(0.5, 0.5, 0.1); + material.unlit = true; + sun.material = material; return sun; } @@ -122,16 +119,28 @@ export class LevelDeserializer { // Calculate direction from planet to sun const toSun = sunPosition.subtract(planetPosition).normalize(); - // Create material using GameConfig texture level - const config = GameConfig.getInstance(); - const material = MaterialFactory.createPlanetMaterial( - planetConfig.name + "-material", - planetConfig.texturePath, - config.planetTextureLevel, + // Create PBR planet material + const material = new PBRMaterial(planetConfig.name + "-material", this.scene); + const texture = new Texture(planetConfig.texturePath, this.scene); + + // Create lightmap with bright light pointing toward sun + const lightmap = createSphereLightmap( + planetConfig.name + "-lightmap", + 256, this.scene, - toSun + toSun, + 1, + toSun.negate(), + 0.3, + 0.3 ); + material.albedoTexture = texture; + material.lightmapTexture = lightmap; + material.useLightmapAsShadowmap = true; + material.roughness = 0.8; + material.metallic = 0; + planet.material = material; planets.push(planet); diff --git a/src/main.ts b/src/main.ts index bcbdbd0..5768993 100644 --- a/src/main.ts +++ b/src/main.ts @@ -46,20 +46,31 @@ export class Main { setLoadingMessage("This browser does not support WebXR"); return; } - this.initialize(); + // Listen for level selection event window.addEventListener('levelSelected', async (e: CustomEvent) => { + this._started = true; + await this.initialize(); const {levelName, config} = e.detail as {levelName: string, config: LevelConfig}; debugLog(`Starting level: ${levelName}`); - // Show loading UI again + // Hide all UI elements const mainDiv = document.querySelector('#mainDiv'); const levelSelect = document.querySelector('#levelSelect') as HTMLElement; + const editorLink = document.querySelector('.editor-link') as HTMLElement; + const settingsLink = document.querySelector('.settings-link') as HTMLElement; + if (levelSelect) { levelSelect.style.display = 'none'; } + if (editorLink) { + editorLink.style.display = 'none'; + } + if (settingsLink) { + settingsLink.style.display = 'none'; + } setLoadingMessage("Initializing Level..."); // Unlock audio engine on user interaction @@ -80,10 +91,15 @@ export class Main { this.play(); }, 500); }); + + // Now initialize the level (after observable is registered) + await this._currentLevel.initialize(); }); // Listen for test level button click window.addEventListener('DOMContentLoaded', () => { + const levelSelect = document.querySelector('#levelSelect'); + levelSelect.classList.add('ready'); debugLog('[Main] DOMContentLoaded fired, looking for test button...'); const testLevelBtn = document.querySelector('#testLevelBtn'); debugLog('[Main] Test button found:', !!testLevelBtn); @@ -92,9 +108,12 @@ export class Main { testLevelBtn.addEventListener('click', async () => { debugLog('[Main] ========== TEST LEVEL BUTTON CLICKED =========='); - // Show loading UI + // Hide all UI elements const mainDiv = document.querySelector('#mainDiv'); const levelSelect = document.querySelector('#levelSelect') as HTMLElement; + const editorLink = document.querySelector('.editor-link') as HTMLElement; + const settingsLink = document.querySelector('.settings-link') as HTMLElement; + debugLog('[Main] mainDiv exists:', !!mainDiv); debugLog('[Main] levelSelect exists:', !!levelSelect); @@ -102,6 +121,12 @@ export class Main { levelSelect.style.display = 'none'; debugLog('[Main] levelSelect hidden'); } + if (editorLink) { + editorLink.style.display = 'none'; + } + if (settingsLink) { + settingsLink.style.display = 'none'; + } setLoadingMessage("Initializing Test Scene..."); // Unlock audio engine on user interaction @@ -193,7 +218,6 @@ export class Main { // photoDome1.position = DefaultScene.MainScene.activeCamera.globalPosition; // photoDome2.position = DefaultScene.MainScene.activeCamera.globalPosition; }); - setLoadingMessage("Select a difficulty to begin!"); } private async setupScene() { @@ -236,11 +260,7 @@ export class Main { window.setTimeout(()=>{ if (!this._started) { this._started = true; - const levelSelect = document.querySelector('#levelSelect'); - if (levelSelect) { - levelSelect.classList.add('ready'); - setLoadingMessage("Ready!"); - } + setLoadingMessage("Ready!"); } }) @@ -250,6 +270,7 @@ export class Main { } private async setupPhysics() { + //DefaultScene.MainScene.useRightHandedSystem = true; const havok = await HavokPhysics(); const havokPlugin = new HavokPlugin(true, havok); //DefaultScene.MainScene.ambientColor = new Color3(.1, .1, .1); diff --git a/src/materialFactory.ts b/src/materialFactory.ts deleted file mode 100644 index a9197d5..0000000 --- a/src/materialFactory.ts +++ /dev/null @@ -1,305 +0,0 @@ -import { - Color3, - DynamicTexture, - NoiseProceduralTexture, - PBRMaterial, - Scene, - StandardMaterial, - Texture, - Vector3 -} from "@babylonjs/core"; -import { TextureLevel } from "./gameConfig"; -import { FireProceduralTexture } from "@babylonjs/procedural-textures"; -import { createSphereLightmap } from "./sphereLightmap"; - -/** - * Factory for creating materials at different quality levels - */ -export class MaterialFactory { - /** - * Create a planet material based on texture level - */ - public static createPlanetMaterial( - name: string, - texturePath: string, - textureLevel: TextureLevel, - scene: Scene, - sunDirection: Vector3 - ): StandardMaterial | PBRMaterial { - switch (textureLevel) { - case TextureLevel.WIREFRAME: - return this.createWireframeMaterial(name, scene, new Color3(0.5, 0.5, 0.8)); - - case TextureLevel.SIMPLE_MATERIAL: - return this.createSimplePlanetMaterial(name, scene); - - case TextureLevel.FULL_TEXTURE: - return this.createFullTexturePlanetMaterial(name, texturePath, scene, sunDirection); - - case TextureLevel.PBR_TEXTURE: - return this.createPBRPlanetMaterial(name, texturePath, scene, sunDirection); - - default: - return this.createFullTexturePlanetMaterial(name, texturePath, scene, sunDirection); - } - } - - /** - * Create an asteroid material based on texture level - */ - public static createAsteroidMaterial( - name: string, - textureLevel: TextureLevel, - scene: Scene, - originalMaterial?: PBRMaterial - ): StandardMaterial | PBRMaterial { - switch (textureLevel) { - case TextureLevel.WIREFRAME: - return this.createWireframeMaterial(name, scene, new Color3(0.5, 0.5, 0.5)); - - case TextureLevel.SIMPLE_MATERIAL: - return this.createSimpleAsteroidMaterial(name, scene); - - case TextureLevel.FULL_TEXTURE: - return this.createFullTextureAsteroidMaterial(name, scene, originalMaterial); - - case TextureLevel.PBR_TEXTURE: - return this.createPBRAsteroidMaterial(name, scene, originalMaterial); - - default: - return this.createFullTextureAsteroidMaterial(name, scene, originalMaterial); - } - } - - /** - * Create a sun material based on texture level - */ - public static createSunMaterial( - name: string, - textureLevel: TextureLevel, - scene: Scene - ): StandardMaterial | PBRMaterial { - switch (textureLevel) { - case TextureLevel.WIREFRAME: - return this.createWireframeMaterial(name, scene, new Color3(1, 1, 0)); - - case TextureLevel.SIMPLE_MATERIAL: - return this.createSimpleSunMaterial(name, scene); - - case TextureLevel.FULL_TEXTURE: - return this.createFullTextureSunMaterial(name, scene); - - case TextureLevel.PBR_TEXTURE: - return this.createPBRSunMaterial(name, scene); - - default: - return this.createFullTextureSunMaterial(name, scene); - } - } - - // ========== Private helper methods ========== - - /** - * Create wireframe material - */ - private static createWireframeMaterial( - name: string, - scene: Scene, - color: Color3 - ): StandardMaterial { - const material = new StandardMaterial(name, scene); - material.wireframe = true; - material.emissiveColor = color; - material.disableLighting = true; - return material; - } - - /** - * Create simple planet material with solid color - */ - private static createSimplePlanetMaterial(name: string, scene: Scene): StandardMaterial { - const material = new StandardMaterial(name, scene); - material.diffuseColor = new Color3(0.4, 0.6, 0.8); - material.specularColor = Color3.Black(); - return material; - } - - /** - * Create full texture planet material (current implementation) - */ - private static createFullTexturePlanetMaterial( - name: string, - texturePath: string, - scene: Scene, - sunDirection: Vector3 - ): StandardMaterial { - const material = new StandardMaterial(name, scene); - const texture = new Texture(texturePath, scene); - - // Create lightmap with bright light pointing toward sun - const lightmap = createSphereLightmap( - name + "-lightmap", - 256, - scene, - sunDirection, - 1, - sunDirection.negate(), - 0.3, - 0.3 - ); - - material.emissiveTexture = texture; - material.lightmapTexture = lightmap; - material.useLightmapAsShadowmap = true; - material.disableLighting = true; - material.roughness = 1; - material.specularColor = Color3.Black(); - material.freeze(); - - return material; - } - - /** - * Create PBR planet material - */ - private static createPBRPlanetMaterial( - name: string, - texturePath: string, - scene: Scene, - sunDirection: Vector3 - ): PBRMaterial { - const material = new PBRMaterial(name, scene); - const texture = new Texture(texturePath, scene); - - // Create lightmap with bright light pointing toward sun - const lightmap = createSphereLightmap( - name + "-lightmap", - 256, - scene, - sunDirection, - 1, - sunDirection.negate(), - 0.3, - 0.3 - ); - - material.albedoTexture = texture; - material.lightmapTexture = lightmap; - material.useLightmapAsShadowmap = true; - material.roughness = 0.8; - material.metallic = 0; - - return material; - } - - /** - * Create simple asteroid material with solid color - */ - private static createSimpleAsteroidMaterial(name: string, scene: Scene): StandardMaterial { - const material = new StandardMaterial(name, scene); - material.diffuseColor = new Color3(0.4, 0.4, 0.4); - material.specularColor = Color3.Black(); - return material; - } - - /** - * Create full texture asteroid material (current implementation) - */ - private static createFullTextureAsteroidMaterial(name: string, scene: Scene, originalMaterial?: PBRMaterial): StandardMaterial { - // If we have the original material from GLB, use it as a base - if (originalMaterial) { - // Clone the original material to preserve bump texture and other properties - const material = originalMaterial.clone(name) as PBRMaterial; - - // Create noise texture for color variation - const noiseTexture = new NoiseProceduralTexture(name + "-noise", 256, scene); - noiseTexture.brightness = 0.6; - noiseTexture.octaves = 4; - - // Replace only the albedo texture, keeping bump and other textures - material.albedoTexture = noiseTexture; - material.roughness = 1; - - return material as any as StandardMaterial; - } - - // Fallback if no original material - const material = new StandardMaterial(name, scene); - const noiseTexture = new NoiseProceduralTexture(name + "-noise", 256, scene); - noiseTexture.brightness = 0.6; - noiseTexture.octaves = 4; - - material.ambientTexture = noiseTexture; - material.diffuseTexture = noiseTexture; - material.roughness = 1; - - return material; - } - - /** - * Create PBR asteroid material - */ - private static createPBRAsteroidMaterial(name: string, scene: Scene, originalMaterial?: PBRMaterial): PBRMaterial { - // If we have the original material from GLB, use it as a base - if (originalMaterial) { - // Clone the original material to preserve bump texture and other properties - const material = originalMaterial.clone(name) as PBRMaterial; - - // Create noise texture for color variation - const noiseTexture = new NoiseProceduralTexture(name + "-noise", 256, scene); - noiseTexture.brightness = 0.6; - noiseTexture.octaves = 4; - - // Replace only the albedo texture, keeping bump and other textures - material.albedoTexture = noiseTexture; - material.roughness = 1; - material.metallic = 0; - - return material; - } - - // Fallback if no original material - const material = new PBRMaterial(name, scene); - const noiseTexture = new NoiseProceduralTexture(name + "-noise", 256, scene); - noiseTexture.brightness = 0.6; - noiseTexture.octaves = 4; - - material.albedoTexture = noiseTexture; - material.roughness = 1; - material.metallic = 0; - - return material; - } - - /** - * Create simple sun material with solid color - */ - private static createSimpleSunMaterial(name: string, scene: Scene): StandardMaterial { - const material = new StandardMaterial(name, scene); - material.emissiveColor = new Color3(1, 0.9, 0.2); - material.disableLighting = true; - return material; - } - - /** - * Create full texture sun material (current implementation) - */ - private static createFullTextureSunMaterial(name: string, scene: Scene): StandardMaterial { - const material = new StandardMaterial(name, scene); - material.emissiveTexture = new FireProceduralTexture("fire", 1024, scene); - material.emissiveColor = new Color3(0.5, 0.5, 0.1); - material.disableLighting = true; - return material; - } - - /** - * Create PBR sun material - */ - private static createPBRSunMaterial(name: string, scene: Scene): PBRMaterial { - const material = new PBRMaterial(name, scene); - material.emissiveTexture = new FireProceduralTexture("fire", 1024, scene); - material.emissiveColor = new Color3(0.5, 0.5, 0.1); - material.unlit = true; - return material; - } -} diff --git a/src/rockFactory.ts b/src/rockFactory.ts index f2f97f2..5b9671f 100644 --- a/src/rockFactory.ts +++ b/src/rockFactory.ts @@ -55,7 +55,7 @@ export class RockFactory { private static async loadMesh() { debugLog('loading mesh'); this._asteroidMesh = (await loadAsset("asteroid.glb")).meshes.get('Asteroid'); - this._asteroidMesh.setParent(null); + //this._asteroidMesh.setParent(null); this._asteroidMesh.setEnabled(false); debugLog(this._asteroidMesh); } diff --git a/src/settingsScreen.ts b/src/settingsScreen.ts index 41ef983..3a88255 100644 --- a/src/settingsScreen.ts +++ b/src/settingsScreen.ts @@ -1,4 +1,4 @@ -import { GameConfig, TextureLevel } from "./gameConfig"; +import { GameConfig } from "./gameConfig"; /** * Initialize the settings screen @@ -7,9 +7,6 @@ export function initializeSettingsScreen(): void { const config = GameConfig.getInstance(); // Get form elements - const planetTextureSelect = document.getElementById('planetTextureLevel') as HTMLSelectElement; - const asteroidTextureSelect = document.getElementById('asteroidTextureLevel') as HTMLSelectElement; - const sunTextureSelect = document.getElementById('sunTextureLevel') as HTMLSelectElement; const physicsEnabledCheckbox = document.getElementById('physicsEnabled') as HTMLInputElement; const debugEnabledCheckbox = document.getElementById('debugEnabled') as HTMLInputElement; @@ -39,9 +36,6 @@ export function initializeSettingsScreen(): void { * Load current settings into form */ function loadSettings(): void { - if (planetTextureSelect) planetTextureSelect.value = config.planetTextureLevel; - if (asteroidTextureSelect) asteroidTextureSelect.value = config.asteroidTextureLevel; - if (sunTextureSelect) sunTextureSelect.value = config.sunTextureLevel; if (physicsEnabledCheckbox) physicsEnabledCheckbox.checked = config.physicsEnabled; if (debugEnabledCheckbox) debugEnabledCheckbox.checked = config.debug; } @@ -50,9 +44,6 @@ export function initializeSettingsScreen(): void { * Save form settings to GameConfig */ function saveSettings(): void { - config.planetTextureLevel = planetTextureSelect.value as TextureLevel; - config.asteroidTextureLevel = asteroidTextureSelect.value as TextureLevel; - config.sunTextureLevel = sunTextureSelect.value as TextureLevel; config.physicsEnabled = physicsEnabledCheckbox.checked; config.debug = debugEnabledCheckbox.checked; config.save(); diff --git a/src/ship.ts b/src/ship.ts index 7090253..2e56bb3 100644 --- a/src/ship.ts +++ b/src/ship.ts @@ -8,7 +8,6 @@ import { PhysicsAggregate, PhysicsMotionType, PhysicsShapeType, - SceneLoader, StandardMaterial, TransformNode, Vector2, @@ -23,10 +22,12 @@ import { GameConfig } from "./gameConfig"; import { Sight } from "./sight"; import debugLog from './debug'; import {Scoreboard} from "./scoreboard"; +import loadAsset from "./utils/loadAsset"; +import {Debug} from "@babylonjs/core/Legacy/legacy"; const MAX_LINEAR_VELOCITY = 200; -const MAX_ANGULAR_VELOCITY = 1.8; -const LINEAR_FORCE_MULTIPLIER = 1200; -const ANGULAR_FORCE_MULTIPLIER = 20; +const MAX_ANGULAR_VELOCITY = 1.4; +const LINEAR_FORCE_MULTIPLIER = 800; +const ANGULAR_FORCE_MULTIPLIER = 15; const controllerComponents = [ 'a-button', @@ -69,8 +70,6 @@ export class Ship { constructor( audioEngine?: AudioEngineV2) { this._audioEngine = audioEngine; - this.setup(); - this.initialize(); } private async initializeSounds() { @@ -102,8 +101,8 @@ export class Ship { this._shot?.play(); const ammo = new InstancedMesh("ammo", this._ammoBaseMesh as Mesh); ammo.parent = this._ship; - ammo.position.y = .5; - ammo.position.z = 7.1; + ammo.position.y = .1; + ammo.position.z = 8.4; //ammo.rotation.x = Math.PI / 2; ammo.setParent(null); const ammoAggregate = new PhysicsAggregate(ammo, PhysicsShapeType.SPHERE, { @@ -141,13 +140,48 @@ export class Ship { }) } - private setup() { - this._ship = new TransformNode("ship", DefaultScene.MainScene); + public async initialize() { + this._scoreboard = new Scoreboard(); + this._ship = new TransformNode("shipBawe", DefaultScene.MainScene); + //this._ship.rotation.y = Math.PI; + const data = await loadAsset('ship.glb'); + const axes = new Debug.AxesViewer(DefaultScene.MainScene, 1); + //axes.xAxis.parent = data.container.rootNodes[0]; + //axes.yAxis.parent = data.container.rootNodes[0]; + axes.zAxis.parent = data.container.transformNodes[0]; + //data.container.transformNodes[0].parent = this._ship; + this._ship = data.container.transformNodes[0]; + this._ship.position.y = 5; + + const config = GameConfig.getInstance(); + if (config.physicsEnabled) { + console.log('Physics Enabled for Ship'); + if (this._ship) { + const agg = new PhysicsAggregate( + this._ship, + PhysicsShapeType.MESH, + { + mass: 10, + mesh: data.container.rootNodes[0].getChildMeshes()[0] as Mesh + }, + DefaultScene.MainScene + ); + + agg.body.setMotionType(PhysicsMotionType.DYNAMIC); + agg.body.setLinearDamping(.2); + agg.body.setAngularDamping(.4); + agg.body.setAngularVelocity(new Vector3(0, 0, 0)); + agg.body.setCollisionCallbackEnabled(true); + + } else { + console.warn("No geometry mesh found, cannot create physics"); + } + } + //shipMesh.position.z = -1; - // Create sounds asynchronously if audio engine is available if (this._audioEngine) { - this.initializeSounds(); + await this.initializeSounds(); } this._ammoMaterial = new StandardMaterial("ammoMaterial", DefaultScene.MainScene); this._ammoMaterial.emissiveColor = new Color3(1, 1, 0); @@ -158,8 +192,8 @@ export class Ship { //const landingLight = new SpotLight("landingLight", new Vector3(0, 0, 0), new Vector3(0, -.5, .5), 1.5, .5, DefaultScene.MainScene); - // landingLight.parent = this._ship; - // landingLight.position.z = 5; + // landingLight.parent = this._ship; + // landingLight.position.z = 5; // Physics will be set up after mesh loads in initialize() @@ -171,11 +205,11 @@ export class Ship { DefaultScene.MainScene); this._camera.parent = this._ship; - DefaultScene.MainScene.setActiveCameraByName("Flat Camera"); + //DefaultScene.MainScene.setActiveCameraByName("Flat Camera"); // Create sight reticle this._sight = new Sight(DefaultScene.MainScene, this._ship, { - position: new Vector3(0, .5, 125), + position: new Vector3(0, .1, 125), circleRadius: 2, crosshairLength: 1.5, lineThickness: 0.1, @@ -183,78 +217,20 @@ export class Ship { renderingGroupId: 3, centerGap: 0.5 }); + console.log(data.meshes.get('Screen')); + const screen = DefaultScene.MainScene.getMaterialById('Screen').getBindedMeshes()[0] as Mesh + console.log(screen); + const old = screen.parent; + screen.setParent(null); + screen.setPivotPoint(screen.getBoundingInfo().boundingSphere.center); + screen.setParent(old); + screen.rotation.y = Math.PI; + console.log(screen.rotation); + console.log(screen.scaling); - } + this._scoreboard.initialize(screen); - private async initialize() { - this._scoreboard = new Scoreboard(); - - const importMesh = await SceneLoader.ImportMeshAsync(null, "./", "ship2.glb", DefaultScene.MainScene); - - const shipMesh = importMesh.meshes[0]; - shipMesh.id = "shipMesh"; - shipMesh.name = "shipMesh"; - debugLog(shipMesh.position); - shipMesh.parent = this._ship; - debugLog(shipMesh.position); - - // Create physics aggregate based on the loaded mesh (if physics enabled) - const config = GameConfig.getInstance(); - if (config.physicsEnabled) { - // Find the actual geometry mesh (usually meshes[1] or a child) - //const geometryMesh = importMesh.meshes.find(m => m instanceof Mesh && m.getTotalVertices() > 0) as Mesh; - const geo = shipMesh.getChildMeshes()[0] - if (geo) { - - - // Create physics aggregate on the ship TransformNode using the mesh shape - const agg = new PhysicsAggregate(this._ship, PhysicsShapeType.CONVEX_HULL, { - mass: 100, - mesh: (geo as Mesh) // Use the actual ship geometry - }, DefaultScene.MainScene); - - - agg.body.setMotionType(PhysicsMotionType.DYNAMIC); - agg.body.setLinearDamping(.2); - agg.body.setAngularDamping(.3); - agg.body.setAngularVelocity(new Vector3(0, 0, 0)); - agg.body.setCollisionCallbackEnabled(true); - } else { - console.warn("No geometry mesh found in ship1.glb, falling back to box shape"); - // Fallback to box shape if mesh not found - const agg = new PhysicsAggregate(this._ship, PhysicsShapeType.BOX, { - mass: 100, - extents: new Vector3(4, 4, 7.4), - center: new Vector3(0, 1, 1.8) - }, DefaultScene.MainScene); - - agg.body.setMotionType(PhysicsMotionType.DYNAMIC); - agg.body.setLinearDamping(.1); - agg.body.setAngularDamping(.2); - agg.body.setAngularVelocity(new Vector3(0, 0, 0)); - agg.body.setCollisionCallbackEnabled(true); - } - } - //shipMesh.rotation.y = Angle.FromDegrees(90).radians(); - //shipMesh.rotation.y = Math.PI; - //shipMesh.position.y = 1; - shipMesh.position.z = -1; - // shipMesh.renderingGroupId = 3; - //const light = new PointLight("ship.light", new Vector3(0, .5, .1), DefaultScene.MainScene); - //light.intensity = 4; - /*light.includedOnlyMeshes = [shipMesh]; - for (const mesh of shipMesh.getChildMeshes()) { - // mesh.renderingGroupId = 3; - if (mesh.material.id.indexOf('glass') === -1) { - light.includedOnlyMeshes.push(mesh); - } - } - light.parent = this._ship;*/ - //DefaultScene.MainScene.getMaterialById('glass_mat.002').alpha = .4; - const screenMesh = DefaultScene.MainScene.getMaterialById('Screen')?.getBindedMeshes()[0]; - this._scoreboard.initialize(screenMesh as Mesh); - //this._scoreboard.initialize(null); } @@ -287,7 +263,8 @@ export class Ship { // Transform to world space - TransformNode vectors are in local space! const worldDirection = Vector3.TransformNormal(localDirection, this._ship.getWorldMatrix()); const force = worldDirection.scale(LINEAR_FORCE_MULTIPLIER); - body.applyForce(force, this._ship.physicsBody.transformNode.absolutePosition); + const thrustPoint = Vector3.TransformCoordinates(this._ship.physicsBody.getMassProperties().centerOfMass.add(new Vector3(0,1,0)), this._ship.getWorldMatrix()); + body.applyForce(force, thrustPoint); } @@ -318,9 +295,9 @@ export class Ship { // Only apply torque if we haven't reached max angular velocity if (currentAngularSpeed < MAX_ANGULAR_VELOCITY) { - const yaw = this._leftStickVector.x; - const pitch = -this._rightStickVector.y; - const roll = -this._rightStickVector.x; + const yaw = -this._leftStickVector.x; + const pitch = this._rightStickVector.y; + const roll = this._rightStickVector.x; // Create torque in local space, then transform to world space const localTorque = new Vector3(pitch, yaw, roll).scale(ANGULAR_FORCE_MULTIPLIER); diff --git a/src/starBase.ts b/src/starBase.ts index 0e884fc..dc4d152 100644 --- a/src/starBase.ts +++ b/src/starBase.ts @@ -1,6 +1,6 @@ import { AbstractMesh, - HavokPlugin, + HavokPlugin, Mesh, PhysicsAggregate, PhysicsMotionType, PhysicsShapeType, @@ -17,13 +17,14 @@ import loadAsset from "./utils/loadAsset"; * @returns Promise resolving to the loaded star base mesh */ export default class StarBase { - public static async buildStarBase(position: Vector3): Promise { + public static async buildStarBase(): Promise { const config = GameConfig.getInstance(); const scene = DefaultScene.MainScene; const importMeshes = await loadAsset('base.glb'); + const baseMesh = importMeshes.meshes.get('Base'); const landingMesh = importMeshes.meshes.get('BaseLandingZone'); - clearParent(importMeshes.meshes, position); + if (config.physicsEnabled) { @@ -38,14 +39,14 @@ export default class StarBase { const landingAgg = new PhysicsAggregate(landingMesh, PhysicsShapeType.MESH); landingAgg.body.setMotionType(PhysicsMotionType.ANIMATED); - landingAgg.body.getCollisionObservable().add((collidedCollidedBody) => { - console.log(collidedCollidedBody); - }); + /*landingAgg.body.getCollisionObservable().add((collidedCollidedBody) => { + + });*/ landingAgg.shape.isTrigger = true; - (DefaultScene.MainScene.getPhysicsEngine().getPhysicsPlugin() as HavokPlugin).onTriggerCollisionObservable.add((eventdata, eventState) => { + /*(DefaultScene.MainScene.getPhysicsEngine().getPhysicsPlugin() as HavokPlugin).onTriggerCollisionObservable.add((eventdata, eventState) => { console.log(eventState); console.log(eventdata); - }) + })*/ landingAgg.body.setCollisionCallbackEnabled(true); } //importMesh.rootNodes[0].dispose(); diff --git a/src/utils/loadAsset.ts b/src/utils/loadAsset.ts index 83ae0c1..861d1e0 100644 --- a/src/utils/loadAsset.ts +++ b/src/utils/loadAsset.ts @@ -8,7 +8,12 @@ export type LoadedAsset = { export default async function loadAsset(file: string, theme: string = "default"): Promise { const container = await LoadAssetContainerAsync(`assets/themes/${theme}/models/${file}`, DefaultScene.MainScene); const map: Map = new Map(); + container.addAllToScene(); for (const mesh of container.rootNodes[0].getChildMeshes(false)) { + console.log(mesh.id, mesh); + //mesh.setParent(null); + //mesh.rotation.y = Math.PI /2; + //mesh.rotation.z = Math.PI; map.set(mesh.id, mesh); } return {container: container, meshes: map}; diff --git a/themes/default/base.blend b/themes/default/base.blend index 2e7c090..9909936 100644 Binary files a/themes/default/base.blend and b/themes/default/base.blend differ diff --git a/themes/default/base.blend1 b/themes/default/base.blend1 new file mode 100644 index 0000000..2e7c090 Binary files /dev/null and b/themes/default/base.blend1 differ diff --git a/themes/default/ship.blend b/themes/default/ship.blend index 31d1d95..c48d5b6 100644 Binary files a/themes/default/ship.blend and b/themes/default/ship.blend differ diff --git a/themes/default/ship.blend1 b/themes/default/ship.blend1 new file mode 100644 index 0000000..31d1d95 Binary files /dev/null and b/themes/default/ship.blend1 differ