Skip to content

๐Ÿชต 7. ํšจ์œจ์ ์ธ ์‚ฌ์šด๋“œ ๊ด€๋ฆฌ๋ฅผ ์œ„ํ•œ ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด ์ ์šฉ๊ธฐ: ๊ฒŒ์ž„ ์‚ฌ์šด๋“œ ์‹œ์Šคํ…œ ์ตœ์ ํ™”

Taeyeon Yoon edited this page Dec 5, 2024 · 1 revision

๊ฒŒ์ž„ ๊ฐœ๋ฐœ ์ค‘ ์‚ฌ์šด๋“œ ๊ด€๋ฆฌ ์‹œ์Šคํ…œ์„ ๊ตฌํ˜„ํ•˜๋ฉด์„œ ๋งˆ์ฃผ์นœ ๋„์ „ ๊ณผ์ œ๋“ค๊ณผ ์ด๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•œ ์ ‘๊ทผ ๋ฐฉ๋ฒ•์„ ๊ณต์œ ํ•˜๊ณ ์ž ํ•ฉ๋‹ˆ๋‹ค.

1. ์ง๋ฉดํ•œ ๋ฌธ์ œ๋“ค

1.1. ๋ธŒ๋ผ์šฐ์ €์˜ ์ž๋™ ์žฌ์ƒ ์ •์ฑ…

๋ธŒ๋ผ์šฐ์ €๋“ค์€ ์‚ฌ์šฉ์ž ๊ฒฝํ—˜ ๋ณดํ˜ธ๋ฅผ ์œ„ํ•ด ์—„๊ฒฉํ•œ ์ž๋™ ์žฌ์ƒ ์ •์ฑ…์„ ์ ์šฉํ•ฉ๋‹ˆ๋‹ค. ํŠนํžˆ, ์‚ฌ์šฉ์ž๊ฐ€ ๋ช…์‹œ์ ์œผ๋กœ ์ƒํ˜ธ์ž‘์šฉํ•˜์ง€ ์•Š์œผ๋ฉด ์˜ค๋””์˜ค ์žฌ์ƒ์ด ์ฐจ๋‹จ๋ฉ๋‹ˆ๋‹ค. ์ด๋Š” ๊ฒŒ์ž„ ์ง„์ž… ์‹œ ํ•„์š”ํ•œ ์‚ฌ์šด๋“œ์˜ ์ž๋™ ์žฌ์ƒ์ด ๋ถˆ๊ฐ€๋Šฅํ•œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค.

1.2. ์ค‘๋ณต ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ

์—ฌ๋Ÿฌ ์ปดํฌ๋„ŒํŠธ์—์„œ ๋…๋ฆฝ์ ์œผ๋กœ Audio ๊ฐ์ฒด๋ฅผ ๊ด€๋ฆฌํ•˜๋ฉด ์ค‘๋ณต๋œ ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ์œผ๋กœ ์ธํ•ด ๋ฉ”๋ชจ๋ฆฌ ๋‚ญ๋น„๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ์ด ๋ฌธ์ œ๋Š” ์„ฑ๋Šฅ ์ €ํ•˜๋กœ ์ด์–ด์ง‘๋‹ˆ๋‹ค.

// โŒ ์ž˜๋ชป๋œ ๊ตฌํ˜„ ์˜ˆ์‹œ: ๊ฐ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋™์ผํ•œ ์‚ฌ์šด๋“œ๋ฅผ ๊ฐœ๋ณ„ ๊ด€๋ฆฌ
const Component = () => {
  const audio = new Audio(soundFile); // ์ปดํฌ๋„ŒํŠธ๋งˆ๋‹ค ์ƒˆ๋กœ์šด Audio ๊ฐ์ฒด ์ƒ์„ฑ

  const playSound = () => {
    audio.play().catch(console.error);
  };
};

1.3. ์ฝ”๋“œ ์žฌ์‚ฌ์šฉ์„ฑ๊ณผ ์œ ์ง€๋ณด์ˆ˜์„ฑ ๋ฌธ์ œ

