[React 5] Howler.js 사용법, Redux-Toolkit을 이용한 볼륨 조절

김헤일리·2023년 1월 14일
0

React

목록 보기
9/10

실전 프로젝트에선 게임을 진행하다보니 게임 진행 시 효과음과 음악을 넣는 것이 좋을거라는 의견을 받았다.
소리를 추가해본 경험은 없기 때문에 이번에 추가해보고 싶었고, 구글링을 했더니 리액트에 소리를 넣는 라이브러리로 Howler.js라는 라이브러리를 많이 사용한다는 것을 알아냈다.

냉큼 github 문서와 다른 사람들이 어떻게 사용하는지 찾아보고 적용시켜보았다.


1. Howler.js 로 BGM 추가하기

  • 가장 첫번째로 시도한 것은 bgm을 추가하는 부분이었다.
  • assets 폴더에 BGM 폴더를 만들고, 효과음과 배경음으로 쓸 mp3 파일을 추가하고, 해당 파일들을 필요한 컴포넌트에 import 해서 사용했다.

📢 new Howl 생성자로 음악 재생하기

  • 프로젝트 진행 시, bgm은 특정 페이지에서만 재생하도록 기획하였었다.
  • 그렇기 때문에 페이지가 변경되었을 땐 음악이 자동적으로 멈춰야했고, 음악 소리 자체가 컸기 때문에 볼륨 조절할 수 있는 기능도 필요했었다.
 // BGM Section
  const range = useSelector((state) => state.bgmVolume.volume);
  // 1. 리덕스 툴킷을 이용해서 볼륨 조절을 전역 상태로 관리했다.
  // 1-1. range라는 상수에 volume 값을 할당하였다.

  const sound = new Howl({
  // 2. sound라는 상수에 new Howl 생성자 생성하고 원하는 옵션을 추가한다.
    src: [bgm],
    // 2-1. 사용할 배경음 src에 추가
    loop: true,
    // 2-2. 반복재생값 true로 설정 (반복재생 on)
    volume: 0.1,
    // 2-3. 기본 볼륨은 0.1로 설정 (최소 0, 최대 1의 값을 가질 수 있다)
  });
  const soundStop = () => sound.stop();
  // 3. soundStop이라는 함수가 실행되면 sound가 멈추도록 설정한다.

  useEffect(() => {
    sound.play();
    // 4. 화면이 렌더링될 때 sound,play()를 통해 배경음악을 실행시킨다.
    sound.on('play', () => {
      const history = createBrowserHistory();
      // 4-1. history라는 상수에 createBroserHistory() 함수를 할당해서 history 객체를 확인할 수 있게 한다.
      history.listen(({ action }) => {
      // 4-2. history 객체를 이용해 브라우저의 action을 감지하고,
        if (action === 'POP') {
        // 4-3. 감지한 브라우저의 action이 POP(이동)인 경우,
          sound.stop();
          // 4-4. bgm이 멈추도록 설정했다.
        }
      });
    });
    return soundStop;
    // 4-5. sound.on() 두번째 매개변수인 익명 함수의 리턴값은 soundStop으로 설정한다.
    // 4-6. loop을 true로 설정했기 때문에 soundStop이 실행될 일은 없을 듯.
  }, []);

  useEffect(() => {
    if (range) {
    // 5. 전역 상태로 관리하고 있는 range의 값이 있는 경우,
      if (range === 0) {
      // 5-1. range의 값이 0일때
        sound.mute();
        // 5-2. sound는 음소거가 된다.
      } else {
      // 5-3. range의 값이 0이외의 값일때
        Howler.volume(range);
        // 5-4. sound의 볼륨은 range의 값으로 설정된다.
        // 5-5. Howl 생성자로 실행될 음악을 초기에 설정하고, 일반적으로 play될 땐 그대로 sound를 이용한다.
        // 5-6. 하지만 global volume을 변경하게될땐 sound나 howl이 아닌 holwer를 사용해야한다.
      }
    }
  }, [sound, range]);
  // 5-7. sound와 range의 값이 변경될때마다 useEffect 내부의 내용이 재실행되어 볼륨 조절이 가능하게된다.

  // End BGM Section
  • 특정 컴포넌트에 BGM Section을 따로 표시하고 코드를 짜서 해당 컴포넌트가 위치한 페이지에 사용자가 도착했을 때 음악이 흘러나오도록 구현할 수 있었다.

