Add mission brief audio playback using AudioEngineV2
All checks were successful
Build / build (push) Successful in 1m53s
All checks were successful
Build / build (push) Successful in 1m53s
- Add mission_brief_audio field to CloudLevelEntry interface - Update missionBrief.ts to use AudioEngineV2.createSoundAsync() instead of legacy Sound class (fixes audio not playing) - Pass audioEngine to MissionBrief.initialize() from Level1 - Add welcome_rookie.mp3 audio file 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
c87b85de40
commit
e3422ef9f2
BIN
public/assets/themes/default/audio/voice/welcome_rookie.mp3
Normal file
BIN
public/assets/themes/default/audio/voice/welcome_rookie.mp3
Normal file
Binary file not shown.
@ -431,7 +431,7 @@ export class Level1 implements Level {
|
|||||||
log.info('[Level1] _missionBrief object:', this._missionBrief);
|
log.info('[Level1] _missionBrief object:', this._missionBrief);
|
||||||
log.info('[Level1] Ship exists:', !!this._ship);
|
log.info('[Level1] Ship exists:', !!this._ship);
|
||||||
log.info('[Level1] Ship ID in scene:', DefaultScene.MainScene.getNodeById('Ship') !== null);
|
log.info('[Level1] Ship ID in scene:', DefaultScene.MainScene.getNodeById('Ship') !== null);
|
||||||
this._missionBrief.initialize();
|
this._missionBrief.initialize(this._audioEngine);
|
||||||
log.info('[Level1] ========== MISSION BRIEF INITIALIZATION COMPLETE ==========');
|
log.info('[Level1] ========== MISSION BRIEF INITIALIZATION COMPLETE ==========');
|
||||||
log.debug('Mission brief initialized');
|
log.debug('Mission brief initialized');
|
||||||
|
|
||||||
|
|||||||
@ -28,6 +28,7 @@ export interface CloudLevelEntry {
|
|||||||
createdAt: string;
|
createdAt: string;
|
||||||
updatedAt: string;
|
updatedAt: string;
|
||||||
reviewNotes?: string;
|
reviewNotes?: string;
|
||||||
|
missionBriefAudio?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -55,6 +56,7 @@ interface LevelRow {
|
|||||||
created_at: string;
|
created_at: string;
|
||||||
updated_at: string;
|
updated_at: string;
|
||||||
review_notes?: string;
|
review_notes?: string;
|
||||||
|
mission_brief_audio?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -93,6 +95,7 @@ function rowToEntry(row: LevelRow): CloudLevelEntry {
|
|||||||
createdAt: row.created_at,
|
createdAt: row.created_at,
|
||||||
updatedAt: row.updated_at,
|
updatedAt: row.updated_at,
|
||||||
reviewNotes: row.review_notes,
|
reviewNotes: row.review_notes,
|
||||||
|
missionBriefAudio: row.mission_brief_audio,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import {
|
|||||||
} from "@babylonjs/gui";
|
} from "@babylonjs/gui";
|
||||||
import { DefaultScene } from "../../core/defaultScene";
|
import { DefaultScene } from "../../core/defaultScene";
|
||||||
import {MeshBuilder, Vector3, Observable, Observer} from "@babylonjs/core";
|
import {MeshBuilder, Vector3, Observable, Observer} from "@babylonjs/core";
|
||||||
|
import type { AudioEngineV2, StaticSound } from "@babylonjs/core";
|
||||||
import log from '../../core/logger';
|
import log from '../../core/logger';
|
||||||
import { LevelConfig } from "../../levels/config/levelConfig";
|
import { LevelConfig } from "../../levels/config/levelConfig";
|
||||||
import { CloudLevelEntry } from "../../services/cloudLevelService";
|
import { CloudLevelEntry } from "../../services/cloudLevelService";
|
||||||
@ -22,11 +23,14 @@ export class MissionBrief {
|
|||||||
private _isVisible: boolean = false;
|
private _isVisible: boolean = false;
|
||||||
private _onStartCallback: (() => void) | null = null;
|
private _onStartCallback: (() => void) | null = null;
|
||||||
private _triggerObserver: Observer<void> | null = null;
|
private _triggerObserver: Observer<void> | null = null;
|
||||||
|
private _audioEngine: AudioEngineV2 | null = null;
|
||||||
|
private _currentSound: StaticSound | null = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize the mission brief as a fullscreen overlay
|
* Initialize the mission brief as a fullscreen overlay
|
||||||
*/
|
*/
|
||||||
public initialize(): void {
|
public initialize(audioEngine?: AudioEngineV2): void {
|
||||||
|
this._audioEngine = audioEngine || null;
|
||||||
log.info('[MissionBrief] ========== INITIALIZE CALLED ==========');
|
log.info('[MissionBrief] ========== INITIALIZE CALLED ==========');
|
||||||
const scene = DefaultScene.MainScene;
|
const scene = DefaultScene.MainScene;
|
||||||
log.info('[MissionBrief] Scene exists:', !!scene);
|
log.info('[MissionBrief] Scene exists:', !!scene);
|
||||||
@ -232,6 +236,21 @@ export class MissionBrief {
|
|||||||
this._container.isVisible = true;
|
this._container.isVisible = true;
|
||||||
this._isVisible = true;
|
this._isVisible = true;
|
||||||
|
|
||||||
|
// Play mission brief audio if specified
|
||||||
|
if (directoryEntry?.missionBriefAudio && this._audioEngine) {
|
||||||
|
log.info('[MissionBrief] Playing audio:', directoryEntry.missionBriefAudio);
|
||||||
|
this._audioEngine.createSoundAsync(
|
||||||
|
"missionBriefAudio",
|
||||||
|
directoryEntry.missionBriefAudio,
|
||||||
|
{ loop: false, volume: 1.0 }
|
||||||
|
).then(sound => {
|
||||||
|
this._currentSound = sound;
|
||||||
|
sound.play();
|
||||||
|
}).catch(err => {
|
||||||
|
log.error('[MissionBrief] Failed to load audio:', err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
log.info('[MissionBrief] ========== CONTAINER NOW VISIBLE ==========');
|
log.info('[MissionBrief] ========== CONTAINER NOW VISIBLE ==========');
|
||||||
log.info('[MissionBrief] Container.isVisible:', this._container.isVisible);
|
log.info('[MissionBrief] Container.isVisible:', this._container.isVisible);
|
||||||
log.info('[MissionBrief] _isVisible flag:', this._isVisible);
|
log.info('[MissionBrief] _isVisible flag:', this._isVisible);
|
||||||
@ -298,6 +317,10 @@ export class MissionBrief {
|
|||||||
* Clean up resources
|
* Clean up resources
|
||||||
*/
|
*/
|
||||||
public dispose(): void {
|
public dispose(): void {
|
||||||
|
if (this._currentSound) {
|
||||||
|
this._currentSound.dispose();
|
||||||
|
this._currentSound = null;
|
||||||
|
}
|
||||||
if (this._advancedTexture) {
|
if (this._advancedTexture) {
|
||||||
this._advancedTexture.dispose();
|
this._advancedTexture.dispose();
|
||||||
this._advancedTexture = null;
|
this._advancedTexture = null;
|
||||||
@ -305,6 +328,7 @@ export class MissionBrief {
|
|||||||
this._container = null;
|
this._container = null;
|
||||||
this._onStartCallback = null;
|
this._onStartCallback = null;
|
||||||
this._triggerObserver = null;
|
this._triggerObserver = null;
|
||||||
|
this._audioEngine = null;
|
||||||
this._isVisible = false;
|
this._isVisible = false;
|
||||||
log.debug('[MissionBrief] Disposed');
|
log.debug('[MissionBrief] Disposed');
|
||||||
}
|
}
|
||||||
|
|||||||
@ -138,6 +138,7 @@ create table public.levels
|
|||||||
tags text[] default '{}'::text[],
|
tags text[] default '{}'::text[],
|
||||||
config jsonb not null,
|
config jsonb not null,
|
||||||
mission_brief text[] default '{}'::text[],
|
mission_brief text[] default '{}'::text[],
|
||||||
|
mission_brief_audio text,
|
||||||
level_type text default 'private'::text not null
|
level_type text default 'private'::text not null
|
||||||
constraint valid_level_type
|
constraint valid_level_type
|
||||||
check (level_type = ANY
|
check (level_type = ANY
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user