このページは編集中です。更新が保留になっている可能性があります。
Available in the Industries Circle
fusion | v1 switch to V2  

Metaverse Music

概要

Music シーンは、パッドでDJスキルをテストすることが可能です。サウンドや音楽を起動するだけでなく、ライトをコントロールすることもできます。 ここでは、ネットワークを通してオーディオトラックまたはライトを同期する方法を説明しています。 このシーンには、いくつかのDJパッドが含まれています。音楽をコントロールするものと、ライトをコントロールするものがあります。

デスクトップモードでは、各パッドの下部分にあるズームアイコンでフルスクリーン表示にすることができ、マウスを使用してUIをより精度高くコントロールすることができます。

Fusion Metaverse Music

トップに戻る
 

ミュージックパッド

各ミュージックパッドは、一つ以上のボタンで構成されています。各ボタンはAudioSourceやサウンドに紐づいています。サウンドはループ設定することができます。ミュージックパッドにはボリューム変更のためのスライダーが付いています。

Fusion Metaverse Music

DJパッドは、3つのクラスが挙動を管理しています。

  • DJPadVolumeSlider : パッドのボリュームを管理
  • DJPadTouch : サウンドボタンを管理
  • DJPadManager : パッドの全体的な機能を管理

トップに戻る
 

DJPadVolumeSlider

プレイヤーがスライダーを触ってボリュームを変更すると、DJPadVolumeSliderDJPadManager ChangeVolumeメソッドを呼び出します。

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がネットワーク上で同期されます。

[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);
}

すると、全員にがローカルのボリュームを更新できるようになります。

public void OnVolumeChanged(DJPadManager bPMClipsPlayer, float volume)
{
    ChangeSliderValue(volume);
}

トップに戻る
 

DJPadTouch

各ボタンはインデックスを参照しているため、DJPadManagerはどのボタンが各オーディオソースをコントロールするか、そしてオーディオソースステートが変更されたときにどのボタンがお知らせを受けるかを把握します。 ユーザーがボタンをタッチすると、DJPadManagerDJPadTouchUpdatePadStatus()メソッドを呼び出します。 それから、UpdatePadStatus()DJPadManagerに新しいステータスについて知らせます。

public void UpdatePadStatus()
{
    if (audioSource.clip)
    {
        isPlaying = !isPlaying;
        padManager.ChangeAudioSourceState(this, isPlaying);
    }
}

また、ボタンがタッチされると、DJPadManagerDJPadTouchOnAudioSourceStatusChangedメソッドを呼び出して、新しいステータスに応じてボタンの色をアップデートします。

トップに戻る
 

DJPadManager

各ボタンのステートは、PadsStatusというネットワークディクショナリの力で同期されます。

[Networked]
Capacity(50)]
public NetworkDictionary<int, NetworkBool> PadsStatus { get; }

開始時に、DJPadManageraudioSourceManagersディクショナリにある全てのボタンを保存します(すべてのDJPadTouchIAudioSourceManagerインターフェースを実装します)。

foreach (var manager in GetComponentsInChildren<IAudioSourceManager>(true))
{
    audioSourceManagers[manager.AudioSourceIndex] = manager;
}

DJPadManagerChangeAudioSourceState()で新しいボタンステータスを受信すると、StateAuthorityをリクエストします(まだ持っていない場合)。それから、ネットワーク化されたディクショナリを更新して全てのリモートプレイヤーがアップデートを受信できるようにします。

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に非常に類似しています。プレイヤーがスライダーに触れて強度を変えると、RequestIntensityChangeLightPadManager ChangeIntensity()メソッドを呼び出します。

そのほかの方法では、リモートプレイヤーが強度を変更した場合に、スライダーの位置をアップデートするためにLightPadManagerによってOnLightStatusChangedメソッドが呼び出されます。

トップに戻る
 

LightPadTouch

LightPadTouchはライトボタンを管理します。 LightPadManagerで定義されているように、ライトボタンには3種類あります。

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メソッドで受信するパラメータに応じてライトステートを変更させます。

   - ライトの有効化 (オン・オフ)
   - ライトの動作有効化 (オン・オフ)
   - ライトの強度 (float)

トップに戻る
 

LightDirectionControler

LightDirectionControlerクラスは、ライトゲームオブジェクトを回転させるロテータースクリプトをコントロールします。 LightDirectionControlerは、 LightSystemによって有効化・無効化されます 。

トップに戻る
 

LightPadManager

LightPadManagerは全てのライトオブジェクトを参照します。(LightInfo)。

LightInfoにはインデックスと、ライトパラメータを修正するためのエフェクトシステムがあります。

public struct LightInfo
{
    public int lightIndex;
    public EffectSystem effectSystem;
}

開始時に、LightPadManagerが全てのライトボタンをディクショナリに登録されます。

また、ライトのさまざまなパラメータ(ライトのオンオフ、動作のオンオフ、ライトの強度)を保存するための目っとワーク化されたディクショナリが3つあります。

[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に知らされます。 すると、ネットワーク化されたディクショナリがアップデートされます。

例えば、ライトのオンオフが切り替えられると、LightPadManagerStateAuthorityをリクエストします(まだ持っていない場合)。それから、ネットワーク化されたディクショナリをアップデートして全てのリモートユーザーがアップデートを受け取れるようにします。

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()メソッドが呼び出されます。

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()メソッドを使用してボタンを関連付けます。

プレイヤーが参加すると、そのプレイヤーのライトがネットワーク化されたディクショナリでアップデートされます。

ドキュメントのトップへ戻る