📢 redux-toolkit을 이용한 bgm 볼륨 조절

  • 다만 진행하면서 어려웠던 부분은 볼륨을 조절하는 것이었는데, 음악 재생은 특정 페이지에서 진행이 됐지만, 볼륨 조절은 해당 페이지에서 설정 모달에서 가능하도록 만들어야했기 때문이다.
  • 다른 조의 코드를 참고하여 redux-toolkit으로 볼륨 자체를 전역으로 관리해서 문제를 해결할 수 있었다.
import { createSlice } from '@reduxjs/toolkit';

const initialState = {
  volume: 0.03,
  // 1. 볼륨의 초기값을 0.03으로 설정하여 소리가 너무 크지 않게 들리도록 하였다.
};

const soundSlice = createSlice({
  name: 'bgmVolume',
  // 2. slice 파일의 식별 이름을 설정한다.
  initialState,
  // 2-1. 위에 선언했던 초기값을 두번째 인자로 설정한다.
  reducers: {
  // 2-2. 세번째 인자로 initialState의 값을 변경할 리듀서 함수를 설정한다.
    setVolume: (_, action) => ({
    // 2-3. 해당 파일은 volume의 값만 변경하는 용도로, 변경할 값도 volume뿐이기 때문에 리듀서 함수도 1개가 된다.
    // 2-4. setVolume이라는 리듀서 함수를 생성해서, 변경내용 (action)을 매개변수로 설정한다.
    // 2-5. 그리고 setVolume 함수가 volume의 값을 action의 payload의 값으로 변화시킨다.
      volume: action.payload,
    }),
  },
});

export const { setVolume } = soundSlice.actions;
// 3. setVolume 함수를 외부로 export하여 외부에서 setVolume을 import 하고 volume의 값을 변경할 수 있게 한다.
export default soundSlice.reducer;
//4. store에 reducer를 등록하기 위해 soundSlice.reducer를 외부로 export한다.
  • slice 파일을 생성하여 외부에서 볼륨의 값을 조절할 수 있게 만들었다.
  • 비록 이 volume이 바로 howler의 볼륨이 되는 것은 아니지만, 이때 변경되는 volume의 값을 sound.volume()의 매개변수로 설정함으로서 직접적으로 볼륨 조절이 가능하게된다.
  • 그리고 volume의 값을 변경 시키는 것은 아래 컴포넌트이다.
  • 해당 컴포넌트는 modal 컴포넌트의 content로서 사용되는 컴포넌트 중 하나이다