๊ฐœ๋ณ„์ ์œผ๋กœ Audio ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ๊ด€๋ฆฌํ•˜๋Š” ์ฝ”๋“œ๋Š” ์ค‘๋ณต์ด ๋งŽ์•„์ง€๊ณ , ํ™•์žฅ์„ฑ์ด ๋ถ€์กฑํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ์ปจ๋Œ€ ์ƒˆ๋กœ์šด ์‚ฌ์šด๋“œ๋ฅผ ์ถ”๊ฐ€ํ•  ๋•Œ๋งˆ๋‹ค ๊ฐ ์ปดํฌ๋„ŒํŠธ์—์„œ ์ˆ˜์ •์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

2. ํ•ด๊ฒฐ ๋ฐฉ์•ˆ: ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด ์ ์šฉ

2.1. SoundManager ํด๋ž˜์Šค ์„ค๊ณ„

SoundManager๋Š” ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด์„ ์‚ฌ์šฉํ•ด ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ์—์„œ ๋™์ผํ•œ ์ธ์Šคํ„ด์Šค๋ฅผ ๊ณต์œ ํ•ฉ๋‹ˆ๋‹ค.

// โœ… SoundManager ํด๋ž˜์Šค: ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด ๊ธฐ๋ฐ˜
export class SoundManager {
  private static instance: SoundManager;
  private audioMap: Map<string, HTMLAudioElement> = new Map();

  private constructor() {}  // ์™ธ๋ถ€์—์„œ ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ ๋ฐฉ์ง€

  static getInstance(): SoundManager {
    if (!SoundManager.instance) {
      SoundManager.instance = new SoundManager();
    }
    return SoundManager.instance;
  }
}

์ด๋ฅผ ํ†ตํ•ด ์‚ฌ์šด๋“œ ๊ด€๋ฆฌ๋ฅผ ์ค‘์•™ํ™”ํ•ด ์ค‘๋ณต ๊ฐ์ฒด ์ƒ์„ฑ์„ ๋ฐฉ์ง€ํ•ฉ๋‹ˆ๋‹ค.

2.2. ํšจ์œจ์ ์ธ ์‚ฌ์šด๋“œ ํ”„๋ฆฌ๋กœ๋”ฉ

์‚ฌ์šด๋“œ๋ฅผ ๋ฏธ๋ฆฌ ๋กœ๋“œํ•˜์—ฌ ์žฌ์ƒ ์‹œ ์ง€์—ฐ์„ ์ค„์ž…๋‹ˆ๋‹ค.

// โœ… ์‚ฌ์šด๋“œ ํ”„๋ฆฌ๋กœ๋”ฉ ๋ฉ”์†Œ๋“œ
preloadSound(id: string, src: string): void {
  if (!this.audioMap.has(id)) {
    const audio = new Audio(src);
    audio.load();  // ์‚ฌ์šด๋“œ ํŒŒ์ผ ๋ฏธ๋ฆฌ ๋กœ๋“œ, ์žฌ์ƒ ์ง€์—ฐ ์ตœ์†Œํ™”
    this.audioMap.set(id, audio);
  }
}

์–ด์ฐจํ”ผ ์ž๋™ ์žฌ์ƒ์ด ๋˜์ง€ ์•Š์œผ๋‹ˆ ๋ฏธ๋ฆฌ ์‚ฌ์šด๋“œ๊ฐ€ ๋‚˜์˜ค๋Š” ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋งˆ์šดํŠธ ์‹œ ๋ฏธ๋ฆฌ ๋„ฃ์–ด๋†“์„ ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋Šฅ์„ ํ™œ์šฉํ•ด ๋ฏธ๋ฆฌ ์‚ฌ์šด๋“œ๋ฅผ ๋ถˆ๋Ÿฌ์˜ต๋‹ˆ๋‹ค.

2.3. ์ž๋™ ์žฌ์ƒ ์ •์ฑ… ๋ช…์‹œ ๋ฐ ์—๋Ÿฌ ์ฒ˜๋ฆฌ

