Unity、Photonで多数決機能を実装する方法

Unity、Photon初心者です。お手数をおかけしてしまい、大変申し訳ございませんが、助けてくださると助かります。

[やりたいこと]
・Unity✖︎Photonで多数決機能を実装したい
AとB、2つの動画をボタン式の選択肢で提示し、複数人の多数決で多く選択された方の動画が流れるシステムを作りたい。

[出来ていること]
①ボタンを選択したら対応した動画が流れる。(notマルチプレイ対応)
②Photonサーバーに接続し、複数の人数が動画を選択できる状態になる(動画の同期は出来ていない)

[教えていただきたいこと(お手数をおかけしますが、コードを教えていただけると助かります)]
投票の管理をマスタークライアントで行う
①ReceiverGroup に MasterClient を指定して Photon.Pun.PhotonNetwork.RaiseEvent() を呼び、投票内容をマスタークライアントに送る
(最初にプレイヤーの人数を認識する。次にChange V Buttonスクリプトにおいてボタンを押したらマスターに投票結果を送る?)
②マスタークライアントは投票を集計して最多得票を決定し、同じく RaiseEvent で全員に結果を送る
(参加者の人数と投票結果から、多数決で選ばれた動画を再生するようにRaiseEventで全員に命令?)
*Change V Buttonスクリプトを書き換えればいいのでしょうか。。。?

[現状]
1.動画の選択再生(マルチ非対応、一人で選択したら動画が流れる状況)
イメージ説明

①PlaneオブジェクトにVideo PlayerとChange VIdeoスクリプト(動画を読み込んで再生)をアタッチ
イメージ説明

C#

