今回はオンラインゲームの一番大事な要素とも言えるチャットを作成していきましょう。
チャットの導入手順
チャット機能自体はPhotonのスクリプトが用意されているので実はとても簡単に実装できます。
導入手順は以下の通りです。
- 空のGameObjectを作成し、ChatManagerと名付けます
- ChatManagerにInRoomChatスクリプトをアタッチする
(InRoomChat.csはAsset/Photon Unity Networking/UtilityScriptsフォルダの中にあります)
以上の手順で以下の画像のようなとりあえず動くチャット機能が導入されます。
しかしこのままだと背景色によってはチャットの文字が非常に見づらいのでInRoomChatスクリプトを改変して、簡易なチャットUIを作成しましょう。
簡易チャットUIの実装
InRoomChatを以下のように書き換えましょう。
InRoomChat.csのソースコード
※InChatRoom.csでエラーが出ていたようなので訂正しました(2018/4/12)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 |
using System.Collections.Generic; using UnityEngine; using System.Collections; [RequireComponent(typeof(PhotonView))] public class InRoomChat : Photon.MonoBehaviour { #region 変数宣言 //範囲チャット実装のためのオブジェクト、変数定義 GameObject[] players; //全てのプレイヤーキャラ取得用 GameObject sender; //送信キャラ取得用 GameObject myPlayer; //自分のキャラ取得用 GUIStyle ChatStyle = new GUIStyle(); //範囲チャットStyle GUIStyleState ChatStyleState = new GUIStyleState(); GUIStyle AllChatStyle = new GUIStyle(); //全体チャットStyle GUIStyleState AllChatStyleState = new GUIStyleState(); public Rect GuiRect = new Rect(0, 0, 300, 200); //チャットUIの大きさ設定用 public bool IsVisible = true; //チャットUI表示非表示フラグ public bool AlignBottom = true; public List<string> messages = new List<string>(); //チャットログ格納用List public List<bool> chatKind = new List<bool>(); //チャットログの種類格納用(範囲チャor全チャ) public string inputLine = "";//入力文章格納用String private Vector2 scrollPos = Vector2.zero; //スクロールバー位置 #endregion #region Start関数 Updata関数 public void Start() { //myPlayerオブジェクト取得(範囲チャット発言時にpositionとmyPM使う) GetmyPlayer(); //範囲チャットの場合は白文字にし、文字がUIからあふれた場合は折り返す設定 ChatStyleState.textColor = Color.white; ChatStyle.normal = ChatStyleState; ChatStyle.wordWrap = true; //全体チャットの場合は赤文字にし、文字がUIからあふれた場合は折り返す設定 AllChatStyleState.textColor = Color.red; AllChatStyle.normal = AllChatStyleState; AllChatStyle.wordWrap = true; } public void Update() { //ChatUIの位置を調整 this.GuiRect.y = Screen.height - this.GuiRect.height; //ChatUIの大きさ調整 GuiRect.width = Screen.width / 3; GuiRect.height = Screen.height / 3; } #endregion #region OnGUI関数 public void OnGUI() { if (!this.IsVisible || !PhotonNetwork.inRoom) //表示フラグがOFFまたはphotonにつながっていないとき { //UI非表示 return; } //ChatUIの作成開始 //チャットUI生成 Begin&EndAreaでチャットUIの位置と大きさを設定 GUILayout.Window(0, GuiRect, ChatUIWindow, ""); //チャットUIウインドウを作成 //Enterを押すと if (Event.current.type == EventType.KeyDown && (Event.current.keyCode == KeyCode.KeypadEnter || Event.current.keyCode == KeyCode.Return)) { //チャット入力待ち状態にする GUI.FocusControl("ChatInput"); } } #endregion #region チャットUI生成 void ChatUIWindow(int windowID) { //FocusがチャットUIに乗ってるときにEnterを押すとチャット発言が実行される if (Event.current.type == EventType.KeyDown && (Event.current.keyCode == KeyCode.KeypadEnter || Event.current.keyCode == KeyCode.Return)) { if (!string.IsNullOrEmpty(this.inputLine)) //チャット入力欄がNullやEmptyでない場合 { //範囲チャット送信関数実行 SendChat(false); return; } } //垂直のコントロールグループ開始 GUILayout.BeginVertical(); //スクロールビュー開始位置 scrollPos = GUILayout.BeginScrollView(scrollPos); //チャットログ表示用フレキシブルスペース生成 GUILayout.FlexibleSpace(); //フレキシブルスペースにチャットログを表示 for (int i = 0; i <= messages.Count - 1; i++) { if (chatKind[i] != true) //範囲チャットであれば { GUILayout.Label(messages[i], ChatStyle); } else //全チャットであれば { GUILayout.Label(messages[i], AllChatStyle); } } //スクロールビュー終了 GUILayout.EndScrollView(); //水平のコントロールグループ開始 GUILayout.BeginHorizontal(); //入力テキストフィールド生成、Focusが乗った状態をChatInputと命名 GUI.SetNextControlName("ChatInput"); inputLine = GUILayout.TextField(inputLine, 200); //「Send」ボタンを生成かつ押したときには範囲チャット送信 if (GUILayout.Button("Send", GUILayout.ExpandWidth(false))) { //範囲チャット送信関数実行 SendChat(false); } //Allボタンを生成かつ押したときには全体チャット送信 if (GUILayout.Button("All", GUILayout.ExpandWidth(false))) { //全体チャット送信関数実行 SendChat(true); } //水平のコントロールグループ終了 GUILayout.EndHorizontal(); //垂直のコントロールグループ終了 GUILayout.EndVertical(); } #endregion #region GetmyPlayer 自キャラのオブジェクトをmyPlayerに登録 void GetmyPlayer() { //自キャラのID取得 int myPlayerID = PhotonNetwork.player.ID; //全てのプレイヤーオブジェクトを取得 players = GameObject.FindGameObjectsWithTag("Player"); //全てのプレイヤーオブジェクトから自キャラをIDで検索し、取り出す foreach (GameObject player in players) { int playerLoopId = player.GetComponent<PhotonView>().owner.ID; if (playerLoopId == myPlayerID) { //自プレイヤーオブジェクトを取得 myPlayer = player; } } return; } #endregion #region チャット送信関数 void SendChat(bool isAll) { //chatRPC this.photonView.RPC("Chat", PhotonTargets.All, myPlayer.transform.position, this.inputLine, isAll); //送信後、入力欄を空にし、スクロール最下位置に移動 this.inputLine = ""; scrollPos.y = Mathf.Infinity; } #endregion #region ChatRPC RPC呼出側:送信者 RPC受信側:受信者 [PunRPC] public void Chat(Vector3 senderposition, string newLine, bool isAll, PhotonMessageInfo mi) { if (messages.Count >= 100) //チャットログが多くなって来たらログを削除してから受信 { messages.Clear(); //全てのチャットログを削除 chatKind.Clear(); //全てのチャットの種類情報削除 } if (!isAll) //範囲チャとして受信 { //myPlayerとsenderの距離から受信するか判断 if (Vector3.Distance(myPlayer.transform.position, senderposition) < 10) { //chat受信 ReceiveChat(newLine, isAll, mi); } } else if (isAll) //全チャとして受信 { //chat受信 ReceiveChat(newLine, isAll, mi); } //受信したときはスクロール最下位置 scrollPos.y = Mathf.Infinity; } #endregion #region チャット受信関数 void ReceiveChat(string _newLine, bool isAll, PhotonMessageInfo _mi) { //送信者の名前用変数 string senderName = "anonymous"; if (_mi.sender != null) { //送信者の名前があれば if (!string.IsNullOrEmpty(_mi.sender.NickName)) { senderName = _mi.sender.NickName; } else { senderName = "player " + _mi.sender.ID; } } //受信したチャットをログに追加 this.messages.Add(senderName + ": " + _newLine); this.chatKind.Add(isAll); return; } #endregion public void AddLine(string newLine) { this.messages.Add(newLine); } } |
書き換え後のChatUI構造
プログラムソースコードだけではどのようにUI構造を作成しているか分かりにくいかもしれないので以下の画像を使って少し説明します。
赤色で囲んだ部分がチャットUIウインドウの垂直コントロールグループになります。つまりUIの構造要素を順番に縦に並べるグループとなります。
青色で囲んだ部分がチャットログ表示するためのスクロールビューとフレキシブルスペースとなります。ここに受信したチャットの内容が流れます。
黄色で囲んだ部分が水平のコントロールグループでUIの構造要素を順番に横に並べます。ここでは入力フィールドと範囲・全体チャットのボタンを横に並べています。
照らし合わせながら、順番を変えて表示していただくと、より構造がわかると思いますのでやってみてください。
実際に動かしてみましょう
チャットのシステムがうまく機能していることがわかります。
ちなみに白い文字のチャットログが近くにいる人にしか受信されない範囲チャットで、赤文字は同じ部屋にいる全ての人に受信される全体チャットです。
次回予告!!
Chatのシステムは実装できました!!
次回はChatの発言者の頭上に発言内容を表示させるようにします!!
お楽しみに!!