Migrate to AudioEngineV2 and fix Meta Quest 2 controller detection
- Upgrade audio system from deprecated Sound API to AudioEngineV2 - Use CreateAudioEngineAsync() for audio engine initialization - Replace new Sound() with createSoundAsync() throughout codebase - Track sound playing state manually (StaticSound lacks isPlaying) - Use volume property instead of setVolume() method - Use stop() instead of pause() for proper StaticSound lifecycle - Fix controller detection for Meta Quest 2 - Check for already-connected controllers after entering XR mode - Fixes issue where Quest 2 controllers only become available after enterXRAsync() - Maintains backward compatibility with WebXR emulator - Improve initialization performance - Move RockFactory.init() to main initialization (before level select) - Pre-load asteroid meshes and explosion particle systems on startup - Level initialization now only creates asteroids, not resources - Refactor level initialization flow - Level creation now happens before entering XR mode - Add level ready observable to track initialization completion - Show loading messages during asteroid creation - Extract loading message logic to separate module - Add audio unlock on user interaction (button click) - Make play() methods async to support AudioEngineV2 - Pass AudioEngineV2 instance to Ship and Level1 constructors 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
d2aec0a87b
commit
57ffe8f689
BIN
public/song1.mp3
Normal file
BIN
public/song1.mp3
Normal file
Binary file not shown.
@ -7,15 +7,17 @@ import {
|
|||||||
ParticleHelper,
|
ParticleHelper,
|
||||||
PhysicsAggregate,
|
PhysicsAggregate,
|
||||||
PhysicsMotionType,
|
PhysicsMotionType,
|
||||||
PhysicsShapeType, PointsCloudSystem, Sound,
|
PhysicsShapeType, PointsCloudSystem,
|
||||||
StandardMaterial, TransformNode,
|
StandardMaterial, TransformNode,
|
||||||
Vector3
|
Vector3
|
||||||
} from "@babylonjs/core";
|
} from "@babylonjs/core";
|
||||||
|
import type {AudioEngineV2} from "@babylonjs/core";
|
||||||
import {Ship} from "./ship";
|
import {Ship} from "./ship";
|
||||||
|
|
||||||
import {RockFactory} from "./starfield";
|
import {RockFactory} from "./starfield";
|
||||||
import Level from "./level";
|
import Level from "./level";
|
||||||
import {Scoreboard} from "./scoreboard";
|
import {Scoreboard} from "./scoreboard";
|
||||||
|
import setLoadingMessage from "./setLoadingMessage";
|
||||||
|
|
||||||
export class Level1 implements Level {
|
export class Level1 implements Level {
|
||||||
private _ship: Ship;
|
private _ship: Ship;
|
||||||
@ -25,6 +27,7 @@ export class Level1 implements Level {
|
|||||||
private _endBase: AbstractMesh;
|
private _endBase: AbstractMesh;
|
||||||
private _scoreboard: Scoreboard;
|
private _scoreboard: Scoreboard;
|
||||||
private _difficulty: string;
|
private _difficulty: string;
|
||||||
|
private _audioEngine: AudioEngineV2;
|
||||||
private _difficultyConfig: {
|
private _difficultyConfig: {
|
||||||
rockCount: number;
|
rockCount: number;
|
||||||
forceMultiplier: number;
|
forceMultiplier: number;
|
||||||
@ -34,10 +37,11 @@ export class Level1 implements Level {
|
|||||||
distanceMax: number;
|
distanceMax: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(difficulty: string = 'recruit') {
|
constructor(difficulty: string = 'recruit', audioEngine: AudioEngineV2) {
|
||||||
this._difficulty = difficulty;
|
this._difficulty = difficulty;
|
||||||
|
this._audioEngine = audioEngine;
|
||||||
this._difficultyConfig = this.getDifficultyConfig(difficulty);
|
this._difficultyConfig = this.getDifficultyConfig(difficulty);
|
||||||
this._ship = new Ship();
|
this._ship = new Ship(undefined, audioEngine);
|
||||||
this._scoreboard = new Scoreboard();
|
this._scoreboard = new Scoreboard();
|
||||||
const xr = DefaultScene.XR;
|
const xr = DefaultScene.XR;
|
||||||
xr.baseExperience.onInitialXRPoseSetObservable.add(() => {
|
xr.baseExperience.onInitialXRPoseSetObservable.add(() => {
|
||||||
@ -47,6 +51,7 @@ export class Level1 implements Level {
|
|||||||
xr.input.onControllerAddedObservable.add((controller) => {
|
xr.input.onControllerAddedObservable.add((controller) => {
|
||||||
this._ship.addController(controller);
|
this._ship.addController(controller);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.createStartBase();
|
this.createStartBase();
|
||||||
this.initialize();
|
this.initialize();
|
||||||
|
|
||||||
@ -116,10 +121,21 @@ export class Level1 implements Level {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private scored: Set<string> = new Set<string>();
|
private scored: Set<string> = new Set<string>();
|
||||||
public play() {
|
public async play() {
|
||||||
const background = new Sound("background", "/background.mp3", DefaultScene.MainScene, () => {
|
// Create background music using AudioEngineV2
|
||||||
}, {loop: true, autoplay: true, volume: .2});
|
const background = await this._audioEngine.createSoundAsync("background", "/song1.mp3", {
|
||||||
DefaultScene.XR.baseExperience.enterXRAsync('immersive-vr', 'local-floor');
|
loop: true,
|
||||||
|
volume: 0.2
|
||||||
|
});
|
||||||
|
background.play();
|
||||||
|
|
||||||
|
// Enter XR mode
|
||||||
|
await DefaultScene.XR.baseExperience.enterXRAsync('immersive-vr', 'local-floor');
|
||||||
|
|
||||||
|
// Check for controllers that are already connected after entering XR
|
||||||
|
DefaultScene.XR.input.controllers.forEach((controller) => {
|
||||||
|
this._ship.addController(controller);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
public dispose() {
|
public dispose() {
|
||||||
this._startBase.dispose();
|
this._startBase.dispose();
|
||||||
@ -130,13 +146,13 @@ export class Level1 implements Level {
|
|||||||
if (this._initialized) {
|
if (this._initialized) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
this.createBackgroundElements();
|
||||||
this._initialized = true;
|
this._initialized = true;
|
||||||
ParticleHelper.BaseAssetsUrl = window.location.href;
|
|
||||||
this._ship.position = new Vector3(0, 1, 0);
|
this._ship.position = new Vector3(0, 1, 0);
|
||||||
await RockFactory.init();
|
|
||||||
|
|
||||||
const config = this._difficultyConfig;
|
const config = this._difficultyConfig;
|
||||||
console.log(config);
|
console.log(config);
|
||||||
|
setLoadingMessage("Creating Asteroids...");
|
||||||
for (let i = 0; i < config.rockCount; i++) {
|
for (let i = 0; i < config.rockCount; i++) {
|
||||||
const distRange = config.distanceMax - config.distanceMin;
|
const distRange = config.distanceMax - config.distanceMin;
|
||||||
const dist = (Math.random() * distRange) + config.distanceMin;
|
const dist = (Math.random() * distRange) + config.distanceMin;
|
||||||
@ -170,6 +186,9 @@ export class Level1 implements Level {
|
|||||||
this._startBase.physicsBody.addConstraint(rock.physicsBody, constraint);
|
this._startBase.physicsBody.addConstraint(rock.physicsBody, constraint);
|
||||||
rock.physicsBody.applyForce(Vector3.Random(-1, 1).scale(5000000 * config.forceMultiplier), rock.position);
|
rock.physicsBody.applyForce(Vector3.Random(-1, 1).scale(5000000 * config.forceMultiplier), rock.position);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Notify that initialization is complete
|
||||||
|
this._onReadyObservable.notifyObservers(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private createStartBase() {
|
private createStartBase() {
|
||||||
@ -200,6 +219,13 @@ export class Level1 implements Level {
|
|||||||
agg.body.setMotionType(PhysicsMotionType.ANIMATED);
|
agg.body.setMotionType(PhysicsMotionType.ANIMATED);
|
||||||
this._endBase = mesh;
|
this._endBase = mesh;
|
||||||
}
|
}
|
||||||
|
private createBackgroundElements() {
|
||||||
|
const sun = MeshBuilder.CreateSphere("sun", {diameter: 200}, DefaultScene.MainScene);
|
||||||
|
const sunMaterial = new StandardMaterial("sunMaterial", DefaultScene.MainScene);
|
||||||
|
sunMaterial.emissiveColor = new Color3(1, 1, 0);
|
||||||
|
sun.material = sunMaterial;
|
||||||
|
sun.position = new Vector3(-200, 300, 500);
|
||||||
|
}
|
||||||
|
|
||||||
private createTarget(i: number) {
|
private createTarget(i: number) {
|
||||||
const target = MeshBuilder.CreateTorus("target" + i, {diameter: 10, tessellation: 72}, DefaultScene.MainScene);
|
const target = MeshBuilder.CreateTorus("target" + i, {diameter: 10, tessellation: 72}, DefaultScene.MainScene);
|
||||||
|
|||||||
76
src/main.ts
76
src/main.ts
@ -1,13 +1,16 @@
|
|||||||
import {
|
import {
|
||||||
Color3,
|
Color3,
|
||||||
|
CreateAudioEngineAsync,
|
||||||
Engine,
|
Engine,
|
||||||
HavokPlugin,
|
HavokPlugin,
|
||||||
|
ParticleHelper,
|
||||||
PhotoDome,
|
PhotoDome,
|
||||||
Scene, StandardMaterial,
|
Scene, StandardMaterial,
|
||||||
Vector3,
|
Vector3,
|
||||||
WebGPUEngine,
|
WebGPUEngine,
|
||||||
WebXRDefaultExperience
|
WebXRDefaultExperience
|
||||||
} from "@babylonjs/core";
|
} from "@babylonjs/core";
|
||||||
|
import type {AudioEngineV2} from "@babylonjs/core";
|
||||||
import '@babylonjs/loaders';
|
import '@babylonjs/loaders';
|
||||||
import HavokPhysics from "@babylonjs/havok";
|
import HavokPhysics from "@babylonjs/havok";
|
||||||
|
|
||||||
@ -17,6 +20,8 @@ import {Level1} from "./level1";
|
|||||||
import {Scoreboard} from "./scoreboard";
|
import {Scoreboard} from "./scoreboard";
|
||||||
import Demo from "./demo";
|
import Demo from "./demo";
|
||||||
import Level from "./level";
|
import Level from "./level";
|
||||||
|
import setLoadingMessage from "./setLoadingMessage";
|
||||||
|
import {RockFactory} from "./starfield";
|
||||||
|
|
||||||
const webGpu = false;
|
const webGpu = false;
|
||||||
const canvas = (document.querySelector('#gameCanvas') as HTMLCanvasElement);
|
const canvas = (document.querySelector('#gameCanvas') as HTMLCanvasElement);
|
||||||
@ -25,44 +30,62 @@ enum GameState {
|
|||||||
DEMO
|
DEMO
|
||||||
}
|
}
|
||||||
export class Main {
|
export class Main {
|
||||||
private _loadingDiv: HTMLElement;
|
|
||||||
private _currentLevel: Level;
|
private _currentLevel: Level;
|
||||||
private _gameState: GameState = GameState.DEMO;
|
private _gameState: GameState = GameState.DEMO;
|
||||||
private _selectedDifficulty: string = 'recruit';
|
private _selectedDifficulty: string = 'recruit';
|
||||||
private _engine: Engine | WebGPUEngine;
|
private _engine: Engine | WebGPUEngine;
|
||||||
|
private _audioEngine: AudioEngineV2;
|
||||||
constructor() {
|
constructor() {
|
||||||
this._loadingDiv = document.querySelector('#loadingDiv');
|
|
||||||
if (!navigator.xr) {
|
if (!navigator.xr) {
|
||||||
this._loadingDiv.innerText = "This browser does not support WebXR";
|
setLoadingMessage("This browser does not support WebXR");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.initialize();
|
this.initialize();
|
||||||
|
|
||||||
document.querySelectorAll('.level-button').forEach(button => {
|
document.querySelectorAll('.level-button').forEach(button => {
|
||||||
button.addEventListener('click', (e) => {
|
button.addEventListener('click', async (e) => {
|
||||||
const levelButton = e.target as HTMLButtonElement;
|
const levelButton = e.target as HTMLButtonElement;
|
||||||
this._selectedDifficulty = levelButton.dataset.level;
|
this._selectedDifficulty = levelButton.dataset.level;
|
||||||
this.setLoadingMessage("Initializing Level...");
|
|
||||||
this._currentLevel = new Level1(this._selectedDifficulty);
|
// Show loading UI again
|
||||||
// Unlock audio engine if it exists
|
const mainDiv = document.querySelector('#mainDiv');
|
||||||
if (this._engine?.audioEngine) {
|
const levelSelect = document.querySelector('#levelSelect') as HTMLElement;
|
||||||
this._engine.audioEngine.unlock();
|
if (levelSelect) {
|
||||||
|
levelSelect.style.display = 'none';
|
||||||
}
|
}
|
||||||
this.play();
|
setLoadingMessage("Initializing Level...");
|
||||||
document.querySelector('#mainDiv').remove();
|
|
||||||
|
// Unlock audio engine on user interaction
|
||||||
|
if (this._audioEngine) {
|
||||||
|
await this._audioEngine.unlockAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create and initialize level BEFORE entering XR
|
||||||
|
this._currentLevel = new Level1(this._selectedDifficulty, this._audioEngine);
|
||||||
|
|
||||||
|
// Wait for level to be ready
|
||||||
|
this._currentLevel.getReadyObservable().add(() => {
|
||||||
|
setLoadingMessage("Level Ready! Entering VR...");
|
||||||
|
|
||||||
|
// Small delay to show message
|
||||||
|
setTimeout(() => {
|
||||||
|
mainDiv.remove();
|
||||||
|
this.play();
|
||||||
|
}, 500);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
private _started = false;
|
private _started = false;
|
||||||
public play() {
|
public async play() {
|
||||||
this._gameState = GameState.PLAY;
|
this._gameState = GameState.PLAY;
|
||||||
this._currentLevel.play();
|
await this._currentLevel.play();
|
||||||
}
|
}
|
||||||
public demo() {
|
public demo() {
|
||||||
this._gameState = GameState.DEMO;
|
this._gameState = GameState.DEMO;
|
||||||
}
|
}
|
||||||
private async initialize() {
|
private async initialize() {
|
||||||
this._loadingDiv.innerText = "Initializing.";
|
setLoadingMessage("Initializing.");
|
||||||
await this.setupScene();
|
await this.setupScene();
|
||||||
|
|
||||||
DefaultScene.XR = await WebXRDefaultExperience.CreateAsync(DefaultScene.MainScene, {
|
DefaultScene.XR = await WebXRDefaultExperience.CreateAsync(DefaultScene.MainScene, {
|
||||||
@ -73,7 +96,7 @@ export class Main {
|
|||||||
disableDefaultUI: true,
|
disableDefaultUI: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
this.setLoadingMessage("Get Ready!");
|
setLoadingMessage("Get Ready!");
|
||||||
|
|
||||||
const photoDome1 = new PhotoDome("testdome", '/8192.webp', {size: 1000}, DefaultScene.MainScene);
|
const photoDome1 = new PhotoDome("testdome", '/8192.webp', {size: 1000}, DefaultScene.MainScene);
|
||||||
photoDome1.material.diffuseTexture.hasAlpha = true;
|
photoDome1.material.diffuseTexture.hasAlpha = true;
|
||||||
@ -86,10 +109,9 @@ export class Main {
|
|||||||
photoDome1.position = DefaultScene.MainScene.activeCamera.globalPosition;
|
photoDome1.position = DefaultScene.MainScene.activeCamera.globalPosition;
|
||||||
photoDome2.position = DefaultScene.MainScene.activeCamera.globalPosition;
|
photoDome2.position = DefaultScene.MainScene.activeCamera.globalPosition;
|
||||||
});
|
});
|
||||||
|
setLoadingMessage("Select a difficulty to begin!");
|
||||||
}
|
}
|
||||||
private setLoadingMessage(message: string) {
|
|
||||||
this._loadingDiv.innerText = message;
|
|
||||||
}
|
|
||||||
private async setupScene() {
|
private async setupScene() {
|
||||||
|
|
||||||
if (webGpu) {
|
if (webGpu) {
|
||||||
@ -106,14 +128,24 @@ export class Main {
|
|||||||
DefaultScene.MainScene = new Scene(this._engine);
|
DefaultScene.MainScene = new Scene(this._engine);
|
||||||
DefaultScene.MainScene.ambientColor = new Color3(.2, .2, .2);
|
DefaultScene.MainScene.ambientColor = new Color3(.2, .2, .2);
|
||||||
|
|
||||||
this.setLoadingMessage("Initializing Physics Engine..");
|
setLoadingMessage("Initializing Physics Engine..");
|
||||||
await this.setupPhysics();
|
await this.setupPhysics();
|
||||||
this.setLoadingMessage("Physics Engine Ready!");
|
setLoadingMessage("Physics Engine Ready!");
|
||||||
|
|
||||||
|
setLoadingMessage("Loading Asteroids and Explosions...");
|
||||||
|
ParticleHelper.BaseAssetsUrl = window.location.href;
|
||||||
|
await RockFactory.init();
|
||||||
|
setLoadingMessage("Ready!");
|
||||||
|
|
||||||
|
// Initialize AudioEngineV2
|
||||||
|
setLoadingMessage("Initializing Audio Engine...");
|
||||||
|
this._audioEngine = await CreateAudioEngineAsync();
|
||||||
|
setLoadingMessage("Ready!");
|
||||||
|
|
||||||
this.setupInspector();
|
this.setupInspector();
|
||||||
this._engine.runRenderLoop(() => {
|
this._engine.runRenderLoop(() => {
|
||||||
if (!this._started) {
|
if (!this._started) {
|
||||||
this._started = true;
|
this._started = true;
|
||||||
this._loadingDiv.remove();
|
|
||||||
const levelSelect = document.querySelector('#levelSelect');
|
const levelSelect = document.querySelector('#levelSelect');
|
||||||
if (levelSelect) {
|
if (levelSelect) {
|
||||||
levelSelect.classList.add('ready');
|
levelSelect.classList.add('ready');
|
||||||
@ -136,7 +168,7 @@ export class Main {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private setupInspector() {
|
private setupInspector() {
|
||||||
this.setLoadingMessage("Initializing Inspector...");
|
setLoadingMessage("Initializing Inspector...");
|
||||||
window.addEventListener("keydown", (ev) => {
|
window.addEventListener("keydown", (ev) => {
|
||||||
if (ev.key == 'i') {
|
if (ev.key == 'i') {
|
||||||
import ("@babylonjs/inspector").then((inspector) => {
|
import ("@babylonjs/inspector").then((inspector) => {
|
||||||
|
|||||||
6
src/setLoadingMessage.ts
Normal file
6
src/setLoadingMessage.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
let loadingDiv: HTMLElement = document.querySelector('#loadingDiv') as HTMLElement;
|
||||||
|
export default function setLoadingMessage(message:string) {
|
||||||
|
if (loadingDiv) {
|
||||||
|
loadingDiv.innerText = message;
|
||||||
|
}
|
||||||
|
}
|
||||||
75
src/ship.ts
75
src/ship.ts
@ -10,7 +10,6 @@ import {
|
|||||||
PhysicsMotionType,
|
PhysicsMotionType,
|
||||||
PhysicsShapeType,
|
PhysicsShapeType,
|
||||||
SceneLoader,
|
SceneLoader,
|
||||||
Sound,
|
|
||||||
SpotLight,
|
SpotLight,
|
||||||
StandardMaterial,
|
StandardMaterial,
|
||||||
TransformNode,
|
TransformNode,
|
||||||
@ -20,6 +19,7 @@ import {
|
|||||||
WebXRControllerComponent,
|
WebXRControllerComponent,
|
||||||
WebXRInputSource
|
WebXRInputSource
|
||||||
} from "@babylonjs/core";
|
} from "@babylonjs/core";
|
||||||
|
import type {AudioEngineV2, StaticSound} from "@babylonjs/core";
|
||||||
import {DefaultScene} from "./defaultScene";
|
import {DefaultScene} from "./defaultScene";
|
||||||
const MAX_FORWARD_THRUST = 40;
|
const MAX_FORWARD_THRUST = 40;
|
||||||
|
|
||||||
@ -58,16 +58,20 @@ export class Ship {
|
|||||||
private _forwardNode: TransformNode;
|
private _forwardNode: TransformNode;
|
||||||
private _rotationNode: TransformNode;
|
private _rotationNode: TransformNode;
|
||||||
private _glowLayer: GlowLayer;
|
private _glowLayer: GlowLayer;
|
||||||
private _primaryThrustVectorSound: Sound;
|
private _primaryThrustVectorSound: StaticSound;
|
||||||
private _secondaryThrustVectorSound: Sound;
|
private _secondaryThrustVectorSound: StaticSound;
|
||||||
private _shot: Sound;
|
private _shot: StaticSound;
|
||||||
|
private _primaryThrustPlaying: boolean = false;
|
||||||
|
private _secondaryThrustPlaying: boolean = false;
|
||||||
private _shooting: boolean = false;
|
private _shooting: boolean = false;
|
||||||
private _camera: FreeCamera;
|
private _camera: FreeCamera;
|
||||||
private _ammoBaseMesh: AbstractMesh;
|
private _ammoBaseMesh: AbstractMesh;
|
||||||
private _controllerMode: ControllerStickMode;
|
private _controllerMode: ControllerStickMode;
|
||||||
private _active = false;
|
private _active = false;
|
||||||
constructor(mode: ControllerStickMode = ControllerStickMode.BEGINNER) {
|
private _audioEngine: AudioEngineV2;
|
||||||
this._controllerMode = mode
|
constructor(mode: ControllerStickMode = ControllerStickMode.BEGINNER, audioEngine?: AudioEngineV2) {
|
||||||
|
this._controllerMode = mode;
|
||||||
|
this._audioEngine = audioEngine;
|
||||||
this.setup();
|
this.setup();
|
||||||
this.initialize();
|
this.initialize();
|
||||||
}
|
}
|
||||||
@ -75,8 +79,25 @@ export class Ship {
|
|||||||
this._controllerMode = mode;
|
this._controllerMode = mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async initializeSounds() {
|
||||||
|
if (!this._audioEngine) return;
|
||||||
|
|
||||||
|
this._primaryThrustVectorSound = await this._audioEngine.createSoundAsync("thrust", "/thrust5.mp3", {
|
||||||
|
loop: true,
|
||||||
|
volume: .2
|
||||||
|
});
|
||||||
|
this._secondaryThrustVectorSound = await this._audioEngine.createSoundAsync("thrust2", "/thrust5.mp3", {
|
||||||
|
loop: true,
|
||||||
|
volume: 0.5
|
||||||
|
});
|
||||||
|
this._shot = await this._audioEngine.createSoundAsync("shot", "/shot.mp3", {
|
||||||
|
loop: false,
|
||||||
|
volume: 0.5
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private shoot() {
|
private shoot() {
|
||||||
this._shot.play();
|
this._shot?.play();
|
||||||
const ammo = new InstancedMesh("ammo", this._ammoBaseMesh as Mesh);
|
const ammo = new InstancedMesh("ammo", this._ammoBaseMesh as Mesh);
|
||||||
ammo.parent = this._ship;
|
ammo.parent = this._ship;
|
||||||
ammo.position.y = 2;
|
ammo.position.y = 2;
|
||||||
@ -113,17 +134,11 @@ export class Ship {
|
|||||||
this._ship = new TransformNode("ship", DefaultScene.MainScene);
|
this._ship = new TransformNode("ship", DefaultScene.MainScene);
|
||||||
this._glowLayer = new GlowLayer('bullets', DefaultScene.MainScene);
|
this._glowLayer = new GlowLayer('bullets', DefaultScene.MainScene);
|
||||||
this._glowLayer.intensity = 1;
|
this._glowLayer.intensity = 1;
|
||||||
this._primaryThrustVectorSound = new Sound("thrust", "/thrust5.mp3", DefaultScene.MainScene, null, {
|
|
||||||
loop: true,
|
// Create sounds asynchronously if audio engine is available
|
||||||
autoplay: false
|
if (this._audioEngine) {
|
||||||
});
|
this.initializeSounds();
|
||||||
this._secondaryThrustVectorSound = new Sound("thrust2", "/thrust5.mp3", DefaultScene.MainScene, null, {
|
}
|
||||||
loop: true,
|
|
||||||
autoplay: false,
|
|
||||||
volume: .5
|
|
||||||
});
|
|
||||||
this._shot = new Sound("shot", "/shot.mp3", DefaultScene.MainScene, null,
|
|
||||||
{loop: false, autoplay: false, volume: .5});
|
|
||||||
this._ammoMaterial = new StandardMaterial("ammoMaterial", DefaultScene.MainScene);
|
this._ammoMaterial = new StandardMaterial("ammoMaterial", DefaultScene.MainScene);
|
||||||
this._ammoMaterial.emissiveColor = new Color3(1, 1, 0);
|
this._ammoMaterial.emissiveColor = new Color3(1, 1, 0);
|
||||||
this._ammoBaseMesh = MeshBuilder.CreateCapsule("bullet", {radius: .1, height: 2.5}, DefaultScene.MainScene);
|
this._ammoBaseMesh = MeshBuilder.CreateCapsule("bullet", {radius: .1, height: 2.5}, DefaultScene.MainScene);
|
||||||
@ -218,14 +233,18 @@ export class Ship {
|
|||||||
//if forward thrust is under 40 we can apply more thrust
|
//if forward thrust is under 40 we can apply more thrust
|
||||||
if (Math.abs(this._forwardValue) <= MAX_FORWARD_THRUST) {
|
if (Math.abs(this._forwardValue) <= MAX_FORWARD_THRUST) {
|
||||||
if (Math.abs(this._leftStickVector.y) > .1) {
|
if (Math.abs(this._leftStickVector.y) > .1) {
|
||||||
if (!this._primaryThrustVectorSound.isPlaying) {
|
if (this._primaryThrustVectorSound && !this._primaryThrustPlaying) {
|
||||||
this._primaryThrustVectorSound.play();
|
this._primaryThrustVectorSound.play();
|
||||||
|
this._primaryThrustPlaying = true;
|
||||||
|
}
|
||||||
|
if (this._primaryThrustVectorSound) {
|
||||||
|
this._primaryThrustVectorSound.volume = Math.abs(this._leftStickVector.y);
|
||||||
}
|
}
|
||||||
this._primaryThrustVectorSound.setVolume(Math.abs(this._leftStickVector.y));
|
|
||||||
this._forwardValue += this._leftStickVector.y * .8;
|
this._forwardValue += this._leftStickVector.y * .8;
|
||||||
} else {
|
} else {
|
||||||
if (this._primaryThrustVectorSound.isPlaying) {
|
if (this._primaryThrustVectorSound && this._primaryThrustPlaying) {
|
||||||
this._primaryThrustVectorSound.pause();
|
this._primaryThrustVectorSound.stop();
|
||||||
|
this._primaryThrustPlaying = false;
|
||||||
}
|
}
|
||||||
this._forwardValue = decrementValue(this._forwardValue, .98);
|
this._forwardValue = decrementValue(this._forwardValue, .98);
|
||||||
}
|
}
|
||||||
@ -245,13 +264,17 @@ export class Ship {
|
|||||||
Math.abs(this._leftStickVector.x);
|
Math.abs(this._leftStickVector.x);
|
||||||
|
|
||||||
if (thrust2 > .01) {
|
if (thrust2 > .01) {
|
||||||
if (!this._secondaryThrustVectorSound.isPlaying) {
|
if (this._secondaryThrustVectorSound && !this._secondaryThrustPlaying) {
|
||||||
this._secondaryThrustVectorSound.play();
|
this._secondaryThrustVectorSound.play();
|
||||||
|
this._secondaryThrustPlaying = true;
|
||||||
|
}
|
||||||
|
if (this._secondaryThrustVectorSound) {
|
||||||
|
this._secondaryThrustVectorSound.volume = thrust2 * .4;
|
||||||
}
|
}
|
||||||
this._secondaryThrustVectorSound.setVolume(thrust2 * .4);
|
|
||||||
} else {
|
} else {
|
||||||
if (this._secondaryThrustVectorSound.isPlaying) {
|
if (this._secondaryThrustVectorSound && this._secondaryThrustPlaying) {
|
||||||
this._secondaryThrustVectorSound.pause();
|
this._secondaryThrustVectorSound.stop();
|
||||||
|
this._secondaryThrustPlaying = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -84,7 +84,7 @@ export class RockFactory {
|
|||||||
score: Observable<ScoreEvent>): Promise<Rock> {
|
score: Observable<ScoreEvent>): Promise<Rock> {
|
||||||
|
|
||||||
const rock = new InstancedMesh("asteroid-" +i, this._rockMesh as Mesh);
|
const rock = new InstancedMesh("asteroid-" +i, this._rockMesh as Mesh);
|
||||||
|
console.log(rock.id);
|
||||||
rock.scaling = size;
|
rock.scaling = size;
|
||||||
rock.position = position;
|
rock.position = position;
|
||||||
//rock.material = this._rockMaterial;
|
//rock.material = this._rockMaterial;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user