Metaverse Music
概要
Music シーンは、パッドでDJスキルをテストすることが可能です。サウンドや音楽を起動するだけでなく、ライトをコントロールすることもできます。
ここでは、ネットワークを通してオーディオトラックまたはライトを同期する方法を説明しています。
このシーンには、いくつかのDJパッドが含まれています。音楽をコントロールするものと、ライトをコントロールするものがあります。
デスクトップモードでは、各パッドの下部分にあるズームアイコンでフルスクリーン表示にすることができ、マウスを使用してUIをより精度高くコントロールすることができます。
ミュージックパッド
各ミュージックパッドは、一つ以上のボタンで構成されています。各ボタンはAudioSourceやサウンドに紐づいています。サウンドはループ設定することができます。ミュージックパッドにはボリューム変更のためのスライダーが付いています。
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はどのボタンが各オーディオソースをコントロールするか、そしてオーディオソースステートが変更されたときにどのボタンがお知らせを受けるかを把握します。
ユーザーがボタンをタッチすると、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()で新しいボタンステータスを受信すると、StateAuthorityをリクエストします(まだ持っていない場合)。それから、ネットワーク化されたディクショナリを更新して全てのリモートプレイヤーがアップデートを受信できるようにします。
C#
public async void ChangeAudioSourceState(IAudioSourceManager audioSourceManager, bool isPlaying)
{
if (!Object.HasStateAuthority)
{
await Object.WaitForStateAuthority();
}
PadsStatus.Set(audioSourceManager.AudioSourceIndex, isPlaying);
}
RefreshPads()メソッド、SyncAudioSource()メソッド、OnAudioStatusChanged()メソッドは、以下を担当します。
- ボリュームスライダー値に応じて各ボタン(
DJPadTouch)のオーディオソースをアップデートする - ボタンステータスが変更されたら(例:オーディオクリップ終了など)、ネットワーク化されたパッドディクショナリをアップデートする
- ネットワーク化されたディクショナリに応じて、各ボタンのaudioSource (再生/停止)を同期する
- ボタンに、ステータスが変更されたことを知らせてボタンの色をアップデートする
ネットワーク化されたディクショナリが変更される度にすぐに上記を行うのではなく、予測された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; }
ローカルのプレイヤーがボタンを押すと、関連するメソッド(ChangeLightState()/ChangeMovementState()/ChangeIntensity())によってLightPadManagerに知らされます。
すると、ネットワーク化されたディクショナリがアップデートされます。
例えば、ライトのオンオフが切り替えられると、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