This commit is contained in:
icslucas
2025-10-05 09:08:46 +02:00
parent 4bbc1e76fa
commit 3d067a191a
7 changed files with 133 additions and 36 deletions
+1 -1
View File
@@ -5,4 +5,4 @@
export PATH="/usr/local/bin:$HOME/.npm-global/bin:$HOME/.nvm/versions/node/$(node -v)/bin:$PATH"
# Then run lint-staged if tests pass
npx lint-staged
npx.cmd lint-staged
+15 -4
View File
@@ -47,7 +47,8 @@ import {
} from "./Transport";
import { createCanvas } from "./Utils";
import { createRenderer, GameRenderer } from "./graphics/GameRenderer";
import SoundManager from "./sound/SoundManager";
import { SoundLayer } from "./sound/SoundLayer";
import { SoundManager } from "./sound/SoundManager";
export interface LobbyConfig {
serverConfig: ServerConfig;
@@ -175,7 +176,15 @@ async function createClientGame(
);
const canvas = createCanvas();
const gameRenderer = createRenderer(canvas, gameView, eventBus);
const soundManager = new SoundManager();
const soundLayer = new SoundLayer(gameView, soundManager);
const gameRenderer = createRenderer(
canvas,
gameView,
eventBus,
soundManager,
soundLayer,
);
console.log(
`creating private game got difficulty: ${lobbyConfig.gameStartInfo.config.difficulty}`,
@@ -189,6 +198,7 @@ async function createClientGame(
transport,
worker,
gameView,
soundManager,
);
}
@@ -211,6 +221,7 @@ export class ClientGameRunner {
private transport: Transport,
private worker: WorkerClient,
private gameView: GameView,
private soundManager: SoundManager,
) {
this.lastMessageTime = Date.now();
}
@@ -245,7 +256,7 @@ export class ClientGameRunner {
}
public start() {
SoundManager.playBackgroundMusic();
this.soundManager.playBackgroundMusic();
console.log("starting client game");
this.isActive = true;
@@ -374,7 +385,7 @@ export class ClientGameRunner {
}
public stop() {
SoundManager.stopBackgroundMusic();
this.soundManager.stopBackgroundMusic();
if (!this.isActive) return;
this.isActive = false;
+8
View File
@@ -3,6 +3,8 @@ import { GameView } from "../../core/game/GameView";
import { UserSettings } from "../../core/game/UserSettings";
import { GameStartingModal } from "../GameStartingModal";
import { RefreshGraphicsEvent as RedrawGraphicsEvent } from "../InputHandler";
import { SoundLayer } from "../sound/SoundLayer";
import { SoundManager } from "../sound/SoundManager";
import { TransformHandler } from "./TransformHandler";
import { UIState } from "./UIState";
import { AlertFrame } from "./layers/AlertFrame";
@@ -44,6 +46,8 @@ export function createRenderer(
canvas: HTMLCanvasElement,
game: GameView,
eventBus: EventBus,
soundManager: SoundManager,
soundLayer: SoundLayer,
): GameRenderer {
const transformHandler = new TransformHandler(game, eventBus, canvas);
const userSettings = new UserSettings();
@@ -160,6 +164,7 @@ export function createRenderer(
}
settingsModal.userSettings = userSettings;
settingsModal.eventBus = eventBus;
settingsModal.soundManager = soundManager;
const unitDisplay = document.querySelector("unit-display") as UnitDisplay;
if (!(unitDisplay instanceof UnitDisplay)) {
@@ -273,6 +278,7 @@ export function createRenderer(
gutterAdModal,
alertFrame,
fpsDisplay,
soundLayer,
];
return new GameRenderer(
@@ -283,6 +289,7 @@ export function createRenderer(
uiState,
layers,
fpsDisplay,
soundManager,
);
}
@@ -297,6 +304,7 @@ export class GameRenderer {
public uiState: UIState,
private layers: Layer[],
private fpsDisplay: FPSDisplay,
public soundManager: SoundManager,
) {
const context = canvas.getContext("2d");
if (context === null) throw new Error("2d context not supported");
+1 -23
View File
@@ -7,7 +7,7 @@ import {
RailroadUpdate,
} from "../../../core/game/GameUpdates";
import { GameView, UnitView } from "../../../core/game/GameView";
import SoundManager, { SoundEffect } from "../../sound/SoundManager";
import { renderNumber } from "../../Utils";
import { AnimatedSpriteLoader } from "../AnimatedSpriteLoader";
import { conquestFxFactory } from "../fx/ConquestFx";
@@ -142,26 +142,14 @@ export class FxLayer implements Layer {
break;
}
case UnitType.AtomBomb:
if (!this.seenNukes.has(unit.id())) {
SoundManager.playSoundEffect(SoundEffect.AtomLaunch);
this.seenNukes.add(unit.id());
}
this.onNukeEvent(unit, 70);
break;
case UnitType.MIRV:
if (!this.seenNukes.has(unit.id())) {
SoundManager.playSoundEffect(SoundEffect.MirvLaunch);
this.seenNukes.add(unit.id());
}
break;
case UnitType.MIRVWarhead:
this.onNukeEvent(unit, 70);
break;
case UnitType.HydrogenBomb:
if (!this.seenNukes.has(unit.id())) {
SoundManager.playSoundEffect(SoundEffect.HydroLaunch);
this.seenNukes.add(unit.id());
}
this.onNukeEvent(unit, 160);
break;
case UnitType.Warship:
@@ -234,8 +222,6 @@ export class FxLayer implements Layer {
return;
}
SoundManager.playSoundEffect(SoundEffect.KaChing);
const conquestFx = conquestFxFactory(
this.animatedSpriteLoader,
conquest,
@@ -280,14 +266,6 @@ export class FxLayer implements Layer {
}
handleNukeExplosion(unit: UnitView, radius: number) {
if (unit.type() === UnitType.AtomBomb) {
SoundManager.playSoundEffect(SoundEffect.AtomHit);
} else if (unit.type() === UnitType.HydrogenBomb) {
SoundManager.playSoundEffect(SoundEffect.HydroHit);
} else if (unit.type() === UnitType.MIRVWarhead) {
SoundManager.playSoundEffect(SoundEffect.MirvHit);
}
const x = this.game.x(unit.lastTile());
const y = this.game.y(unit.lastTile());
const nukeFx = nukeFxFactory(
+8 -5
View File
@@ -15,7 +15,7 @@ import { UserSettings } from "../../../core/game/UserSettings";
import { AlternateViewEvent, RefreshGraphicsEvent } from "../../InputHandler";
import { PauseGameEvent } from "../../Transport";
import { translateText } from "../../Utils";
import SoundManager from "../../sound/SoundManager";
import { SoundManager } from "../../sound/SoundManager";
import { Layer } from "./Layer";
export class ShowSettingsModalEvent {
@@ -30,6 +30,7 @@ export class ShowSettingsModalEvent {
export class SettingsModal extends LitElement implements Layer {
public eventBus: EventBus;
public userSettings: UserSettings;
public soundManager: SoundManager;
@state()
private isVisible: boolean = false;
@@ -47,10 +48,12 @@ export class SettingsModal extends LitElement implements Layer {
wasPausedWhenOpened = false;
init() {
SoundManager.setBackgroundMusicVolume(
this.soundManager.setBackgroundMusicVolume(
this.userSettings.backgroundMusicVolume(),
);
SoundManager.setSoundEffectsVolume(this.userSettings.soundEffectsVolume());
this.soundManager.setSoundEffectsVolume(
this.userSettings.soundEffectsVolume(),
);
this.eventBus.on(ShowSettingsModalEvent, (event) => {
this.isVisible = event.isVisible;
this.shouldPause = event.shouldPause;
@@ -159,14 +162,14 @@ export class SettingsModal extends LitElement implements Layer {
private onVolumeChange(event: Event) {
const volume = parseFloat((event.target as HTMLInputElement).value) / 100;
this.userSettings.setBackgroundMusicVolume(volume);
SoundManager.setBackgroundMusicVolume(volume);
this.soundManager.setBackgroundMusicVolume(volume);
this.requestUpdate();
}
private onSoundEffectsVolumeChange(event: Event) {
const volume = parseFloat((event.target as HTMLInputElement).value) / 100;
this.userSettings.setSoundEffectsVolume(volume);
SoundManager.setSoundEffectsVolume(volume);
this.soundManager.setSoundEffectsVolume(volume);
this.requestUpdate();
}
+99
View File
@@ -0,0 +1,99 @@
import { UnitType } from "../../core/game/Game";
import { GameUpdateType } from "../../core/game/GameUpdates";
import { GameView, UnitView } from "../../core/game/GameView";
import { Layer } from "../graphics/layers/Layer";
import { SoundEffect, SoundManager } from "./SoundManager";
export class SoundLayer implements Layer {
private seenNukes: Set<number> = new Set();
constructor(
private game: GameView,
private soundManager: SoundManager,
) {}
shouldTransform(): boolean {
return false;
}
init(): void {}
tick(): void {
this.game
.updatesSinceLastTick()
?.[GameUpdateType.Unit]?.map((unit) => this.game.unit(unit.id))
?.forEach((unitView) => {
if (unitView === undefined) return;
this.onUnitEvent(unitView);
});
}
onUnitEvent(unit: UnitView) {
const myPlayer = this.game.myPlayer();
if (!myPlayer) return;
const isNuke =
unit.type() === UnitType.AtomBomb ||
unit.type() === UnitType.HydrogenBomb ||
unit.type() === UnitType.MIRV;
if (isNuke) {
if (!this.seenNukes.has(unit.id())) {
const owner = unit.owner();
const targetTile = unit.targetTile();
const targetPlayer = targetTile
? this.game.playerBySmallID(this.game.ownerID(targetTile))
: undefined;
if (owner === myPlayer || targetPlayer === myPlayer) {
let soundEffect: SoundEffect | undefined;
if (unit.type() === UnitType.AtomBomb) {
soundEffect = SoundEffect.AtomLaunch;
} else if (unit.type() === UnitType.HydrogenBomb) {
soundEffect = SoundEffect.HydroLaunch;
} else if (unit.type() === UnitType.MIRV) {
soundEffect = SoundEffect.MirvLaunch;
}
if (soundEffect) {
this.soundManager.playSoundEffect(soundEffect);
}
}
this.seenNukes.add(unit.id());
}
}
if (!unit.isActive() && unit.reachedTarget()) {
const isNukeHit =
unit.type() === UnitType.AtomBomb ||
unit.type() === UnitType.HydrogenBomb ||
unit.type() === UnitType.MIRVWarhead;
if (isNukeHit) {
const owner = unit.owner();
const targetTile = unit.lastTile();
const targetPlayer = this.game.playerBySmallID(
this.game.ownerID(targetTile),
);
if (owner === myPlayer || targetPlayer === myPlayer) {
let soundEffect: SoundEffect | undefined;
if (unit.type() === UnitType.AtomBomb) {
soundEffect = SoundEffect.AtomHit;
} else if (unit.type() === UnitType.HydrogenBomb) {
soundEffect = SoundEffect.HydroHit;
} else if (unit.type() === UnitType.MIRVWarhead) {
soundEffect = SoundEffect.MirvHit;
}
if (soundEffect) {
this.soundManager.playSoundEffect(soundEffect);
}
}
}
}
}
renderLayer(context: CanvasRenderingContext2D): void {}
redraw(): void {}
}
+1 -3
View File
@@ -19,7 +19,7 @@ export enum SoundEffect {
MirvLaunch = "mirv_launch",
}
class SoundManager {
export class SoundManager {
private backgroundMusic: Howl[] = [];
private currentTrack: number = 0;
private soundEffects: Map<SoundEffect, Howl> = new Map();
@@ -122,5 +122,3 @@ class SoundManager {
}
}
}
export default new SoundManager();