using UnityEngine;using UnityEngine.Video; public class ChangV : MonoBehaviour { public VideoPlayer Vp { get; private set; } void Start() { Vp = GetComponent<VideoPlayer>(); //↓VideoPlayerの再生準備ができたとき、OnVideoPlayerPreparedが呼ばれる Vp.prepareCompleted += OnVideoPlayerPrepared; } void OnVideoPlayerPrepared(VideoPlayer vp) { vp.Play(); } public void ChangeVideo(VideoID id) { //既にVideoPlayerに動画が読み込まれている場合 if (Vp.clip != null) { Vp.Stop(); //↓その動画をメモリから解放する Resources.UnloadAsset(Vp.clip); } var meta = id.GetMeta(); // var title = meta.Title; //動画をメモリに読み込む Vp.clip = Resources.Load<VideoClip>(meta.Path); //↓VideoPlayerに再生準備をさせる Vp.Prepare(); }}

②Canvasにボタンの親オブジェクトを配置し、Change V Button Contorollerスクリプト(ボタンの管理)をアタッチ
イメージ説明

C#

using UnityEngine;using UnityEngine.Assertions;using UnityEngine.Video; /// <summary>/// ボタンの管理/// すべてのボタンをこのスクリプトがアタッチされた子に配置/// </summary>public class ChangVButtonController : MonoBehaviour { [SerializeField] ChangV changV; /// <summary> /// Videoが再生中か? /// </summary> public bool IsPlaying => changV.Vp.isPlaying; ChangVButton[] buttons; void Awake() { buttons = GetComponentsInChildren<ChangVButton>(true); Assert.IsTrue(buttons.Length > 0, "ボタンが0です。すべてのボタンをこのスクリプトがアタッチされた子に配置してください。"); } void Start() { foreach (var button in buttons) { button.SetController(this); } changV.Vp.loopPointReached += OnLoopPointReached; } public void ChangeVideo(VideoID videoID) { Assert.IsTrue(!IsPlaying, "再生中に再生が呼ばれました"); changV.ChangeVideo(videoID); foreach (var button in buttons) { button.gameObject.SetActive(false); } } void OnLoopPointReached(VideoPlayer source) { foreach (var button in buttons) { button.gameObject.SetActive(true); } } void Reset() { changV = FindObjectOfType<ChangV>(); }}

③ボタンA,BにChang V Buttonスクリプト(動画の選択)をアタッチ
イメージ説明

C#

using UnityEngine;using UnityEngine.UI; [RequireComponent(typeof(Button))]public class ChangVButton : MonoBehaviour { [SerializeField] Button playButton; [SerializeField] VideoID playTarget; ChangVButtonController controller; void Start() { playButton.onClick.AddListener(ClickPlayButton); } public void SetController(ChangVButtonController controller) { this.controller = controller; } /// <summary> /// プレイボタンのクリック /// </summary> void ClickPlayButton() { if (!controller.IsPlaying) { controller.ChangeVideo(playTarget); } } void Reset() { playButton = GetComponent<Button>(); }}

④アセットにVideoMetaDataスクリプト(動画の管理)を追加

C#

using System.Collections.Generic;using UnityEngine; /// <summary>/// ビデオのID/// ※ 最初に設定する順番変更禁止。増やす場合は後に追加/// </summary>public enum VideoID{ London = 0, op = 1, yasi = 2, // 他動画のIDをここに追加していく} public class VideoMeta { public VideoID ID; public string Title; public string Path; // 入れたい情報を書き足していく} public static class VideoExtensions { static readonly IEnumerable<VideoMeta> Metas = new VideoMeta[] { new VideoMeta { ID = VideoID.London, Title = "ロンドン", Path = "London" }, new VideoMeta { ID = VideoID.op, Title = "op", Path = "op" }, new VideoMeta { ID = VideoID.yasi, Title = "yasi", Path = "yasi" }, // 他動画の情報をここに追加していく }; /// <summary> /// Videoの情報を取得 /// </summary> public static VideoMeta GetMeta(this VideoID id) { foreach (var meta in Metas) { if (meta.ID == id) { return meta; } } Debug.LogError($"存在しないVideo {id}"); return default; }}

2.複数人で動画選択(Photon実装)
①アバター(白い円)のプレハブを作成し、AvatarControllerスクリプト(マスカーソルに合わせて白い円を動かす)→誰がどの選択肢を選ぶか見えるように
イメージ説明

C#

using System.Collections;using System.Collections.Generic;using UnityEngine;using Photon.Pun; // MonoBehaviourPunCallbacksを継承して、photonViewプロパティを使えるようにするpublic class AvatarController : MonoBehaviourPunCallbacks { private void Update() { // 自身が生成したオブジェクトだけに移動処理を行う if (photonView.IsMine) { Vector3 touchScreenPosition = Input.mousePosition; // 10.0fに深い意味は無い。画面に表示したいので適当な値を入れてカメラから離そうとしているだけ. touchScreenPosition.z = 120.0f; Camera gameCamera = Camera.main; Vector3 touchWorldPosition = gameCamera.ScreenToWorldPoint(touchScreenPosition); transform.position = touchWorldPosition; } }}

②OtherPlayersオブジェクトにOtherPlayersスクリプト(Photonサーバーに接続したらアバター(白い円)を作成する)をアタッチ
イメージ説明

C#

using Photon.Pun;using Photon.Realtime;using UnityEngine; // MonoBehaviourPunCallbacksを継承して、PUNのコールバックを受け取れるようにするpublic class OtherPlayers : MonoBehaviourPunCallbacks { private void Start() { // プレイヤー自身の名前を"Player"に設定する PhotonNetwork.NickName = "Player"; // PhotonServerSettingsの設定内容を使ってマスターサーバーへ接続する PhotonNetwork.ConnectUsingSettings(); } // マスターサーバーへの接続が成功した時に呼ばれるコールバック public override void OnConnectedToMaster() { // "Room"という名前のルームに参加する(ルームが存在しなければ作成して参加する) PhotonNetwork.JoinOrCreateRoom("Room", new RoomOptions(), TypedLobby.Default); } // ゲームサーバーへの接続が成功した時に呼ばれるコールバック public override void OnJoinedRoom() { // ランダムな座標に自身のアバター(ネットワークオブジェクト)を生成する var position = new Vector3(Random.Range(-3f, 3f), Random.Range(-3f, 3f)); PhotonNetwork.Instantiate("Avatar", position, Quaternion.identity); }}

コメントを投稿

0 コメント