//tips
//PUN Sample scene内オブジェクト自動生成検証
Sampleスクリプトのコールバックpublic override void OnJoinedRoom()メソッドが機能していないので修正する。
そもそも既にマッチングが成立しているのでpublic override void OnJoinedRoom()メソッド自体が不要かと思い、startメソッドの方に下記の生成スクリプトを移動させてみる。
// マッチング後、ランダムな位置に自分自身のネットワークオブジェクトを生成する
var v = new Vector3(Random.Range(-3f, 3f), Random.Range(-3f, 3f));
PhotonNetwork.Instantiate("GamePlayer", v, Quaternion.identity);
// 現在のサーバー時刻を、ゲームの開始時刻に設定する
if (PhotonNetwork.IsMasterClient && !PhotonNetwork.CurrentRoom.HasStartTime())
{
PhotonNetwork.CurrentRoom.SetStartTime(PhotonNetwork.ServerTimestamp);
}
これにより一つのエラーと一つの警告が現れた。
警告:
ConnectUsingSettings() failed. Can only connect while in state 'Disconnected'. Current state: Connected
UnityEngine.Debug:LogWarning(Object)
Photon.Pun.PhotonNetwork:ConnectUsingSettings(AppSettings, Boolean) (at Assets/Photon/PhotonUnityNetworking/Code/PhotonNetwork.cs:1081)
Photon.Pun.PhotonNetwork:ConnectUsingSettings() (at Assets/Photon/PhotonUnityNetworking/Code/PhotonNetwork.cs:1074)
SampleScene:Start() (at Assets/Script/SampleScene.cs:11)
これは既にPhotonNetwork.ConnectUsingSettings();で接続済みなので再度接続処理は不要というもの。
エラー:
Can not Instantiate before the client joined/created a room. State: Joining
UnityEngine.Debug:LogError(Object)
Photon.Pun.PhotonNetwork:Instantiate(String, Vector3, Quaternion, Byte, Object[]) (at Assets/Photon/PhotonUnityNetworking/Code/PhotonNetwork.cs:2349)
SampleScene:Start() (at Assets/Script/SampleScene.cs:19)
join状態をPhotonNetwork.IsMessageQueueRunningでfalseにしているのでそちらをtrueにする。
NetworkManagerのスクリプトからPhotonNetwork.IsMessageQueueRunning = false;部分を削除したがやはりエラー。
クライアントがjoinする前に生成できないとあり、自身のjoinがうまく感知されていないか、人数が揃って初めてjoin状態に移行する設定にしているかの要因が考えられる。
人数が揃ってjoin状態に移行するスクリプトは書いていないので、joinする際のメソッドに指定しているPhotonNetwork.JoinOrCreateRoom(roomName, roomOptions, TypedLobby.Default);部分に問題がありそう。
roomNameを"Sample”に変更し、再度トライするも失敗。
だがコンソールを見ると、sample sceneのOnJoinedRoom()のメソッドが呼ばれていることがわかった。
"Sample”を設定が今まで不十分であったのでOnJoinedRoom()が呼ばれなかったと考えると、自動生成がエラーとなるのはjoinの許可より前に生成を行おうとしているからだろうので、再度自動生成のスクリプトをOnJoinedRoom()メソッド内に戻してみる。
これにより無事自動生成ができるようになった。
これで既存に存在する部屋に入ることは可能になったので、新しい部屋の名前を決めて生成する方法も考えていく。
まずは、プレイヤーのキーボードの入力を受け取り、UI表示できる仕組みを確認する。
編集可能な Text を作成するInputFieldを利用していく。Create→UI→InputFieldでcanvas下に簡単に作成できる。
ただ、現状況では記入してエンターを押しても何も反映されないので、入力されたテキストをスクリプトを利用して受け取っていく。
string name = inputField.text;で入力テキストを取得してコンソールに出力、その後に初期化を行っている。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class InputFieldManager : MonoBehaviour
{
//InputFieldを格納するための変数
InputField inputField;
// Start is called before the first frame update
void Start()
{
//InputFieldコンポーネントを取得
inputField = GameObject.Find("InputField").GetComponent<InputField>();
}
//入力された名前情報を読み取ってコンソールに出力する関数
public void GetInputName()
{
//InputFieldからテキスト情報を取得する
string name = inputField.text;
Debug.Log(name);
//入力フォームのテキストを空にする
inputField.text = "";
}
}
このGetInputName関数をInputFieldのOnEndEditに登録することでテキストを取得することが可能となる。
On Value ChangeにセットしたらInputFieldの内容が変更された時に呼び出され、End EditにセットしたらInputField外をクリックしたり、エンターボタンを押した時に呼び出される。
PlaceholderはInputFieldの後ろにうっすらと見える文字のこと。
コンソールではなく画面上に文字データを出力したい場合は下記のようにUI textを別途作成し、そちらと紐付けることで対応できる。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class InputFieldManager : MonoBehaviour
{
//InputFieldを格納するための変数
InputField inputField;
// テキストを格納する変数
public Text text;
// Start is called before the first frame update
void Start()
{
//InputFieldコンポーネントを取得
inputField = GameObject.Find("InputField").GetComponent<InputField>();
}
//入力された名前情報を読み取ってコンソールに出力する関数
public void GetInputName()
{
// テキストに入力内容を表示
text.GetComponent<Text>().text = inputField.text;
//入力フォームのテキストを空にする
//inputField.text = "";
}
}
初期時点では日本語入力できないので、input fieldのインスペクターのLine TypeをMultiLineNewlineに変更する。
MultiLineNewlineにするとエンターが改行と認識されてしまうので、on end editからon value changedにinput fieldの文字入力の認識方法を変える。
さらにon value changedの際に改行の認識をさせないようにinput fieldにvalue.IndexOf("\n") != -1のスクリプトをアタッチする。
下記にすると日本語もきちんと表示できるようになる。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class InputFieldManager : MonoBehaviour
{
//InputFieldを格納するための変数
InputField inputField;
// テキストを格納する変数
public Text text;
// Start is called before the first frame update
void Start()
{
//InputFieldコンポーネントを取得
inputField = GameObject.Find("InputField").GetComponent<InputField>();
}
//入力された名前情報を読み取ってコンソールに出力する関数
public void GetInputName()
{
string value = inputField.text;
if (value.IndexOf("\n") != -1)
{
// テキストに入力内容を表示
text.GetComponent<Text>().text = inputField.text;
//入力フォームのテキストを空にする
//inputField.text = "";
// 入力できないようにする
inputField.interactable = false;
}
}
}
部屋の名前なので一度つけたら変更できないようにするinputField.interactable = false;も追加した。
部屋名の入力と同時にその名前の記載された新たなボタンの作成方法を考える。
一旦canvasとbutton一式をprefab化し、resourcesフォルダに配置する。
ここからResoucesを使用したprefabの動的生成のスクリプトを書いていく。まずは空オブジェクトに下記のスクリプトをアタッチし、prefabが生成できているかを確認。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TestManager : MonoBehaviour
{
// 初期化
void Start()
{
GameObject obj = (GameObject)Resources.Load("Canvasname");
// プレハブを元にオブジェクトを生成する
GameObject instance = (GameObject)Instantiate(obj,
new Vector3(3.0f, 0.0f, 0.0f),
Quaternion.identity);
}
}