게임 리팩토링 작업을 하면서 Voice 시스템도 수정해야 할 필요가 생겼다.
여러 시행착오를 거쳐서 적용한 방식을 블로그에 적어보고자 한다.
시작하기에 앞서
당연한 얘기지만, Fusion2와 Voice2를 먼저 프로젝트에 설치해야한다.
Fusion2 : https://assetstore.unity.com/packages/tools/network/photon-fusion-267958
Photon Fusion | 네트워크 | Unity Asset Store
Get the Photon Fusion package from Photon Engine and speed up your game development process. Find this & other 네트워크 options on the Unity Asset Store.
assetstore.unity.com
Voice2 : http://assetstore.unity.com/packages/p/photon-voice-2-130518
Photon Voice 2 | 음악 | Unity Asset Store
Get the Photon Voice 2 package from Photon Engine and speed up your game development process. Find this & other 음악 options on the Unity Asset Store.
assetstore.unity.com
이 두 에셋을 프로젝트에 적용하게 된다.
Photon voice2에서는 기본적으로 Photon Pun과 Chat이 같이 깔리게 되는데, Fusion이랑은 중복되면서 문제가 발생할 수 있으니 모두 제거해주었다.
https://doc.photonengine.com/voice/current/getting-started/voice-intro
https://doc.photonengine.com/voice/current/getting-started/voice-for-fusion
Voice 2 - Voice Intro | Photon Engine
Photon Voice 2 is an SDK that makes it easy to add high quality low latency voice chat to a Unity application. It is built on top of Photon Realtime a
doc.photonengine.com
Voice 2 - Voice - Fusion Integration | Photon Engine
This integration simplifies the use of Photon Voice inside Photon Fusion projects. The main use case is when each player has network-spawned object (c
doc.photonengine.com
두 링크를 통해 Pun 및 Chat을 제거한 후 Voice를 적용하였다.
네트워크 러너 생성
현재 구현한 게임에서는 Photon에 사용한 NetworkRunner를 맵에 스폰해둔 것이 아니라 런타임에 생성되는 방식으로 구현하였다.
게임 내에서 버튼을 통해 세션을 생성, 참여를 할 경우에는 다음과 같은 코드가 실행된다.
GameObject runnerGo = new GameObject("@NetworkRunner");
// NetworkRunner 붙이기
_networkRunner = runnerGo.AddComponent<NetworkRunner>();
_networkRunner.ProvideInput = true;
_networkRunner.AddCallbacks(this);
DontDestroyOnLoad(_networkRunner);
이를 통해 NetworkRunner를 생성하고 세션에 접속하게 되면 Runner 게임 오브젝트에 FusionVoiceClient를 붙여주어 Voice 통신을 할 수 있게 해주었다.
Fusion Voice Client는 음성 채팅을 하기 위해 Fusion 클라이언트가 세션에 접속하게 되면 자동으로 음성 채팅 방에도 접속하게 해주고 관리해주는 컴포넌트이다.
var result = await _networkRunner.StartGame(new StartGameArgs()
{
. . .
});
if (result.Ok)
{
var voiceClient = runnerGo.AddComponent<FusionVoiceClient>();
voiceClient.VoiceLogger.LogLevel = Photon.Voice.LogLevel.Error;
. . .
}
네트워크 러너가 생성되고 또한 보이스 클라이언트도 붙게 된다면 자동적으로 방에 가입도 될 것이다.
이제 클라이언트들이 서로 목소리를 받고, 전달하는 작업이 필요하다.
네트워크 상태에서 여러 상황에 대한 콜백을 받기 위해서는 INetworkRunnerCallbacks 를 이용해 값을 받아야 한다.
클라이언트가 접속하게 되면 그 클라이언트가 조종하는 프리팹을 소환하게 할 것이다.
INetworkRunnerCallbacks 에 존재하는 콜백 중 하나인 OnPlayerJoined 를 이용해 프리팹을 생성할 것이다.
public class SessionManager : MonoBehaviour, INetworkRunnerCallbacks
{
. . .
public void OnPlayerJoined(NetworkRunner runner, PlayerRef player)
{
if (runner.IsServer)
{
GameObject playerObject = Resources.Load<GameObject>("PlayerObject");
if (playerObject != null)
{
NetworkObject networkPlayerObject = runner.Spawn(playerObject, Vector3.zero, Quaternion.identity, player);
networkPlayerObject.name = "@Player" + player.PlayerId;
DontDestroyOnLoad(networkPlayerObject);
}
}
}
. . .
}
이렇게 플레이어 프리팹을 생성해서 스폰하게 하였다.

Resources.Load로 불러오는 프리팹은 다음과 같은 구성으로 되어 있다.
각각의 설명을 하자면 다음과 같다.
- Recorder : 녹음기. 내 목소리를 녹음하여 다른 클라이언트들에게 전달하는 역할을 수행한다.
- Speaker : 재생기. 네트워크를 통해 전달된 다른 클라이언트들의 목소리를 재생하는 역할을 수행한다.
재생 및 볼륨 조절을 위해 Audio Source가 자동으로 생성된다. - Voice Network Object : 누가 전달하는지와 어떤 클라이언트에서 재생해야하는지를 관리하는 통합 관리 오브젝트입니다.
필자는 각 클라이언트에서는 다른 플레이어의 목소리를 조절하게 하고, 자신의 목소리도 관리해야 한다고 생각하여 각 플레이어 프리팹에 녹음기와 재생기를 모두 붙였다.
각각의 플레이어가 각각의 플레이어 프리팹을 통해 원하는 상대방의 목소리 크기를 조절할 수 있고, 자신의 Recorder를 통해 내 목소리의 전달 여부를 설정할 수 있게 하여 원활한 음성 채팅을 진행할 수 있도록 작성하였다.

Voice2를 적용하기 위해 적용했던 방식을 순서대로 간단하게 정리하면 다음과 같다.
- NetworkRunner를 세션 생성 / 접속 시에 생성.
- 세션이 생성되어 OK값을 보내게 된다면 Fusion Voice Client 컴포넌트를 오브젝트에 부착.
- 클라이언트가 접속함에 따라 Prefab이 생성(OnPlayerJoined)
- Prefab에 붙여져 있던 Voice Network Object를 통해 자동으로 접속한 세션의 음성 채팅 방에 참여.
- Recorder로 내 입력값을 음성 채팅 방에 다른 클라이언트에 전달.
Speaker로 다른 클라이언트의 전달값을 재생.
이렇게 하여 Fusion2 환경에서 Voice2를 적용할 수 있었다.
'Unity > 공부' 카테고리의 다른 글
| [Unity C#] 자연스럽게 등장하는 UI 애니메이션 구현 (0) | 2025.04.19 |
|---|---|
| [Unity C#] Dynamic Menu에 따른 카메라 움직임 구현 (0) | 2025.04.19 |
| [Unity C#] 씬 이동 시 로딩 화면 만들기 (0) | 2025.03.26 |
CSE & GAME 개발 블로그
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 부탁드립니다!