์‚ฌ์šฉ์ž๊ฐ€ ๋ช…์‹œ์ ์œผ๋กœ ์ƒํ˜ธ์ž‘์šฉํ•˜๊ธฐ ์ „์—๋Š” ์‚ฌ์šด๋“œ ์ž๋™ ์žฌ์ƒ์ด ์ฐจ๋‹จ๋ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ๋ช…์‹œํ•˜๊ธฐ ์œ„ํ•ด ์˜ค๋ฅ˜๋ฅผ ์‹๋ณ„ํ•˜๊ณ  ์‚ฌ์šฉ์ž์—๊ฒŒ ๋ช…ํ™•ํžˆ ์•Œ๋ฆฝ๋‹ˆ๋‹ค.

// โœ… ์ž๋™ ์žฌ์ƒ ์ •์ฑ… ์šฐํšŒ ๋ฐ ์—๋Ÿฌ ์ฒ˜๋ฆฌ
async playSound(id: string, volume = 1): Promise<void> {
  const audio = this.audioMap.get(id);
  if (!audio) {
    console.warn(`์‚ฌ์šด๋“œ ID(${id})๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.`);
    return;
  }

  try {
    audio.volume = volume;
    await audio.play();  // ์‚ฌ์šฉ์ž ์ƒํ˜ธ์ž‘์šฉ ์—†์„ ๊ฒฝ์šฐ ์‹คํŒจ ๊ฐ€๋Šฅ
    audio.currentTime = 0;  // ์žฌ์ƒ ์™„๋ฃŒ ํ›„ ์ฒ˜์Œ์œผ๋กœ ๋˜๊ฐ๊ธฐ
  } catch (error) {
    if (error instanceof Error) {
      if (error.name === 'NotAllowedError') {
        console.info('๋ธŒ๋ผ์šฐ์ € ์ •์ฑ…์— ์˜ํ•ด ์‚ฌ์šด๋“œ ์ž๋™ ์žฌ์ƒ์ด ์ฐจ๋‹จ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.');
      } else {
        console.error(`์‚ฌ์šด๋“œ ์žฌ์ƒ ์˜ค๋ฅ˜: ${error.message}`);
      }
    }
  }
}

3. ๊ตฌํ˜„์˜ ์žฅ์ 

3.1. ๋ฉ”๋ชจ๋ฆฌ ํšจ์œจ์„ฑ

  • ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด์œผ๋กœ Audio ๊ฐ์ฒด ์žฌ์‚ฌ์šฉ
  • ์‚ฌ์šด๋“œ ๋ฆฌ์†Œ์Šค์˜ ์ค‘๋ณต ๋กœ๋”ฉ ๋ฐฉ์ง€

3.2. ์‹คํ–‰ ์‹œ๊ฐ„ ์ตœ์ ํ™”

  • ์‚ฌ์šด๋“œ ํ”„๋ฆฌ๋กœ๋”ฉ์œผ๋กœ ์žฌ์ƒ ์ง€์—ฐ ์ตœ์†Œํ™”
  • ํšจ์œจ์ ์ธ ๋ฉ”๋ชจ๋ฆฌ ์บ์‹ฑ

3.3. ์—๋Ÿฌ ์ฒ˜๋ฆฌ ๊ฐ•ํ™”

  • ๋ธŒ๋ผ์šฐ์ € ์ž๋™ ์žฌ์ƒ ์ •์ฑ… ๋Œ€์‘
  • ์‚ฌ์šด๋“œ ์žฌ์ƒ ์‹คํŒจ์— ๋Œ€ํ•œ ์‘๋‹ต์„ ์‚ฌ์šฉ์ž or ๊ฐœ๋ฐœ์ž์—๊ฒŒ ์•Œ๋ฆผ - ์šฐ์•„ํ•œ ์ฒ˜๋ฆฌ

4. ์‹ค์ œ ์‚ฌ์šฉ ์˜ˆ์‹œ

4.1. ์‚ฌ์šด๋“œ ID์™€ ๋ฆฌ์†Œ์Šค ๋งคํ•‘

