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