Replace game audio with Pixabay tracks
This commit is contained in:
26
docs/audio-sources.md
Normal file
26
docs/audio-sources.md
Normal file
@@ -0,0 +1,26 @@
|
||||
# Audio Sources
|
||||
|
||||
Downloaded from Pixabay on 2026-06-22 and used under the Pixabay Content License.
|
||||
|
||||
License reference: https://pixabay.com/service/license-summary/
|
||||
|
||||
## Background Music
|
||||
|
||||
| Project file | Pixabay title | Creator | Source |
|
||||
| --- | --- | --- | --- |
|
||||
| `src/assets/audio/bgm/title-theme.mp3` | Chinese ancient music, World, Ethnic music | ET11LX | https://pixabay.com/music/china-chinese-ancient-style-music-love-et11lx-%E5%8F%A4%E9%A3%8E-%E6%8A%92%E6%83%85-%E8%AF%86-155926/ |
|
||||
| `src/assets/audio/bgm/story-dark.mp3` | Chinese, Asia, China music | Reklamistrz | https://pixabay.com/music/meditationspiritual-ancient-chinese-dali-448882/ |
|
||||
| `src/assets/audio/bgm/oath-theme.mp3` | Chinese ancient style, Ancient style, World music | ET11LX | https://pixabay.com/music/world-chinese-ancient-style-music-love-et%E5%8D%81%E4%B8%80lx-%E5%8F%A4%E9%A3%8E-%E6%8A%92%E6%83%85-%E8%AF%86%E4%B8%B0%E5%AF%8C%E9%85%8D%E5%99%A8%E6%8E%A8%E9%AB%98%E6%BD%AE%E7%89%88-247345/ |
|
||||
| `src/assets/audio/bgm/militia-theme.mp3` | Orchestra, Heroic, Warrior music | NR-Music | https://pixabay.com/music/adventure-short-heroic-orchestral-loop-541095/ |
|
||||
| `src/assets/audio/bgm/battle-prep.mp3` | Epic, Battle, Knight music | DeusLower | https://pixabay.com/music/mystery-epic-battle-orchestra-music-241006/ |
|
||||
|
||||
## Sound Effects
|
||||
|
||||
| Project file | Pixabay title | Creator | Source |
|
||||
| --- | --- | --- | --- |
|
||||
| `src/assets/audio/sfx/ui-select.mp3` | Ui, Click, Retro sound effect | SoundShelfStudio | https://pixabay.com/sound-effects/film-special-effects-ui-click-retro-514601/ |
|
||||
| `src/assets/audio/sfx/sword-slash.mp3` | Sword, Slash, Swing sound effect | DavidDumaisAudio | https://pixabay.com/sound-effects/film-special-effects-sword-slash-and-swing-185432/ |
|
||||
| `src/assets/audio/sfx/combat-impact.mp3` | Sword, Slash, Weapon sound effect | DavidDumaisAudio | https://pixabay.com/sound-effects/film-special-effects-sword-slash-with-metal-shield-impact-185433/ |
|
||||
| `src/assets/audio/sfx/strategy-cast.mp3` | Designed, Magic spell, Projectile sound effect | RescopicSound | https://pixabay.com/sound-effects/film-special-effects-elemental-magic-spell-impact-outgoing-228342/ |
|
||||
| `src/assets/audio/sfx/cart-roll.mp3` | Cart, Wheel, Cobblestones sound effect | Fronbondi_Skegs | https://pixabay.com/sound-effects/film-special-effects-foley-heavily-laden-cart-moving-over-cobblestones-sound-effect-246657/ |
|
||||
| `src/assets/audio/sfx/exp-gain.mp3` | Level up, Level up sound, Game level up sound effect | Universfield | https://pixabay.com/sound-effects/film-special-effects-level-up-06-370051/ |
|
||||
BIN
src/assets/audio/bgm/battle-prep.mp3
Normal file
BIN
src/assets/audio/bgm/battle-prep.mp3
Normal file
Binary file not shown.
Binary file not shown.
BIN
src/assets/audio/bgm/militia-theme.mp3
Normal file
BIN
src/assets/audio/bgm/militia-theme.mp3
Normal file
Binary file not shown.
Binary file not shown.
BIN
src/assets/audio/bgm/oath-theme.mp3
Normal file
BIN
src/assets/audio/bgm/oath-theme.mp3
Normal file
Binary file not shown.
Binary file not shown.
BIN
src/assets/audio/bgm/story-dark.mp3
Normal file
BIN
src/assets/audio/bgm/story-dark.mp3
Normal file
Binary file not shown.
Binary file not shown.
BIN
src/assets/audio/bgm/title-theme.mp3
Normal file
BIN
src/assets/audio/bgm/title-theme.mp3
Normal file
Binary file not shown.
Binary file not shown.
BIN
src/assets/audio/sfx/cart-roll.mp3
Normal file
BIN
src/assets/audio/sfx/cart-roll.mp3
Normal file
Binary file not shown.
BIN
src/assets/audio/sfx/combat-impact.mp3
Normal file
BIN
src/assets/audio/sfx/combat-impact.mp3
Normal file
Binary file not shown.
BIN
src/assets/audio/sfx/exp-gain.mp3
Normal file
BIN
src/assets/audio/sfx/exp-gain.mp3
Normal file
Binary file not shown.
BIN
src/assets/audio/sfx/strategy-cast.mp3
Normal file
BIN
src/assets/audio/sfx/strategy-cast.mp3
Normal file
Binary file not shown.
BIN
src/assets/audio/sfx/sword-slash.mp3
Normal file
BIN
src/assets/audio/sfx/sword-slash.mp3
Normal file
Binary file not shown.
BIN
src/assets/audio/sfx/ui-select.mp3
Normal file
BIN
src/assets/audio/sfx/ui-select.mp3
Normal file
Binary file not shown.
@@ -1,21 +1,33 @@
|
||||
type AudioTrackMap = Record<string, string>;
|
||||
|
||||
type PlayEffectOptions = {
|
||||
volume?: number;
|
||||
rate?: number;
|
||||
stopAfterMs?: number;
|
||||
};
|
||||
|
||||
class SoundDirector {
|
||||
private context?: AudioContext;
|
||||
private master?: GainNode;
|
||||
private started = false;
|
||||
private muted = false;
|
||||
private musicTracks: AudioTrackMap = {};
|
||||
private effectTracks: AudioTrackMap = {};
|
||||
private music?: HTMLAudioElement;
|
||||
private currentMusicKey?: string;
|
||||
private pendingMusicKey?: string;
|
||||
private musicFadeTimer?: number;
|
||||
private readonly musicVolume = 0.14;
|
||||
private readonly musicVolume = 0.22;
|
||||
private readonly effectVolume = 0.42;
|
||||
|
||||
registerMusicTracks(tracks: AudioTrackMap) {
|
||||
this.musicTracks = tracks;
|
||||
}
|
||||
|
||||
registerEffectTracks(tracks: AudioTrackMap) {
|
||||
this.effectTracks = tracks;
|
||||
}
|
||||
|
||||
start() {
|
||||
if (this.started) {
|
||||
this.resume();
|
||||
@@ -70,10 +82,48 @@ class SoundDirector {
|
||||
}
|
||||
|
||||
playSelect() {
|
||||
if (this.playEffect('ui-select', { volume: 0.24, stopAfterMs: 420 })) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.playTone(300, 0.07, 0.04, 'sine');
|
||||
window.setTimeout(() => this.playTone(450, 0.08, 0.028, 'sine'), 70);
|
||||
}
|
||||
|
||||
playEffect(key: string, options: PlayEffectOptions = {}) {
|
||||
if (!this.started || this.muted) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const src = this.effectTracks[key];
|
||||
if (!src) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const effect = new Audio(src);
|
||||
effect.preload = 'auto';
|
||||
effect.volume = options.volume ?? this.effectVolume;
|
||||
effect.playbackRate = options.rate ?? 1;
|
||||
effect.muted = this.muted;
|
||||
effect.addEventListener(
|
||||
'ended',
|
||||
() => {
|
||||
effect.src = '';
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
|
||||
if (options.stopAfterMs) {
|
||||
window.setTimeout(() => {
|
||||
effect.pause();
|
||||
effect.src = '';
|
||||
}, options.stopAfterMs);
|
||||
}
|
||||
|
||||
void effect.play().catch(() => undefined);
|
||||
return true;
|
||||
}
|
||||
|
||||
playMusic(key?: string) {
|
||||
if (!key) {
|
||||
return;
|
||||
|
||||
@@ -1,8 +1,14 @@
|
||||
import battlePrepUrl from '../../assets/audio/bgm/battle-prep.wav';
|
||||
import militiaThemeUrl from '../../assets/audio/bgm/militia-theme.wav';
|
||||
import oathThemeUrl from '../../assets/audio/bgm/oath-theme.wav';
|
||||
import storyDarkUrl from '../../assets/audio/bgm/story-dark.wav';
|
||||
import titleThemeUrl from '../../assets/audio/bgm/title-theme.wav';
|
||||
import battlePrepUrl from '../../assets/audio/bgm/battle-prep.mp3';
|
||||
import militiaThemeUrl from '../../assets/audio/bgm/militia-theme.mp3';
|
||||
import oathThemeUrl from '../../assets/audio/bgm/oath-theme.mp3';
|
||||
import storyDarkUrl from '../../assets/audio/bgm/story-dark.mp3';
|
||||
import titleThemeUrl from '../../assets/audio/bgm/title-theme.mp3';
|
||||
import cartRollUrl from '../../assets/audio/sfx/cart-roll.mp3';
|
||||
import combatImpactUrl from '../../assets/audio/sfx/combat-impact.mp3';
|
||||
import expGainUrl from '../../assets/audio/sfx/exp-gain.mp3';
|
||||
import strategyCastUrl from '../../assets/audio/sfx/strategy-cast.mp3';
|
||||
import swordSlashUrl from '../../assets/audio/sfx/sword-slash.mp3';
|
||||
import uiSelectUrl from '../../assets/audio/sfx/ui-select.mp3';
|
||||
|
||||
export const musicTracks = {
|
||||
'title-theme': titleThemeUrl,
|
||||
@@ -12,4 +18,14 @@ export const musicTracks = {
|
||||
'battle-prep': battlePrepUrl
|
||||
} as const;
|
||||
|
||||
export const effectTracks = {
|
||||
'ui-select': uiSelectUrl,
|
||||
'sword-slash': swordSlashUrl,
|
||||
'combat-impact': combatImpactUrl,
|
||||
'strategy-cast': strategyCastUrl,
|
||||
'cart-roll': cartRollUrl,
|
||||
'exp-gain': expGainUrl
|
||||
} as const;
|
||||
|
||||
export type MusicTrackKey = keyof typeof musicTracks;
|
||||
export type EffectTrackKey = keyof typeof effectTracks;
|
||||
|
||||
@@ -1270,6 +1270,10 @@ export class BattleScene extends Phaser.Scene {
|
||||
await this.animateCombatGauge(defenderStatus.hpFill, result.previousDefenderHp / result.defender.maxHp, result.defender.hp / result.defender.maxHp, 420);
|
||||
defenderStatus.hpText.setText(`${result.defender.hp} / ${result.defender.maxHp}`);
|
||||
|
||||
if (result.characterGrowth.amount > 0) {
|
||||
soundDirector.playEffect('exp-gain', { volume: result.characterGrowth.leveled ? 0.44 : 0.28, stopAfterMs: 1000 });
|
||||
}
|
||||
|
||||
await this.animateCombatGauge(
|
||||
attackerStatus.expFill,
|
||||
result.characterGrowth.previousExp / result.characterGrowth.next,
|
||||
@@ -1400,6 +1404,7 @@ export class BattleScene extends Phaser.Scene {
|
||||
) {
|
||||
const direction = result.attacker.faction === 'ally' ? 1 : -1;
|
||||
if (result.action === 'attack') {
|
||||
soundDirector.playEffect('sword-slash', { volume: 0.52, stopAfterMs: 700 });
|
||||
this.tweens.add({
|
||||
targets: attackerSprite,
|
||||
x: attackerX + direction * 84,
|
||||
@@ -1418,6 +1423,11 @@ export class BattleScene extends Phaser.Scene {
|
||||
return;
|
||||
}
|
||||
|
||||
soundDirector.playEffect(result.action === 'item' ? 'cart-roll' : 'strategy-cast', {
|
||||
volume: result.action === 'item' ? 0.34 : 0.44,
|
||||
stopAfterMs: result.action === 'item' ? 720 : 950
|
||||
});
|
||||
|
||||
const projectile =
|
||||
result.action === 'item'
|
||||
? this.createCombatCart(attackerX + direction * 78, groundY - 10, depth)
|
||||
@@ -1462,6 +1472,8 @@ export class BattleScene extends Phaser.Scene {
|
||||
}
|
||||
|
||||
private showCombatImpact(result: CombatResult, x: number, y: number, depth: number) {
|
||||
soundDirector.playEffect('combat-impact', { volume: result.action === 'strategy' ? 0.3 : 0.48, stopAfterMs: 650 });
|
||||
|
||||
const impact = this.trackCombatObject(this.add.star(x, y, 8, 12, 42, result.action === 'strategy' ? 0x6cc5ff : 0xffdf7b, 0.92));
|
||||
impact.setDepth(depth);
|
||||
this.tweens.add({
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import Phaser from 'phaser';
|
||||
import { musicTracks } from './game/audio/audioAssets';
|
||||
import { effectTracks, musicTracks } from './game/audio/audioAssets';
|
||||
import { soundDirector } from './game/audio/SoundDirector';
|
||||
import { BattleScene } from './game/scenes/BattleScene';
|
||||
import { BootScene } from './game/scenes/BootScene';
|
||||
@@ -42,6 +42,7 @@ const config: Phaser.Types.Core.GameConfig = {
|
||||
};
|
||||
|
||||
soundDirector.registerMusicTracks(musicTracks);
|
||||
soundDirector.registerEffectTracks(effectTracks);
|
||||
|
||||
const game = new Phaser.Game(config);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user