์‚ฌ์šด๋“œ๋ฅผ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•œ ID์™€ ๊ฒฝ๋กœ๋ฅผ ์ƒ์ˆ˜๋กœ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค. ์–ด๋–ค ID๊ฐ€ ์˜ค๋Š”์ง€์— ๋Œ€ํ•œ ๋ช…์‹œ๋ฅผ ํ•˜๊ณ , ๊ด€๋ฆฌ ์ผ๊ด€์„ฑ์„ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค.

// ์‚ฌ์šด๋“œ ID ์ •์˜
export const SOUND_IDS = {
  ENTRY: 'entry',
  BUTTON_CLICK: 'button_click',
} as const;

export const SOUND_PATHS = {
  [SOUND_IDS.ENTRY]: '/sounds/entry-sound.mp3',
  [SOUND_IDS.BUTTON_CLICK]: '/sounds/button-click.mp3',
};

4.2. ์ปดํฌ๋„ŒํŠธ์—์„œ์˜ ํ”„๋ฆฌ๋กœ๋”ฉ

์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋กœ๋“œ๋  ๋•Œ, ํ•„์š”ํ•œ ์‚ฌ์šด๋“œ๋ฅผ ๋ฏธ๋ฆฌ ๋กœ๋“œํ•ฉ๋‹ˆ๋‹ค.

import { SoundManager } from './SoundManager';
import { SOUND_IDS, SOUND_PATHS } from './constants';

const GameEntryComponent = () => {
  useEffect(() => {
    const soundManager = SoundManager.getInstance();
    soundManager.preloadSound(SOUND_IDS.ENTRY, SOUND_PATHS[SOUND_IDS.ENTRY]);
  }, []);

  const handlePlayerJoin = () => {
    const soundManager = SoundManager.getInstance();
    void soundManager.playSound(SOUND_IDS.ENTRY, 0.8); // ๋ณผ๋ฅจ ์กฐ์ • ํฌํ•จ
  };

  return <button onClick={handlePlayerJoin}>Join Game</button>;
};

4.3. ๋™์  ์‚ฌ์šด๋“œ ๋กœ๋”ฉ

๋™์ ์œผ๋กœ ์ƒˆ๋กœ์šด ์‚ฌ์šด๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ  ์žฌ์ƒํ•  ์ˆ˜ ์žˆ๋Š” ์œ ์—ฐ์„ฑ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

const handleDynamicSound = (id: string, path: string) => {
  const soundManager = SoundManager.getInstance();
  soundManager.preloadSound(id, path);
  void soundManager.playSound(id, 1.0);
};

<button
  onClick={() =>
    handleDynamicSound('dynamic_alert', '/sounds/dynamic-alert.mp3')
  }
>
  Play Alert
</button>;

์ด๋Ÿฌํ•œ ๊ตฌํ˜„์„ ํ†ตํ•ด ํšจ์œจ์ ์ด๊ณ  ์•ˆ์ •์ ์ธ ์‚ฌ์šด๋“œ ์‹œ์Šคํ…œ์„ ๊ตฌ์ถ•ํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด์˜ ์ ์šฉ์œผ๋กœ ๋ฆฌ์†Œ์Šค ๊ด€๋ฆฌ๊ฐ€ ์šฉ์ดํ•ด์กŒ๊ณ , ๋ธŒ๋ผ์šฐ์ €์˜ ์ œ์•ฝ์‚ฌํ•ญ๋„ ์ ์ ˆํžˆ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

๐Ÿ˜Ž ์›จ๋ฒ ๋ฒ ๋ฒ ๋ฒฑ

๐Ÿ‘ฎ๐Ÿป ํŒ€ ๊ทœ์น™

๐Ÿ’ป ํ”„๋กœ์ ํŠธ

๐Ÿชต ์›จ๋ฒ ๋ฒฑ ๊ธฐ์ˆ ๋กœ๊ทธ

๐Ÿช„ ๋ฐ๋ชจ ๊ณต์œ 

๐Ÿ”„ ์Šคํ”„๋ฆฐํŠธ ๊ธฐ๋ก

๐Ÿ“— ํšŒ์˜๋ก

Clone this wiki locally