All checks were successful
Build and Publish Docker Image / Build and Validate (pull_request) Successful in 10s
76 lines
2.1 KiB
TypeScript
76 lines
2.1 KiB
TypeScript
import { System } from '../core/System.ts';
|
|
import { SystemName, ComponentType, GameState } from '../core/Constants.ts';
|
|
import type { Entity } from '../core/Entity.ts';
|
|
import type { Engine } from '../core/Engine.ts';
|
|
import type { Music } from '../components/Music.ts';
|
|
import type { MenuSystem } from './MenuSystem.ts';
|
|
|
|
/**
|
|
* System responsible for managing background music playback.
|
|
*/
|
|
export class MusicSystem extends System {
|
|
private audioContext: AudioContext | null;
|
|
private wasPaused: boolean;
|
|
|
|
constructor() {
|
|
super(SystemName.MUSIC);
|
|
this.requiredComponents = [ComponentType.MUSIC];
|
|
this.priority = 5;
|
|
this.audioContext = null;
|
|
this.wasPaused = false;
|
|
}
|
|
|
|
/**
|
|
* Initialize the audio context when system is added to engine.
|
|
*/
|
|
init(engine: Engine): void {
|
|
super.init(engine);
|
|
}
|
|
|
|
/**
|
|
* Process music entities - ensures audio context exists and handles pause/resume.
|
|
*/
|
|
process(_deltaTime: number, entities: Entity[]): void {
|
|
const menuSystem = this.engine.systems.find((s) => s.name === SystemName.MENU) as
|
|
| MenuSystem
|
|
| undefined;
|
|
const gameState = menuSystem ? menuSystem.getGameState() : GameState.PLAYING;
|
|
const isPaused = gameState === GameState.PAUSED;
|
|
|
|
entities.forEach((entity) => {
|
|
const music = entity.getComponent<Music>(ComponentType.MUSIC);
|
|
if (!music) return;
|
|
|
|
if (!this.audioContext) {
|
|
this.audioContext = new AudioContext();
|
|
}
|
|
|
|
if (isPaused && !this.wasPaused) {
|
|
music.pause();
|
|
this.wasPaused = true;
|
|
} else if (!isPaused && this.wasPaused) {
|
|
music.resume();
|
|
this.wasPaused = false;
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Get or create the shared audio context.
|
|
*/
|
|
getAudioContext(): AudioContext {
|
|
if (!this.audioContext) {
|
|
this.audioContext = new AudioContext();
|
|
}
|
|
return this.audioContext;
|
|
}
|
|
|
|
/**
|
|
* Resume audio context (required after user interaction).
|
|
*/
|
|
resumeAudioContext(): void {
|
|
if (this.audioContext && this.audioContext.state === 'suspended') {
|
|
this.audioContext.resume();
|
|
}
|
|
}
|
|
}
|