function BGMTab({ setting }) {
  const sound = useSelector((state) => state.bgmVolume);
  // 1. seSelector를 이용하여 soundSlice의 state 중에서도 bgmVolume에 해당하는 값에 접근한다.
  // 1-1. 해당 값을 sound라는 상수에 할당한다.

  const [range, setRange] = useState(sound.volume);
  // 2. range, setRange 변수를 선언하여 useState의 초기값으로 initialState의 volume 값을 할당한다.

  const dispatch = useDispatch();
  // 3. 리듀서 함수를 사용할 수 있도록 dispatch라는 상수에 useDispatch() 함수를 할당한다.

  useEffect(() => {
    dispatch(setVolume(range));
    // 4. soundSlice 파일로부터 import해온 setVolume 리듀서 함수의 매개변수로 range를 설정한다.
    // 4-1. dispatch를 이용해서 range라는 액션 객체를 넘겨주어 volume의 상태를 업데이트한다.
  }, [dispatch, range]);
  // 4-2. dispatch가 일어나고 range의 값이 변경될때마다 useEffect 내용이 실행된다.

  return (
    <StBGMTab>
        사운드 조절 기능
      <StSubTitle>BGM 음량 조절</StSubTitle>
      <StVolumeCon>
          <StVolume
            className="rangeInput"
            type="range"
            min={0}
            max={0.1}
            step={0.001}
            value={range}
			// 5. type이 range인 인풋 필드의 value 값을 range로 설정한다.
            onChange={(e) => setRange(e.target.value)}
            // 5-1. onChange 이벤트를 감지하고, 해당 이벤트로 변경되는 value를 setRange의 값으로 할당한다.
            // 5-2. setState 함수를 통해 range의 값이 변경되고, 변경된 range의 값이 volume 값으로 변한다.
          />
      </StVolumeCon>
      <StBtnBox />
    </StBGMTab>
  );
}
  • 모달창에서 볼륨을 조절할 수 있게 기획했기 때문에 redux-toolkit을 사용하지 않았으면 굉장히 까다롭거나 성공하지 못 했을 것 같다.
  • 실제로 다른 조에서 이 방법을 사용했다는 것을 몰랐다면 혼자서는 생각해내지 못 하고 bgm 기능을 아예 제외했을 것이다.


2. Howler.js로 효과음 추가하기

  • howler.js를 이용해서 bgm을 추가했으니, 효과음도 추가하도록 했다.
  • 효과음은 seungdeng17.log님 벨로그를 참고해서 사용할 수 있는 코드를 쉽게 가져와서 custom hook을 만들 수 있었다.
import { Howl } from 'howler';

function useEffectSound(src, volume = 1) {
// 1. useEffectSound라는 함수를 선언하고, 매개변수로 src와 volume을 지정한다.
  let sound;
  // 1-1. sound라는 변수를 선언하고 값은 따로 할당하지 않는다.
  const soundEffect = (src) => {
  // 1-2. 중첩함수로 soundEffect 화살표 함수를 생성한다.
  // 1-3. 해당 함수의 매개변수는 src로 설정한다.
    sound = new Howl({ src });
    // 1-4. new howl 생성자를 만들고 sound라는 변수에 할당한다.
    sound.volume(volume);
    // 1-5. sound.volume의 매개변수는 useEffectSound의 인자인 volume과 동일하게 설정한다
  };
  soundEffect(src);
  // 1-6. useEffectSound 내부에서 soundEffect 함수를 호출한다.
  return sound;
  // 1-7. useEffectSound의 리턴값을 sound로 설정하여 soundEffect의 결과물이 sound에 할당되도록 한다.
}

export default useEffectSound;
  • 효과음 custom hook 사용 예시:
const startEffect = useEffectSound(startSound, 1);
const endEffect = useEffectSound(endSound, 1);
// custom hook을 호출하고, 특정 상수에 해당 custom hook을 할당한다.
// 사용하는 효과음이 2개라면 2개를 생성하고, useEffectSound의 첫번째 매개변수인 src를 다르게 설정한다.
// 이때 두번째 매개변수는 숫자로, useEffectSound의 volume값이 된다.

startEffect.play()
endtEffect.play()
// 효과음을 사용하고자 하는 곳에 .play()로 효과음이 플레이되게 만든다.


앞으로 변경할 값이 전역적으로 필요한 경우에 대해 조금 감이 잡힌것 같다.
구글링을 통해 새로운 것을 배우고, 또 원하는 기능을 써먹을 수 있는 코드를 발견해서 좋았다.

볼륨 조절이나 효과음 재생 부분을 직접 생각해냈다면 더 좋았겠지만, 찾아낸 코드를 이해하고 사용해보면서 배우는 것도 있을 것이라고 생각한다.

출처:

profile
공부하느라 녹는 중... 밖에 안 나가서 버섯 피는 중... 🍄

0개의 댓글