Metaverse Music
개요
Music 씬을 통해 플레이어는 소리와 음악을 트리거하고 조명 쇼를 제어할 수 있는 패드로 DJ 기술을 테스트할 수 있습니다.
여기에서는 네트워크를 통해 오디오 트랙 또는 조명을 동기화하는 방법을 보여 줍니다.
씬에는 여러 개의 DJ 패드가 포함됩니다. 어떤 것은 음악을 통제하고 다른 것은 조명을 통제합니다.
데스크톱 모드에서는 마우스로 UI를 더 잘 제어할 수 있도록 각 패드의 하단에 있는 확대/축소 아이콘을 사용하여 전체 화면으로 표시할 수 있습니다.
뮤직 패드
각 뮤직 패드는 하나 이상의 버튼으로 구성되어 있습니다. 각 버튼은 오디오 소스와 사운드에 해당합니다. 사운드를 루프로 설정할 수 있습니다.
뮤직 패드에는 볼륨을 변경하기 위한 슬라이더가 포함되어 있습니다.
DJ 패드는 3개 클래스에 의해 관리됩니다:
DJPadVolumeSlider
: 패드의 볼륨을 관리합니다DJPadTouch
: 사운드 버튼을 관리합니다DJPadManager
: 패드의 전반적인 기능을 관리합니다
DJPadVolumeSlider
플레이어가 슬라이더를 터치하여 볼륨을 변경하면 DJPadVolumeSlider
가 DJPadManager ChangeVolume
메서드를 호출합니다.
C#
void RequestVolumeChange(float volume)
{
padManager.ChangeVolume(volume);
}
public async void ChangeVolume(float volume)
{
// We use an attribute, so if another volume is requested while taking the authority, the last volume request is the one executed
lastVolumeRequest = volume;
if (!Object.HasStateAuthority)
{
await Object.WaitForStateAuthority();
}
MasterVolume = lastVolumeRequest;
}
그런 다음 DJPadManager
의 네트워크 변수 MasterVolume
이 네트워크를 통해 동기화됩니다.
C#
[Networked(OnChanged = nameof(OnMasterVolumeChanged))]
public float MasterVolume { get; set; } = 1;
static void OnMasterVolumeChanged(Changed<DJPadManager> changed)
{
changed.Behaviour.OnMasterVolumeChanged();
}
void OnMasterVolumeChanged()
{
if(volumeManager != null) volumeManager.OnVolumeChanged(this, MasterVolume);
}
모든 사용자가 로컬 볼륨을 업데이트할 수 있도록 합니다.
C#
public void OnVolumeChanged(DJPadManager bPMClipsPlayer, float volume)
{
ChangeSliderValue(volume);
}
DJPadTouch
각 버튼은 인덱스를 참조하므로 DJPadManager
는 각 오디오 소스를 제어하는 버튼을 알고 오디오 소스 상태가 변경될 때 알림을 받아야 하는 버튼을 알 수 있습니다.
그래서 사용자가 버튼을 누르면 DJPadTouch
의 UpdatePadStatus()
메소드를 호출합니다.
그러면 UpdatePadStatus()
가 DJPadManager
에게 새 상태를 알립니다.
C#
public void UpdatePadStatus()
{
if (audioSource.clip)
{
isPlaying = !isPlaying;
padManager.ChangeAudioSourceState(this, isPlaying);
}
}
또한 버튼이 터치되면 DJPadManager
는 DJPadTouch
의 OnAudioSourceStatusChanged
메소드를 호출하여 새로운 상태에 따라 버튼 색상을 업데이트하도록 요청합니다.
DJPadManager
각 버튼의 상태는 PadsStatus
라는 네트워크 사전 덕분에 동기화됩니다.
C#
[Networked]
Capacity(50)]
public NetworkDictionary<int, NetworkBool> PadsStatus { get; }
처음에 DJPadManager
는 모든 버튼을 audioSourceManagers
딕셔너리에 저장합니다(모든 DJPadTouch
는 IAudioSourceManager
인터페이스를 구현합니다).
C#
foreach (var manager in GetComponentsInChildren<IAudioSourceManager>(true))
{
audioSourceManagers[manager.AudioSourceIndex] = manager;
}
DJPadManager
가 ChangeAudioSourceState()
로 표시된 새 버튼 상태를 수신하면 상태 요청시 권한이 아직 없는 경우 권한을 부여한 다음 모든 원격 사용자가 업데이트를 받을 수 있도록 네트워크 딕셔너리를 업데이트합니다.
C#
public async void ChangeAudioSourceState(IAudioSourceManager audioSourceManager, bool isPlaying)
{
if (!Object.HasStateAuthority)
{
await Object.WaitForStateAuthority();
}
PadsStatus.Set(audioSourceManager.AudioSourceIndex, isPlaying);
}
RefreshPads()
, SyncAudioSource()
& OnAudioStatusChanged()
메소드는 다음의 역할을 합니다 :
- 볼륨 슬라이더 값에 따라 각 버튼(
DJPadTouch
)의 오디오 소스를 업데이트합니다 - 버튼 상태가 변경된 경우(예: 오디오 클립이 완료된 경우) 패드 네트워크 사전 업데이트
- 네트워크 사전에 따라 각 버튼의 오디오 소스(플레이/정지)를 동기화
- 버튼 색상을 업데이트하기 위해 상태가 변경되었음을 버튼에 알립니다
네트워크 된 딕셔너리가 변경되는 즉시 이러한 업데이트를 수행하는 대신 사전 정의된 BPM 매개 변수를 기반으로 정기적으로 수행됩니다
(AudioLoop()
메소드).
라이트 패드
라이트 패드는 4개의 조명을 제어합니다.
각 조명에 대해 패드를 사용하면 다음 작업을 수행할 수 있습니다:
- 전등 켬/끔
- 전등 움직임 켬/끔
- 광도 변경
라이트 패드 구조는 뮤직 패드와 매우 유사합니다.
조명은 다음 클래스에 의해 관리됩니다:
LightPadManager
: 패드의 전반적인 기능을 관리LightPadTouch
: 조명 버튼 관리LightSystem
: 조명 상태 관리LightIntensitySlider
: 빛의 강도를 관리LightDirectionControler
: 빛의 회전을 관리
LightIntensitySlider
LightIntensitySlider
는 DJPadVolumeSlider
와 매우 유사합니다.
플레이어가 슬라이더를 터치하여 강도를 변경하면 RequestIntensityChange
는 LightPadManager ChangeIntensity()
메소드를 호출합니다.
반대로 원격 플레이어가 강도를 변경된 경우 LightPadManager
는 OnLightStatusChanged
메소드를 호출해 슬라이더 위치를 업데이트합니다.
LightPadTouch
LightPadTouch
는 라이트 버튼을 관리합니다.
LightPadManager
에 정의된 바와 같이 3가지 종류의 라이트 버튼이 있습니다:
C#
public enum LightManagerType
{
OnOff, // switch on/off the light
Movement, // switch on/off the movement
Intensity // slider to change the intensity
}
각 버튼은 라이트 인덱스를 참조하므로 LightPadManager
는 각 라이트를 제어하는 버튼을 알고 조명 상태가 변경될 때 어떤 버튼을 통지해야 하는지를 알 수 있습니다.
UpdatePadStatus()
는 플레이어가 버튼을 누르면 호출됩니다. 상태가 바뀌어야 한다는 것을 PadManager
에게 알립니다.
OnLightStatusChanged()
는 상태가 변경되면 PadManager
에 의해 호출되므로 버튼 UI를 업데이트해야 합니다.
LightSystem
LightSystem
클래스는 추상 클래스 EffectSystem
에서 상속됩니다.
LightSystem
은 ChangeState
메소드로 수신된 파라미터에 따라 조명 상태를 변경합니다:
LightDirectionControler
LightDirectionControler
클래스는 라이트 게임 객체를 회전시키는 로테이터 스크립트를 제어합니다.
LightDirectionControler
는 LightSystem에 의해 활성화/비활성화됩니다.
LightPadManager
LightPadManager
는 모든 라이트 객체(LightInfo
)를 참조합니다.
각각의 LightInfo
에는 빛 매개변수를 수정할 수 있는 인덱스와 효과 시스템이 있습니다.
C#
public struct LightInfo
{
public int lightIndex;
public EffectSystem effectSystem;
}
시작할 때 LightPadManager
는 모든 라이트 버튼을 사전에 등록합니다.
또한 조명의 다양한 매개변수(조명 켜기/끄기, 이동 켜기/끄기, 조명 강도)를 저장할 수 있는 3개의 네트워크 딕셔너리가 있습니다.
C#
[Networked(OnChanged = nameof(OnLightStatusChanged))]
[Capacity(MAX_LIGHTS)]
public NetworkDictionary<int, NetworkBool> LightStatus { get; }
[Networked(OnChanged = nameof(OnLightMovementStatusChanged))]
[Capacity(MAX_LIGHTS)]
public NetworkDictionary<int, NetworkBool> LightMovementStatus { get; }
[Networked(OnChanged = nameof(OnLightIntensityChanged))]
[Capacity(MAX_LIGHTS)]
public NetworkDictionary<int, float> LightIntensities { get; }
로컬 플레이어가 버튼을 누르면 LightPadManager
가 관련 메소드(ChangeLightState()/ChangeMovementState()/ChangeIntensity()
)에 의해 알려집니다.
그런 다음 연결된 네트워크 딕셔너리가 업데이트됩니다.
예를 들어 라이트가 켜지거나 꺼지면 LightPadManager
가 상태 권한이 없는 경우 네트워크 사전을 업데이트하여 모든 원격 사용자가 업데이트를 받을 수 있도록 StateAuthority
를 요청합니다.
C#
public async void ChangeLightState(LightPadTouch lightPadTouch, bool isLightOn)
{
if (!Object.HasStateAuthority)
{
await Object.WaitForStateAuthority();
}
// update network status
LightStatus.Set(lightPadTouch.LightIndex, isLightOn);
// movement must be stopped if the light is off
if (!isLightOn)
LightMovementStatus.Set(lightPadTouch.LightIndex, false);
}
딕셔너리가 업데이트되는 즉시 Refresh()
메소드는 로컬 및 원격 플레이어에서 호출됩니다.
C#
private static void OnLightStatusChanged(Changed<LightPadManager> changed)
{
changed.Behaviour.Refresh();
}
private static void OnLightMovementStatusChanged(Changed<LightPadManager> changed)
{
changed.Behaviour.Refresh();
}
private static void OnLightIntensityChanged(Changed<LightPadManager> changed)
{
changed.Behaviour.Refresh();
}
Refresh()
는 UpdateLightsAndButtons()
메소드를 사용하여 모든 조명 상태 및 관련 버튼 업데이트를 담당합니다.
플레이어가 참여하면 조명이 네트워크 딕셔너리로 업데이트됩니다.
Back to top