どーも、siroponnです。
久しぶりに投稿かな。
今回は、前回書いたphotonでのシーン切り替えの続きみたいなものです。
前回photonでRoomシーン(Photonのルームとは違います)からGameシーンに遷移した部分で終わりました。今度はGameシーンからRoomシーンに行く部分を書こうと思います。
Roomシーンに行くのは簡単で、前回とは逆に実装します。
今回はゲームオーバになったとしましょう。
こんな感じかな?
//----------Gameシーンの方にあるスクリプト抜粋--------------------
//ゲームオーバになったら.
if (PhotonNetwork.player.isMasterClient && (localWaitTime >= 4f) && (!isOver) )
{
isOver = true;
PhotonNetwork.room.open = false;
PhotonNetwork.room.visible = false;
ExitGames.Client.Photon.Hashtable h = new ExitGames.Client.Photon.Hashtable() { { "GS", GameState.Progress } };
PhotonNetwork.player.SetCustomProperties(h);
ExitGames.Client.Photon.Hashtable hh = new ExitGames.Client.Photon.Hashtable() { { "BS", "Ending" } };
PhotonNetwork.room.SetCustomProperties(hh);
PhotonNetwork.DestroyAll();
pPview.RPC("ReturnToRoom", PhotonTargets.All);
}
ルームを閉じて、視えなくして、プレイヤ、ルームのプロパティ変更してphotonで生成したobject全部ぶっ壊してます。
PhotonNetowrk.DestroyAll();はやらないと、Buffer上(?)にobject情報が残るっぽいです。
やらずに、他のunityのシーンでこれを呼ぶと怒られます。
話は戻って、Gameシーン上からRoomシーンに戻ってきたら現在Photonに繋がっていてルームの中に存在するかを判定。
//----------Roomシーンにある方のスクリプト抜粋----------
void Start()
{
PhotonNetwork.isMessageQueueRunning = true;
if (PhotonNetwork.connected && PhotonNetwork.inRoom) //Gameからかえってきたら.
{
ExitGames.Client.Photon.Hashtable h = new HashTable() { { "GS", GameState.Room } };
PhotonNetwork.player.SetCustomProperties(h); //自分のプロパティを戻す.
if (PhotonNetwork.player.isMasterClient)
{
PhotonNetwork.room.open = true;
PhotonNetwork.room.visible = true;
ExitGames.Client.Photon.Hashtable hh = new HashTable() { { "BS", "idle" } };
PhotonNetwork.room.SetCustomProperties(hh); //準備中に戻す
}
sceneState = SceneState.Room;
}
else //起動時のみ.
sceneState = SceneState.Title;
}
//------------------------
sceneStateは独自で定義した列挙型です。これで、RoomシーンでもLobyに居るかRoomにいるか、はたまたまだ接続してすらいないかを判定しています。
GameシーンからRoomシーンに戻ってくるのでStartがもう一回呼び出されますね。
このやり方は1シーンだけでやってる時は出来ません。注意してください。
はい、後は特別お話することもありません。
お疲れさまでした。
今度は1シーンだけでやる方法も書きたいな。
untiyやphotonCloud、プログラム全般。あとは2Dイラストやblenderについても書きたいと思う。後、UE4.本業がプログラムなのでほぼそれになりそうです。 基本的にこのブログに書いてあるソースコードは「プログラミングが目的」であるのであればPublic domainです。使用者が全責任を持ってもらえるのであれば、自由に改変、営利目的での使用をしていただいて構いません。ブログに転載や引用等はこのブログのURLを明記してください。
2014年11月18日火曜日
2014年10月13日月曜日
Application.persistentDataPathでエラーが出る
おーすsiroponnです。
今回はApplication.persistentDataPathでエラーが出る件についてです。
先日Application.persistentDataPathにWWWクラスでアクセスしたらこんなエラーを取得しました。
java.net.MalformedURLException; protocol not found;
/data/data/com.hoge.hoge2/files/hoge3.txt
てな感じです.hogeは適当な値です。
どうやら、WWWではApplication.persistentDataPathにはアクセス出来ないみたいです。
もしかしたら出来るのかもしれませんが、僕は出来ませんでした。
ただ、FileクラスやFileStreamではアクセスできるみたいなのでそちらを使えばよいみたいです。
その場合は非同期の方がいいですよね。めんど。
まぁ、C#5.0(.NetFramework4.5?)になってからasync:awaitなる、非同期を楽に記述できるものがあるから結構楽にできるっぽい?
ただ、僕の家のeditorだと対応していない。2010のVSだからか。それとも.NetFramework4.5が入っていないからか。ただ、有料版で結構使いやすいから手放せない。
まぁそんなことはどうでもいいか。とりあえず、みなさんはお気をつけてください。これで1~2時間無駄にしましたので。
Poka!
今回はApplication.persistentDataPathでエラーが出る件についてです。
先日Application.persistentDataPathにWWWクラスでアクセスしたらこんなエラーを取得しました。
java.net.MalformedURLException; protocol not found;
/data/data/com.hoge.hoge2/files/hoge3.txt
てな感じです.hogeは適当な値です。
どうやら、WWWではApplication.persistentDataPathにはアクセス出来ないみたいです。
もしかしたら出来るのかもしれませんが、僕は出来ませんでした。
ただ、FileクラスやFileStreamではアクセスできるみたいなのでそちらを使えばよいみたいです。
その場合は非同期の方がいいですよね。めんど。
まぁ、C#5.0(.NetFramework4.5?)になってからasync:awaitなる、非同期を楽に記述できるものがあるから結構楽にできるっぽい?
ただ、僕の家のeditorだと対応していない。2010のVSだからか。それとも.NetFramework4.5が入っていないからか。ただ、有料版で結構使いやすいから手放せない。
まぁそんなことはどうでもいいか。とりあえず、みなさんはお気をつけてください。これで1~2時間無駄にしましたので。
Poka!
2014年10月6日月曜日
シーンにオブジェクトを残したい時
おひさです。siroponnです。
PUNでシーンにオブジェクトを残したい時についてです。
PhotonNetwork.Instantiate(略)だと、そのObjectを生成したプレイヤーが抜けた時、消えてしまいます。
そういう時はPhotonNetwork.InstantiateSceneObjectメソッドを使いましょう。
これで生成されたオブジェクトはownerIDが0になり、sceneが所有していることになります。
ただ、このメソッドを呼べるのはMasterClientのみっぽいです。
フィールドで全てのキャラが共通で使うものに使えそうです。
あとはPhotonNetwork.autoCleanUpPlayerObjectsを変えることで同じことができそうかも。
僕の方でも検証してみますが、 興味を持ったら検証してみてください。
じゃ、また今度。
PUNでシーンにオブジェクトを残したい時についてです。
PhotonNetwork.Instantiate(略)だと、そのObjectを生成したプレイヤーが抜けた時、消えてしまいます。
そういう時はPhotonNetwork.InstantiateSceneObjectメソッドを使いましょう。
これで生成されたオブジェクトはownerIDが0になり、sceneが所有していることになります。
ただ、このメソッドを呼べるのはMasterClientのみっぽいです。
フィールドで全てのキャラが共通で使うものに使えそうです。
あとはPhotonNetwork.autoCleanUpPlayerObjectsを変えることで同じことができそうかも。
僕の方でも検証してみますが、 興味を持ったら検証してみてください。
じゃ、また今度。
2014年8月21日木曜日
photoncloudを使ったシーン切り替えについて
あついーあついーよ、どうもsiroponnです。
今回はシーンの切り替えについてです。
オンラインゲームのFPSとかみたいに、まずはある程度プレイヤーがルームに集まってから、ゲーム を開始したい場合どうすればいいのだろうと流れを考えてコードを組んでみました。
・スタート時のシーンをロード。
・ConnectUsingSettingsで繋ぐ。
・ルームを探す。
・ルームに接続。
・ある程度プレイヤーが集まったらゲームプレイ用のシーンをロード。
・途中参加OK。
こんな感じですかね。
で、実際のコードですが。
ルームに接続の部分ですが、ルームが作られていない場合ルームを作らなきゃなりません。
このとき、ルームのカスタムプロパティを設定してあげます。後々にこのカスタムプロパティは使います。
RoomOptions ro = new RoomOptions();
ro.maxPlayers = playerMaxCount +1;
ro.isOpen = true;
ro.isVisible = true;
string[] s = { "BS" }; //BS:BattleState.
ro.customRoomPropertiesForLobby = s; //ロビーで表示される値.
ro.customRoomProperties = new ExitGames.Client.Photon.Hashtable() { { "BS","idle" } };
PhotonNetwork.CreateRoom(RoomName, ro, TypedLobby.Default);
sceneState = SceneState.Room;
ルームに入った後呼ばれるこのコールバックでプレイヤーのカスタムプロパティを設定してあげます。後々使います。
void OnJoinedRoom()
{
HashTable h = new HashTable() { { "GS", GameState.Room } }; //playerのカスタムプロパティ.
//ルームプロパティとは違います.
PhotonNetwork.player.SetCustomProperties(h);
RoomInfo r = PhotonNetwork.room;
//ゲームプレイ中に入ったら一時的にイベントをシャットアウト.
//そうしないと、Roomに入った瞬間インスタンス情報が流れてきてしまう.
if ((string)r.customProperties["BS"] != "idle")
{
PhotonNetwork.isMessageQueueRunning = false;
Application.LoadLevel(1);
}
}
で、ルームを作るor接続したらキリのいいタイミングでゲームプレイ用のシーンをロードします。
シーンのロードはマスタークライアントがRPCをコールしてあげます。
if (PhotonNetwork.inRoom && PhotonNetwork.isMasterClient)
{
if (GUI.Button(new Rect(100, 100, 100, 100), "GameStart"))
{
PhotonNetwork.room.open = false; //エラーが起きたら困るので一回ここでルームを閉じる.
HashTable h = new HashTable() { { "BS", "Standing" } }; //ルームのステータスを変更.スタートアップ中.
PhotonNetwork.room.SetCustomProperties(h);
sceneState = SceneState.ChildsGamePlay;//現在意味をなしていない.
//room情報をセットし終わったらリモートクライアントにシーンを呼ばせる.
PhotonNetwork.DestroyAll();
SendGameStart();
}
}
void SendGameStart()
{
pView.RPC("SendGameStartRPC", PhotonTargets.All);
}
[RPC]
void SendGameStartRPC()
{
//メッセージを一時的に遮断.
PhotonNetwork.isMessageQueueRunning = false;
Application.LoadLevel(1);
}
シーンを変更する際にはこれを呼ばないとエラーが起きます。
PhotonNetwork.DestroyAll();
また上のソースコードにも書かれていますが、こいつを必ずシーンを移行する前にfalseにしてください。そうしないと、別シーン上のイベントが受信してまったり、別シーン上にイベントを送信してしまうことになります。
PhotonNetwork.isMessageQueueRunning
次はゲームプレイ用シーンでやることです。
void Start () {
PhotonNetwork.isMessageQueueRunning = true; //ゲームプレイ用のシーンが読み込まれたら必ずtrueにする!
//-------------Playerがゲーム中だとする------
HashTable h = new HashTable() { { "GS", GameState.Play } }; //ルームプロパティじゃないです!
PhotonNetwork.player.SetCustomProperties(h);
//--------------------------------------
if ((string)PhotonNetwork.room.customProperties["BS"] != "Play")
{
phaze = Phase.Prepare;
}
else //途中参加
{
phaze = Phase.Instance;
}
}
まずはシーン移行する前にfalseにしたPhotonNetwork.isMessageQueueRunningを再びtrueにしてください。これで再びイベントを送受信できるようになりました。
ここでルームプロパティを使います。まだゲームが開始されているか?それともされていないかを判断します。
判断したらマスタークライアント以外のプレイヤーがちゃんと、このシーンをロードしたか確認します。(エラー処理していない)
case Phase.Prepare:
if (PhotonNetwork.player.isMasterClient)
{
int count = 0;
int otherPlayers = PhotonNetwork.otherPlayers.Length;
if (otherPlayers != 0)
{
foreach (PhotonPlayer pp in PhotonNetwork.otherPlayers)
{
if ((GameState)pp.customProperties["GS"] == GameState.Play)
count++;
}
}
//他プレイヤーの準備が整っていればプレイヤー逹をインスタンスし始める.
if (count == otherPlayers)
{
pView.RPC("SetPhazeRPC", PhotonTargets.All, (int)Phase.Instance);
}
}
break;
ここでプレイヤーのカスタムプロパティを使いますね。こうすれば、まだリモートクライアントがこのシーン上にいなくても判定を行うことができます。
次にインスタンスです。自分としてはここでプレイヤーのインスタンスをすると思っていましたが、背景のロードを行ってもかまいません。しかし、今掲載しているコードにはありませんが、背景はシーンに入った直後非同期で行うことを推奨します。nowlowdingとか表示しながら。
case Phase.Instance:
TestInstance();
//MCだけルームの状態を変更させる.
if (PhotonNetwork.isMasterClient)
{
HashTable hh = new HashTable { { "BS", "Play" } };
PhotonNetwork.room.SetCustomProperties(hh);
PhotonNetwork.room.open = true; //Start時に閉めておいたのオープンにさせる.
}
phaze = Phase.Play; //インスタンスしたら各々プレイ状態にはいる.
break;
さて↑の部分でルームのプロパティ"BS"を"Play"状態にしました。
先ほど書いたOnJoinedRoom()の一部分を見てみます。
//ゲームプレイ中に入ったら一時的にイベントをシャットアウト.
//そうしないと、Roomに入った瞬間インスタンス情報が流れてきてしまう.
if ((string)r.customProperties["BS"] != "idle")
{
PhotonNetwork.isMessageQueueRunning = false;
Application.LoadLevel(1);
}
こうすることによって他の、まだルームに入っていないプレイヤーが入ってきた時、問題なくゲームを始められるようになります。
また、ルームにバッファリングされたイベントはOnJoinedRoomが呼ばれた後に呼ばれるっぽいのでここでPhotonNetwork.isMessageQueueRunningをfalseにしておけばゲームプレイ用のシーンに入った時にイベントが受信できるようになるわけです。
そして、Start()の部分をもう一回。
if ((string)PhotonNetwork.room.customProperties["BS"] != "Play")
{
phaze = Phase.Prepare;
}
else //途中参加
{
phaze = Phase.Instance;
}
"BS"を"Play"にしたので途中から入ってきた人はprepareを飛ばしてインスタンスできるようになります。
インスタンス後はみなさんかなり独自実装になると思うので省きました。というか自分が書くスピードが遅いので止めました。
でも、インスタンスするときにPhotonNetowork.Instantiateを使わない方法でやると(マニュアルでインスタンスとviewIDをつけるやつの)バグるのは解決したい。あとはルームに入れなかった時とか、ルームから退出したときとか、ルームでマスタークライアントが変わった時とかその辺の処理もいずれかは解決したいと思います。
後々にちゃんとした加筆修正をしたいなぁ。いつになるかは分からんが。
さて長々と書きました。はっきり言って説明されるより、コードを見ながら自分で覚えた方が早いと思うので以下に使ったコードを書きます。
無駄な表記(使わないコードなど)あるのでC#対応のテキストエディタにコピペした後、見てもらえばコメント部分が色わけされていいかもしれません。
駄コードですが、参考になれば幸いです。
では、siroponnでした!
以下,コード。
ゲームを始めた時に呼ばれるシーンでのスクリプト
//---------------.----------------
using UnityEngine;
using System.Collections;
using HashTable = ExitGames.Client.Photon.Hashtable;
using System.Collections.Generic;
enum SceneState : int {
Title = 0,
select = 1,
Loby = 2,
Room = 3,
ChildsGamePlay = 4,
HostGamePlay = 5,
}
public enum GameState : int //今プレイヤーがどの状態にあるか?
{
Room = 0,
Play = 1,
}
public class StartScene : MonoBehaviour {
float ConnectTime = 0.0f;
int selectGrid;
SceneState sceneState;
string RoomName = "PressRoomName";
int playerMaxCount = 0;
string[] playerCount ={ "1", "2", "3", "4" };
PhotonView pView;
int playerCnt = 0;
List<PhotonPlayer> pList = new List<PhotonPlayer>();
void Awake()
{
pView = this.GetComponent<PhotonView>();
//PhotonNetwork.isMessageQueueRunning = false;
}
// Use this for initialization
void Start () {
sceneState = SceneState.Title;
}
// Update is called once per frame
void Update () {
if (ConnectTime >= 0.1f)
{
ConnectTime += Time.deltaTime;
if (PhotonNetwork.connectionStateDetailed == PeerState.JoinedLobby)
{
ConnectTime = 0f;
sceneState = SceneState.Loby;
}
}
if (Input.GetKey(KeyCode.A))
{
Debug.Log(PhotonNetwork.isMessageQueueRunning);
}
}
void OnGUI()
{
int sw = Screen.width;
int sh = Screen.height;
switch (sceneState)
{
case SceneState.Title: //接続するまで
if (GUI.Button(new Rect(sw / 2f, sh / 2f, 30f, 30f), "接続"))
{
PhotonNetwork.ConnectUsingSettings("v1.0");
ConnectTime = 0.1f;
}
if (ConnectTime >= 0.1f && PhotonNetwork.connectionStateDetailed != PeerState.JoinedLobby)
{
GUILayout.Label("接続中");
}
break;
case SceneState.Loby://接続後.
RoomName = GUI.TextField(new Rect(100, 100, 150, 20), RoomName, 16);
GUI.Label(new Rect(100f, 170f, 50f, 50f), "Player数");
playerMaxCount = GUI.SelectionGrid(new Rect(100, 200, 100, 20), playerMaxCount,playerCount,4);
if (GUILayout.Button("createroom"))
{
RoomOptions ro = new RoomOptions();
ro.maxPlayers = playerMaxCount +1;
ro.isOpen = true;
ro.isVisible = true;
string[] s = { "BS" }; //BS:BattleState.
ro.customRoomPropertiesForLobby = s; //ロビーで表示される値.
ro.customRoomProperties = new ExitGames.Client.Photon.Hashtable() { { "BS","idle" } };
PhotonNetwork.CreateRoom(RoomName, ro, TypedLobby.Default);
sceneState = SceneState.Room;
}
if (PhotonNetwork.countOfRooms == 0)
return;
foreach (RoomInfo game in PhotonNetwork.GetRoomList())
{
GUI.Label(new Rect(sw/2f,(sh*2/3),500,30),game.name + " " + game.playerCount + "/" + game.maxPlayers + "/" + game.customProperties["BS"]);
if (GUILayout.Button("JOIN"))
{
PhotonNetwork.JoinRoom(game.name);
sceneState = SceneState.Room;
}
}
break;
case SceneState.Room://ルームに入った後.
if (PhotonNetwork.inRoom && PhotonNetwork.isMasterClient)
{
if (GUI.Button(new Rect(100, 100, 100, 100), "GameStart"))
{
PhotonNetwork.room.open = false; //エラーが起きたら困るので一回ここでルームを閉じる.
HashTable h = new HashTable() { { "BS", "Standing" } }; //ルームのステータスを変更.スタートアップ中.
PhotonNetwork.room.SetCustomProperties(h);
sceneState = SceneState.ChildsGamePlay;//現在意味をなしていない.
//room情報をセットし終わったらリモートクライアントにシーンを呼ばせる.
PhotonNetwork.DestroyAll();
SendGameStart();
}
}
if (GUILayout.Button("testInstance"))
PhotonNetwork.Instantiate("TestInstance", Vector3.zero, Quaternion.identity, 0);
break;
/* case SceneState.ChildsGamePlay:
int cnt = 0;
//マスタークライアント以外のローカルクライアントがしっかりシーンを読み終わったかを調べる.
foreach (PhotonPlayer pp in PhotonNetwork.otherPlayers)
{
if ((int)pp.customProperties["GS"] == (int)GameState.Play)
{
cnt++;
}
}
if (cnt == PhotonNetwork.otherPlayers.Length)
sceneState = SceneState.HostGamePlay;
break;
case SceneState.HostGamePlay:
Debug.Log("MC以外の準備完了");
PhotonNetwork.isMessageQueueRunning = false;
Application.LoadLevel(1);
break;*/
}
GUILayout.Label(PhotonNetwork.connectionStateDetailed.ToString());
GUILayout.Label(ConnectTime.ToString());
GUILayout.Label(PhotonNetwork.connectionState.ToString());
}
void SendGameStart()
{
pView.RPC("SendGameStartRPC", PhotonTargets.All);
}
[RPC]
void SendGameStartRPC()
{
//メッセージを一時的に遮断.
PhotonNetwork.isMessageQueueRunning = false;
Application.LoadLevel(1);
}
//ルームに入った時呼ばれる.
void OnJoinedRoom()
{
//プレイヤーがバトル用のシーンを読み込んだかチェック.
HashTable h = new HashTable() { { "GS", GameState.Room } }; //playerのカスタムプロパティ.
//ルームプロパティとは違います.
PhotonNetwork.player.SetCustomProperties(h);
RoomInfo r = PhotonNetwork.room;
//ゲームプレイ中に入ったら一時的にイベントをシャットアウト.
//そうしないと、Roomに入った瞬間インスタンス情報が流れてきてしまう.
if ((string)r.customProperties["BS"] != "idle")
{
PhotonNetwork.isMessageQueueRunning = false;
Application.LoadLevel(1);
}
}
void OnPhotonJoinRoomFailed()
{
//ルームに入れなかった場合
sceneState = SceneState.Loby;
}
}
//------------------------------------------------------------------
ゲームプレイ用のシーンに入った後に呼ばれるスクリプト
//---------------------------------------------------------
using UnityEngine;
using System.Collections;
using HashTable = ExitGames.Client.Photon.Hashtable;
enum Phase:int
{
Prepare = 0,
Instance = 1,
Play = 2,
GameOver = 3,
None = 4,
};
public class TestGameMain : MonoBehaviour {
PhotonView pView;
public GameObject g;
Phase phaze = Phase.None;
void Awake()
{
pView = GetComponent<PhotonView>();
}
// Use this for initialization
void Start () {
PhotonNetwork.isMessageQueueRunning = true; //ゲームプレイ用のシーンが読み込まれたら必ずtrueにする!
//-------------Playerがゲーム中だとする------
HashTable h = new HashTable() { { "GS", GameState.Play } };
PhotonNetwork.player.SetCustomProperties(h);
//--------------------------------------
if ((string)PhotonNetwork.room.customProperties["BS"] != "Play")
{
phaze = Phase.Prepare;
}
else //途中参加
{
phaze = Phase.Instance;
}
}
// Update is called once per frame
void Update () {
if (Input.GetKeyDown(KeyCode.Q))
Debug.Log(PhotonNetwork.player.ID);
switch (phaze)
{
case Phase.Prepare:
if (PhotonNetwork.player.isMasterClient)
{
int count = 0;
int otherPlayers = PhotonNetwork.otherPlayers.Length;
if (otherPlayers != 0)
{
foreach (PhotonPlayer pp in PhotonNetwork.otherPlayers)
{
if ((GameState)pp.customProperties["GS"] == GameState.Play)
count++;
}
}
//他プレイヤーの準備が整っていれば始める.
if (count == otherPlayers)
{
//MC用のキャラインスタンス通知,
/*TestInstance(); //親
//他プレイヤーに自分のキャラインスタンスを通知.
if (otherPlayers != 0)
{
pView.RPC("SendTestInstanceRPC", PhotonTargets.OthersBuffered);
}*/
pView.RPC("SetPhazeRPC", PhotonTargets.All, (int)Phase.Instance);
}
}
break;
case Phase.Instance:
TestInstance();
//MCだけルームの状態を変更させる.
if (PhotonNetwork.isMasterClient)
{
HashTable hh = new HashTable { { "BS", "Play" } };
PhotonNetwork.room.SetCustomProperties(hh);
PhotonNetwork.room.open = true; //Start時に閉めておいたのオープンにさせる.
}
phaze = Phase.Play; //インスタンスしたら各々プレイ状態にはいる.
break;
case Phase.Play:
break;
case Phase.GameOver:
break;
case Phase.None:
break;
}
}
void OnGUI()
{
string s = "";
if(PhotonNetwork.player.isMasterClient)
s = "MCです";
else
s = "MCではありません";
GUILayout.Label("私は" + s);
}
void TestInstance() //モデルをマニュアルでインスタンス.
{
//int id1 = PhotonNetwork.AllocateViewID();
//pView.RPC("TestInstanceRPC",PhotonTargets.AllBuffered,id1,PhotonNetwork.player);
PhotonNetwork.Instantiate("TestInstance", Vector3.zero, Quaternion.identity, 0);
}
[RPC]
void SetPhazeRPC(int phaze)
{
this.phaze = (Phase)phaze;
}
//以降下のコードバグあり。コメント化。
/*[RPC]
void TestInstanceRPC(int vid,PhotonPlayer pp)
{
GameObject go = (GameObject)GameObject.Instantiate(g, Vector3.zero, Quaternion.identity);
PhotonView p = go.GetComponent<PhotonView>();
p.viewID = vid;
p.ownerId = pp.ID;
}
[RPC]
void SendTestInstanceRPC()
{
TestInstance();
}*/
}
//--------------------------------------------------------------------
今回はシーンの切り替えについてです。
オンラインゲームのFPSとかみたいに、まずはある程度プレイヤーがルームに集まってから、ゲーム を開始したい場合どうすればいいのだろうと流れを考えてコードを組んでみました。
・スタート時のシーンをロード。
・ConnectUsingSettingsで繋ぐ。
・ルームを探す。
・ルームに接続。
・ある程度プレイヤーが集まったらゲームプレイ用のシーンをロード。
・途中参加OK。
こんな感じですかね。
で、実際のコードですが。
ルームに接続の部分ですが、ルームが作られていない場合ルームを作らなきゃなりません。
このとき、ルームのカスタムプロパティを設定してあげます。後々にこのカスタムプロパティは使います。
RoomOptions ro = new RoomOptions();
ro.maxPlayers = playerMaxCount +1;
ro.isOpen = true;
ro.isVisible = true;
string[] s = { "BS" }; //BS:BattleState.
ro.customRoomPropertiesForLobby = s; //ロビーで表示される値.
ro.customRoomProperties = new ExitGames.Client.Photon.Hashtable() { { "BS","idle" } };
PhotonNetwork.CreateRoom(RoomName, ro, TypedLobby.Default);
sceneState = SceneState.Room;
ルームに入った後呼ばれるこのコールバックでプレイヤーのカスタムプロパティを設定してあげます。後々使います。
void OnJoinedRoom()
{
HashTable h = new HashTable() { { "GS", GameState.Room } }; //playerのカスタムプロパティ.
//ルームプロパティとは違います.
PhotonNetwork.player.SetCustomProperties(h);
RoomInfo r = PhotonNetwork.room;
//ゲームプレイ中に入ったら一時的にイベントをシャットアウト.
//そうしないと、Roomに入った瞬間インスタンス情報が流れてきてしまう.
if ((string)r.customProperties["BS"] != "idle")
{
PhotonNetwork.isMessageQueueRunning = false;
Application.LoadLevel(1);
}
}
で、ルームを作るor接続したらキリのいいタイミングでゲームプレイ用のシーンをロードします。
シーンのロードはマスタークライアントがRPCをコールしてあげます。
if (PhotonNetwork.inRoom && PhotonNetwork.isMasterClient)
{
if (GUI.Button(new Rect(100, 100, 100, 100), "GameStart"))
{
PhotonNetwork.room.open = false; //エラーが起きたら困るので一回ここでルームを閉じる.
HashTable h = new HashTable() { { "BS", "Standing" } }; //ルームのステータスを変更.スタートアップ中.
PhotonNetwork.room.SetCustomProperties(h);
sceneState = SceneState.ChildsGamePlay;//現在意味をなしていない.
//room情報をセットし終わったらリモートクライアントにシーンを呼ばせる.
PhotonNetwork.DestroyAll();
SendGameStart();
}
}
void SendGameStart()
{
pView.RPC("SendGameStartRPC", PhotonTargets.All);
}
[RPC]
void SendGameStartRPC()
{
//メッセージを一時的に遮断.
PhotonNetwork.isMessageQueueRunning = false;
Application.LoadLevel(1);
}
シーンを変更する際にはこれを呼ばないとエラーが起きます。
PhotonNetwork.DestroyAll();
また上のソースコードにも書かれていますが、こいつを必ずシーンを移行する前にfalseにしてください。そうしないと、別シーン上のイベントが受信してまったり、別シーン上にイベントを送信してしまうことになります。
PhotonNetwork.isMessageQueueRunning
次はゲームプレイ用シーンでやることです。
void Start () {
PhotonNetwork.isMessageQueueRunning = true; //ゲームプレイ用のシーンが読み込まれたら必ずtrueにする!
//-------------Playerがゲーム中だとする------
HashTable h = new HashTable() { { "GS", GameState.Play } }; //ルームプロパティじゃないです!
PhotonNetwork.player.SetCustomProperties(h);
//--------------------------------------
if ((string)PhotonNetwork.room.customProperties["BS"] != "Play")
{
phaze = Phase.Prepare;
}
else //途中参加
{
phaze = Phase.Instance;
}
}
まずはシーン移行する前にfalseにしたPhotonNetwork.isMessageQueueRunningを再びtrueにしてください。これで再びイベントを送受信できるようになりました。
ここでルームプロパティを使います。まだゲームが開始されているか?それともされていないかを判断します。
判断したらマスタークライアント以外のプレイヤーがちゃんと、このシーンをロードしたか確認します。(エラー処理していない)
case Phase.Prepare:
if (PhotonNetwork.player.isMasterClient)
{
int count = 0;
int otherPlayers = PhotonNetwork.otherPlayers.Length;
if (otherPlayers != 0)
{
foreach (PhotonPlayer pp in PhotonNetwork.otherPlayers)
{
if ((GameState)pp.customProperties["GS"] == GameState.Play)
count++;
}
}
//他プレイヤーの準備が整っていればプレイヤー逹をインスタンスし始める.
if (count == otherPlayers)
{
pView.RPC("SetPhazeRPC", PhotonTargets.All, (int)Phase.Instance);
}
}
break;
ここでプレイヤーのカスタムプロパティを使いますね。こうすれば、まだリモートクライアントがこのシーン上にいなくても判定を行うことができます。
次にインスタンスです。自分としてはここでプレイヤーのインスタンスをすると思っていましたが、背景のロードを行ってもかまいません。しかし、今掲載しているコードにはありませんが、背景はシーンに入った直後非同期で行うことを推奨します。nowlowdingとか表示しながら。
case Phase.Instance:
TestInstance();
//MCだけルームの状態を変更させる.
if (PhotonNetwork.isMasterClient)
{
HashTable hh = new HashTable { { "BS", "Play" } };
PhotonNetwork.room.SetCustomProperties(hh);
PhotonNetwork.room.open = true; //Start時に閉めておいたのオープンにさせる.
}
phaze = Phase.Play; //インスタンスしたら各々プレイ状態にはいる.
break;
さて↑の部分でルームのプロパティ"BS"を"Play"状態にしました。
先ほど書いたOnJoinedRoom()の一部分を見てみます。
//ゲームプレイ中に入ったら一時的にイベントをシャットアウト.
//そうしないと、Roomに入った瞬間インスタンス情報が流れてきてしまう.
if ((string)r.customProperties["BS"] != "idle")
{
PhotonNetwork.isMessageQueueRunning = false;
Application.LoadLevel(1);
}
こうすることによって他の、まだルームに入っていないプレイヤーが入ってきた時、問題なくゲームを始められるようになります。
また、ルームにバッファリングされたイベントはOnJoinedRoomが呼ばれた後に呼ばれるっぽいのでここでPhotonNetwork.isMessageQueueRunningをfalseにしておけばゲームプレイ用のシーンに入った時にイベントが受信できるようになるわけです。
そして、Start()の部分をもう一回。
if ((string)PhotonNetwork.room.customProperties["BS"] != "Play")
{
phaze = Phase.Prepare;
}
else //途中参加
{
phaze = Phase.Instance;
}
"BS"を"Play"にしたので途中から入ってきた人はprepareを飛ばしてインスタンスできるようになります。
インスタンス後はみなさんかなり独自実装になると思うので省きました。というか自分が書くスピードが遅いので止めました。
でも、インスタンスするときにPhotonNetowork.Instantiateを使わない方法でやると(マニュアルでインスタンスとviewIDをつけるやつの)バグるのは解決したい。あとはルームに入れなかった時とか、ルームから退出したときとか、ルームでマスタークライアントが変わった時とかその辺の処理もいずれかは解決したいと思います。
後々にちゃんとした加筆修正をしたいなぁ。いつになるかは分からんが。
さて長々と書きました。はっきり言って説明されるより、コードを見ながら自分で覚えた方が早いと思うので以下に使ったコードを書きます。
無駄な表記(使わないコードなど)あるのでC#対応のテキストエディタにコピペした後、見てもらえばコメント部分が色わけされていいかもしれません。
駄コードですが、参考になれば幸いです。
では、siroponnでした!
以下,コード。
ゲームを始めた時に呼ばれるシーンでのスクリプト
//---------------.----------------
using UnityEngine;
using System.Collections;
using HashTable = ExitGames.Client.Photon.Hashtable;
using System.Collections.Generic;
enum SceneState : int {
Title = 0,
select = 1,
Loby = 2,
Room = 3,
ChildsGamePlay = 4,
HostGamePlay = 5,
}
public enum GameState : int //今プレイヤーがどの状態にあるか?
{
Room = 0,
Play = 1,
}
public class StartScene : MonoBehaviour {
float ConnectTime = 0.0f;
int selectGrid;
SceneState sceneState;
string RoomName = "PressRoomName";
int playerMaxCount = 0;
string[] playerCount ={ "1", "2", "3", "4" };
PhotonView pView;
int playerCnt = 0;
List<PhotonPlayer> pList = new List<PhotonPlayer>();
void Awake()
{
pView = this.GetComponent<PhotonView>();
//PhotonNetwork.isMessageQueueRunning = false;
}
// Use this for initialization
void Start () {
sceneState = SceneState.Title;
}
// Update is called once per frame
void Update () {
if (ConnectTime >= 0.1f)
{
ConnectTime += Time.deltaTime;
if (PhotonNetwork.connectionStateDetailed == PeerState.JoinedLobby)
{
ConnectTime = 0f;
sceneState = SceneState.Loby;
}
}
if (Input.GetKey(KeyCode.A))
{
Debug.Log(PhotonNetwork.isMessageQueueRunning);
}
}
void OnGUI()
{
int sw = Screen.width;
int sh = Screen.height;
switch (sceneState)
{
case SceneState.Title: //接続するまで
if (GUI.Button(new Rect(sw / 2f, sh / 2f, 30f, 30f), "接続"))
{
PhotonNetwork.ConnectUsingSettings("v1.0");
ConnectTime = 0.1f;
}
if (ConnectTime >= 0.1f && PhotonNetwork.connectionStateDetailed != PeerState.JoinedLobby)
{
GUILayout.Label("接続中");
}
break;
case SceneState.Loby://接続後.
RoomName = GUI.TextField(new Rect(100, 100, 150, 20), RoomName, 16);
GUI.Label(new Rect(100f, 170f, 50f, 50f), "Player数");
playerMaxCount = GUI.SelectionGrid(new Rect(100, 200, 100, 20), playerMaxCount,playerCount,4);
if (GUILayout.Button("createroom"))
{
RoomOptions ro = new RoomOptions();
ro.maxPlayers = playerMaxCount +1;
ro.isOpen = true;
ro.isVisible = true;
string[] s = { "BS" }; //BS:BattleState.
ro.customRoomPropertiesForLobby = s; //ロビーで表示される値.
ro.customRoomProperties = new ExitGames.Client.Photon.Hashtable() { { "BS","idle" } };
PhotonNetwork.CreateRoom(RoomName, ro, TypedLobby.Default);
sceneState = SceneState.Room;
}
if (PhotonNetwork.countOfRooms == 0)
return;
foreach (RoomInfo game in PhotonNetwork.GetRoomList())
{
GUI.Label(new Rect(sw/2f,(sh*2/3),500,30),game.name + " " + game.playerCount + "/" + game.maxPlayers + "/" + game.customProperties["BS"]);
if (GUILayout.Button("JOIN"))
{
PhotonNetwork.JoinRoom(game.name);
sceneState = SceneState.Room;
}
}
break;
case SceneState.Room://ルームに入った後.
if (PhotonNetwork.inRoom && PhotonNetwork.isMasterClient)
{
if (GUI.Button(new Rect(100, 100, 100, 100), "GameStart"))
{
PhotonNetwork.room.open = false; //エラーが起きたら困るので一回ここでルームを閉じる.
HashTable h = new HashTable() { { "BS", "Standing" } }; //ルームのステータスを変更.スタートアップ中.
PhotonNetwork.room.SetCustomProperties(h);
sceneState = SceneState.ChildsGamePlay;//現在意味をなしていない.
//room情報をセットし終わったらリモートクライアントにシーンを呼ばせる.
PhotonNetwork.DestroyAll();
SendGameStart();
}
}
if (GUILayout.Button("testInstance"))
PhotonNetwork.Instantiate("TestInstance", Vector3.zero, Quaternion.identity, 0);
break;
/* case SceneState.ChildsGamePlay:
int cnt = 0;
//マスタークライアント以外のローカルクライアントがしっかりシーンを読み終わったかを調べる.
foreach (PhotonPlayer pp in PhotonNetwork.otherPlayers)
{
if ((int)pp.customProperties["GS"] == (int)GameState.Play)
{
cnt++;
}
}
if (cnt == PhotonNetwork.otherPlayers.Length)
sceneState = SceneState.HostGamePlay;
break;
case SceneState.HostGamePlay:
Debug.Log("MC以外の準備完了");
PhotonNetwork.isMessageQueueRunning = false;
Application.LoadLevel(1);
break;*/
}
GUILayout.Label(PhotonNetwork.connectionStateDetailed.ToString());
GUILayout.Label(ConnectTime.ToString());
GUILayout.Label(PhotonNetwork.connectionState.ToString());
}
void SendGameStart()
{
pView.RPC("SendGameStartRPC", PhotonTargets.All);
}
[RPC]
void SendGameStartRPC()
{
//メッセージを一時的に遮断.
PhotonNetwork.isMessageQueueRunning = false;
Application.LoadLevel(1);
}
//ルームに入った時呼ばれる.
void OnJoinedRoom()
{
//プレイヤーがバトル用のシーンを読み込んだかチェック.
HashTable h = new HashTable() { { "GS", GameState.Room } }; //playerのカスタムプロパティ.
//ルームプロパティとは違います.
PhotonNetwork.player.SetCustomProperties(h);
RoomInfo r = PhotonNetwork.room;
//ゲームプレイ中に入ったら一時的にイベントをシャットアウト.
//そうしないと、Roomに入った瞬間インスタンス情報が流れてきてしまう.
if ((string)r.customProperties["BS"] != "idle")
{
PhotonNetwork.isMessageQueueRunning = false;
Application.LoadLevel(1);
}
}
void OnPhotonJoinRoomFailed()
{
//ルームに入れなかった場合
sceneState = SceneState.Loby;
}
}
//------------------------------------------------------------------
ゲームプレイ用のシーンに入った後に呼ばれるスクリプト
//---------------------------------------------------------
using UnityEngine;
using System.Collections;
using HashTable = ExitGames.Client.Photon.Hashtable;
enum Phase:int
{
Prepare = 0,
Instance = 1,
Play = 2,
GameOver = 3,
None = 4,
};
public class TestGameMain : MonoBehaviour {
PhotonView pView;
public GameObject g;
Phase phaze = Phase.None;
void Awake()
{
pView = GetComponent<PhotonView>();
}
// Use this for initialization
void Start () {
PhotonNetwork.isMessageQueueRunning = true; //ゲームプレイ用のシーンが読み込まれたら必ずtrueにする!
//-------------Playerがゲーム中だとする------
HashTable h = new HashTable() { { "GS", GameState.Play } };
PhotonNetwork.player.SetCustomProperties(h);
//--------------------------------------
if ((string)PhotonNetwork.room.customProperties["BS"] != "Play")
{
phaze = Phase.Prepare;
}
else //途中参加
{
phaze = Phase.Instance;
}
}
// Update is called once per frame
void Update () {
if (Input.GetKeyDown(KeyCode.Q))
Debug.Log(PhotonNetwork.player.ID);
switch (phaze)
{
case Phase.Prepare:
if (PhotonNetwork.player.isMasterClient)
{
int count = 0;
int otherPlayers = PhotonNetwork.otherPlayers.Length;
if (otherPlayers != 0)
{
foreach (PhotonPlayer pp in PhotonNetwork.otherPlayers)
{
if ((GameState)pp.customProperties["GS"] == GameState.Play)
count++;
}
}
//他プレイヤーの準備が整っていれば始める.
if (count == otherPlayers)
{
//MC用のキャラインスタンス通知,
/*TestInstance(); //親
//他プレイヤーに自分のキャラインスタンスを通知.
if (otherPlayers != 0)
{
pView.RPC("SendTestInstanceRPC", PhotonTargets.OthersBuffered);
}*/
pView.RPC("SetPhazeRPC", PhotonTargets.All, (int)Phase.Instance);
}
}
break;
case Phase.Instance:
TestInstance();
//MCだけルームの状態を変更させる.
if (PhotonNetwork.isMasterClient)
{
HashTable hh = new HashTable { { "BS", "Play" } };
PhotonNetwork.room.SetCustomProperties(hh);
PhotonNetwork.room.open = true; //Start時に閉めておいたのオープンにさせる.
}
phaze = Phase.Play; //インスタンスしたら各々プレイ状態にはいる.
break;
case Phase.Play:
break;
case Phase.GameOver:
break;
case Phase.None:
break;
}
}
void OnGUI()
{
string s = "";
if(PhotonNetwork.player.isMasterClient)
s = "MCです";
else
s = "MCではありません";
GUILayout.Label("私は" + s);
}
void TestInstance() //モデルをマニュアルでインスタンス.
{
//int id1 = PhotonNetwork.AllocateViewID();
//pView.RPC("TestInstanceRPC",PhotonTargets.AllBuffered,id1,PhotonNetwork.player);
PhotonNetwork.Instantiate("TestInstance", Vector3.zero, Quaternion.identity, 0);
}
[RPC]
void SetPhazeRPC(int phaze)
{
this.phaze = (Phase)phaze;
}
//以降下のコードバグあり。コメント化。
/*[RPC]
void TestInstanceRPC(int vid,PhotonPlayer pp)
{
GameObject go = (GameObject)GameObject.Instantiate(g, Vector3.zero, Quaternion.identity);
PhotonView p = go.GetComponent<PhotonView>();
p.viewID = vid;
p.ownerId = pp.ID;
}
[RPC]
void SendTestInstanceRPC()
{
TestInstance();
}*/
}
//--------------------------------------------------------------------
2014年8月6日水曜日
PhotonCloud OnPhotonInstantiateでのエラーについて
おっす、siroponnです。
今回はOnPhotonInstantiateのエラーについてです。
OnPhotonInstantiateはPhotonNetwork.Instantiate により生成された GameObject(とその子オブジェクト)上のすべてのスクリプトでコールされる(公式抜粋)
さて、こういったエラーが出たことありませんか?
↓
TargetParameterCountException: parameters do not match signature.
これは
void OnPhotonInstantiate()
と書いてしまうと、出ます。
ただしくは
void OnPhotonInstantiate(PhotonMessageInfo info)
という風に引数を入れてあげないとダメです。
これは簡単なエラーだったのですぐ見つかりました。
が、びっくりしたので書き記しておきます。
RPCでは引数いらないのにこれは引数いるのはなんでじゃー。って思ったのは秘密。
では凡人siroponnでした~~。ノシシ
次はどうしよう。ネタがないから、うーん。しばらく考えてみます。
追記:08/07 05:34
OnPhotonInstantiateの使い方を書き忘れていました。
public class A : MonoBehaviour{
int TestId;
void Test()
{
object[] obj = new object[1];
int[] id = new int[1];
id[0] = TestId;
obj[0] = (int)id[0];
PhotonNetowork.Instantiate("TestPrefab",this.transform.position,Quaternion.identity,0,obj)
}
}
public class TestPrefabScript : MonoBehaviour{
int catchId;
PhotonView pView;
void Awake()
{
pView = GetComponent<PhotonView>();
}
void OnPhotonInstantiate(PhotonMessageInfo info)
{
this.catchId = (int)this.pView.instantiationData[0];
}
}
PhotonNetwork.Instantiateの時にobject型を送ります。
インスタンスされたオブジェクトに付随するPhotonViewにアクセスする。
するとinstantiationDataにobject型の送られてきた値が入っているのでOnPhotonInstantiateで受け取る。
調べていませんが、別にOnPhotonInstantiateで受け取る必要はないかもしれません。
今回はOnPhotonInstantiateのエラーについてです。
OnPhotonInstantiateはPhotonNetwork.Instantiate により生成された GameObject(とその子オブジェクト)上のすべてのスクリプトでコールされる(公式抜粋)
さて、こういったエラーが出たことありませんか?
↓
TargetParameterCountException: parameters do not match signature.
これは
void OnPhotonInstantiate()
と書いてしまうと、出ます。
ただしくは
void OnPhotonInstantiate(PhotonMessageInfo info)
という風に引数を入れてあげないとダメです。
これは簡単なエラーだったのですぐ見つかりました。
が、びっくりしたので書き記しておきます。
RPCでは引数いらないのにこれは引数いるのはなんでじゃー。って思ったのは秘密。
では凡人siroponnでした~~。ノシシ
次はどうしよう。ネタがないから、うーん。しばらく考えてみます。
追記:08/07 05:34
OnPhotonInstantiateの使い方を書き忘れていました。
public class A : MonoBehaviour{
int TestId;
void Test()
{
object[] obj = new object[1];
int[] id = new int[1];
id[0] = TestId;
obj[0] = (int)id[0];
PhotonNetowork.Instantiate("TestPrefab",this.transform.position,Quaternion.identity,0,obj)
}
}
public class TestPrefabScript : MonoBehaviour{
int catchId;
PhotonView pView;
void Awake()
{
pView = GetComponent<PhotonView>();
}
void OnPhotonInstantiate(PhotonMessageInfo info)
{
this.catchId = (int)this.pView.instantiationData[0];
}
}
PhotonNetwork.Instantiateの時にobject型を送ります。
インスタンスされたオブジェクトに付随するPhotonViewにアクセスする。
するとinstantiationDataにobject型の送られてきた値が入っているのでOnPhotonInstantiateで受け取る。
調べていませんが、別にOnPhotonInstantiateで受け取る必要はないかもしれません。
2014年8月4日月曜日
photoncloud ownerIDについて
にっこにっこにー、siroponnです。ラブライブの曲いいですよね。元気が出ます。
さて、早くも五回目です。そろそろ失速してきそうです。
基本的にgoogle先生にきいて、検索結果1ページで他の人が書いていない情報しか書かない主義ですから。だって1ページ目に出てくるのなんて有名で検索すればすぐ出てくるでしょ?それをわざわざ書くのはめんどいちーん。
で、ownerIDです。
PhotonViewクラスのメンバーです。
こいつはなんぞやというと、読んで字のごとくownerのIDです。
このPhotonViewがついているObjectを、どのプレイヤーが管理しているかちゅーことです。
基本的に、自分が生成した(PhotonNetwork.Instantiateなどで) Objectには自分のIDがつきます。
自分のIDとはPhotonPlayerクラスの"ID"メンバーで得られる値です。
で、このownerIDはアクセスレベルがpublicなので書きかえられます。
自分が生成していないObjectを自分の管理化に置きたい場合、このメンバーを変えてやればOKです。
僕がやった例だと、
シーン上に落ちているボックスをプレイヤーキャラの子Objectにしたい。
しかし、 プレイヤーキャラはローカルクライアント。ボックスはリモートクライアント。
子Objectにすると、同期が狂いラグが発生しまくる。
そんな時にボックスのownerIDをプレイヤーのownerIDと一緒にする。
以上で、同期が狂うことはなくなりました。
さて、以上です。
次はOnPhotonInstantiateしたときのエラーについて書きましょうか。明日か明後日には書きます。
ではでは。
さて、早くも五回目です。そろそろ失速してきそうです。
基本的にgoogle先生にきいて、検索結果1ページで他の人が書いていない情報しか書かない主義ですから。だって1ページ目に出てくるのなんて有名で検索すればすぐ出てくるでしょ?それをわざわざ書くのはめんどいちーん。
で、ownerIDです。
PhotonViewクラスのメンバーです。
こいつはなんぞやというと、読んで字のごとくownerのIDです。
このPhotonViewがついているObjectを、どのプレイヤーが管理しているかちゅーことです。
基本的に、自分が生成した(PhotonNetwork.Instantiateなどで) Objectには自分のIDがつきます。
自分のIDとはPhotonPlayerクラスの"ID"メンバーで得られる値です。
で、このownerIDはアクセスレベルがpublicなので書きかえられます。
自分が生成していないObjectを自分の管理化に置きたい場合、このメンバーを変えてやればOKです。
僕がやった例だと、
シーン上に落ちているボックスをプレイヤーキャラの子Objectにしたい。
しかし、 プレイヤーキャラはローカルクライアント。ボックスはリモートクライアント。
子Objectにすると、同期が狂いラグが発生しまくる。
そんな時にボックスのownerIDをプレイヤーのownerIDと一緒にする。
以上で、同期が狂うことはなくなりました。
さて、以上です。
次はOnPhotonInstantiateしたときのエラーについて書きましょうか。明日か明後日には書きます。
ではでは。
2014年8月2日土曜日
なんかphotonでエラーログが出る
お疲れ様です、siroponnです。日々熱いですね。
さて、タイトルの件についてですが。
今回やりたかった処理は、
ボックスがプレイヤーか地面に接触した時破壊する。
その後エフェクトプレファブをインスタンスして、爆発を出し、周りのボックスも破壊する。というものです。
photonを使っていて以下のエラーログを見たことありませんか?
「PhotonView with ID 2002 has no method "DestroyObjectRPC" marked with the [RPC](C#) or @RPC(JS) property! Args: 」
えーと、 "DestroyObjectRPC"というメソッドを持っていない、そして[RPC]表記していないっと。
ソースを見る。
↓こちらのメソッドを通してRPC通信する
public void DestroyThisObject()
{
myPhotonView.RPC("DestroyObjectRPC", PhotonTargets.All);
}
[RPC]
void DestroyObjectRPC()
{
if (myPhotonView.isMine)
{
PhotonNetwork.Destroy(this.gameObject);
}
}
されていますね。
そこで、RPCを呼ばないで直接PhotonNetwork.Destroyを呼んだ。
public void DestroyThisObject()
{
if(myPhotonView.isMine)
{
PhotonNetwork.Destroy(this.gameObject);
}
//myPhotonView.RPC("DestroyObjectRPC", PhotonTargets.All);
}
こうしたら、一応エラーは消えました。
が。
リモートクライアントに当たった時反応してくれません。当たり前で、isMineにて判定を行っていますからね。
次の策。↓ というか完全に直感で書いた。
public void DestroyThisObject()
{
if (this.myPhotonView.isMine)
PhotonNetwork.Destroy(this.gameObject);
else
myPhotonView.RPC("DestroyObjectRPC",PhotonTargets.Others);
//myPhotonView.RPC("DestroyObjectRPC", PhotonTargets.All);
}
こうしたら意図したとおりに直りました。なぜなんだ。おい。
RPCでPhotonNetwork.Destoryを呼ぶのがいけないと思っていたが。
RPCのTargets.AllでPhotonNetwork.Destroyを呼ぶのがいけないのか???
わからん。
思い当たる節があるとすれば、まだブログには書いてませんが、ownerIDをゲーム処理中に書き変えていることでしょうか……。ローカルとリモートを入れ替えたりしているので、それかもしれません。
また、エフェクトのプレファブのスクリプトにも問題がありそうです。
爆発した際、爆発に巻き込まれたボックスを破壊している処理がありますから。ただ、エフェクトを呼んだボックスはインスタンスIDで判定して破壊されるのを防いでいるんですけどね。
とりあえず、PhotonNetwork.InstantiateやPhotonNetwork.Destroyを呼ばないで、マニュアルでインスタンスとデストロイを行った方が安全かもしれない。
もやもやするが、ここで立ち止まっているとプロジェクトが進まないので一旦、置いておく。
だれか、この原因を詳しく解明してくれ。
次回は、問題があるかもしれないownerIDについて書こうと思います。
では、ノシ
さて、タイトルの件についてですが。
今回やりたかった処理は、
ボックスがプレイヤーか地面に接触した時破壊する。
その後エフェクトプレファブをインスタンスして、爆発を出し、周りのボックスも破壊する。というものです。
photonを使っていて以下のエラーログを見たことありませんか?
「PhotonView with ID 2002 has no method "DestroyObjectRPC" marked with the [RPC](C#) or @RPC(JS) property! Args: 」
えーと、 "DestroyObjectRPC"というメソッドを持っていない、そして[RPC]表記していないっと。
ソースを見る。
↓こちらのメソッドを通してRPC通信する
public void DestroyThisObject()
{
myPhotonView.RPC("DestroyObjectRPC", PhotonTargets.All);
}
[RPC]
void DestroyObjectRPC()
{
if (myPhotonView.isMine)
{
PhotonNetwork.Destroy(this.gameObject);
}
}
されていますね。
そこで、RPCを呼ばないで直接PhotonNetwork.Destroyを呼んだ。
public void DestroyThisObject()
{
if(myPhotonView.isMine)
{
PhotonNetwork.Destroy(this.gameObject);
}
//myPhotonView.RPC("DestroyObjectRPC", PhotonTargets.All);
}
こうしたら、一応エラーは消えました。
が。
リモートクライアントに当たった時反応してくれません。当たり前で、isMineにて判定を行っていますからね。
次の策。↓ というか完全に直感で書いた。
public void DestroyThisObject()
{
if (this.myPhotonView.isMine)
PhotonNetwork.Destroy(this.gameObject);
else
myPhotonView.RPC("DestroyObjectRPC",PhotonTargets.Others);
//myPhotonView.RPC("DestroyObjectRPC", PhotonTargets.All);
}
こうしたら意図したとおりに直りました。なぜなんだ。おい。
RPCでPhotonNetwork.Destoryを呼ぶのがいけないと思っていたが。
RPCのTargets.AllでPhotonNetwork.Destroyを呼ぶのがいけないのか???
わからん。
思い当たる節があるとすれば、まだブログには書いてませんが、ownerIDをゲーム処理中に書き変えていることでしょうか……。ローカルとリモートを入れ替えたりしているので、それかもしれません。
また、エフェクトのプレファブのスクリプトにも問題がありそうです。
爆発した際、爆発に巻き込まれたボックスを破壊している処理がありますから。ただ、エフェクトを呼んだボックスはインスタンスIDで判定して破壊されるのを防いでいるんですけどね。
とりあえず、PhotonNetwork.InstantiateやPhotonNetwork.Destroyを呼ばないで、マニュアルでインスタンスとデストロイを行った方が安全かもしれない。
もやもやするが、ここで立ち止まっているとプロジェクトが進まないので一旦、置いておく。
だれか、この原因を詳しく解明してくれ。
次回は、問題があるかもしれないownerIDについて書こうと思います。
では、ノシ
2014年7月21日月曜日
unityのInput.GetButton("Jump")が効かないことについて
ども、凡人のsiroponnです。
タイトルにあります通り、Input.GetButton("Jump")が効きません。
詳しく言いますと、キーボードの上矢印ボタンと左矢印ボタンを押しながらの状態だとInput.GetButton("Jump")が効きません。
これは自分の環境が悪いのか。それともunityのバグなのか分かりませんが。
みなさんは気を付けてください。
では、また会いましょう。
タイトルにあります通り、Input.GetButton("Jump")が効きません。
詳しく言いますと、キーボードの上矢印ボタンと左矢印ボタンを押しながらの状態だとInput.GetButton("Jump")が効きません。
これは自分の環境が悪いのか。それともunityのバグなのか分かりませんが。
みなさんは気を付けてください。
では、また会いましょう。
2014年7月18日金曜日
PhotonCloud photonView.isMineについて
どうも凡人なsiroponnです。
前の投稿にphotonについて話すと書いた。
僕が言っているphotonとはExitGamesが開発しているPhotonCloudのことである。
https://www-jp.exitgames.com/ja/Realtime
そもそもphotonCloudとはなんぞや?って知らない人は思うでしょう。
詳細は上のリンクを見てもらうとして。
簡単に言うと、オンラインゲームを、自分でサーバを立てなくて、「お手軽」につくれるサービスです。
その中でも僕はunityユーザーなのでPhotonUnityNetworking(PUN)について書いていくことになります。
untiy
http://japan.unity3d.com/
もしかしたら、unityを使わずのAndroid開発やiOS開発、HTML5での開発やcocos2d-xでの開発もするかもしれない。でも、当分はPUNの話です。
さて、技術的な話を書くぞ。
以下はphotonを使ったことがある人向け。
PUNを使っているとこういうコードに出くわす。(シンタックスハイライトしなきゃ。でもめんどくさい)
class test : Photon.Monobehaviour
{
void test()
{
if(photonView.isMine)
{
"なんかのコード "
}
}
}
で、 "なんかのコード"部分が実行されない時がある。
それはPhotonNetwork.ConnectUsingSettings("貴方のアプリの適当なバージョン")をあらかじめ呼ばなかった場合である。photonView.isMineがfalseを返しているのだ。
自分はオフライン環境でもコードを使えるようにしていたのだが、一向に”なんかのコード”部分が実行されず二時間ぐらい唸っていた。
なお、PhotonNetwork.offlineModeの値をtrueにしても駄目だった。なぜだ……。
では、凡人はこれにて失敬。
前の投稿にphotonについて話すと書いた。
僕が言っているphotonとはExitGamesが開発しているPhotonCloudのことである。
https://www-jp.exitgames.com/ja/Realtime
そもそもphotonCloudとはなんぞや?って知らない人は思うでしょう。
詳細は上のリンクを見てもらうとして。
簡単に言うと、オンラインゲームを、自分でサーバを立てなくて、「お手軽」につくれるサービスです。
その中でも僕はunityユーザーなのでPhotonUnityNetworking(PUN)について書いていくことになります。
untiy
http://japan.unity3d.com/
もしかしたら、unityを使わずのAndroid開発やiOS開発、HTML5での開発やcocos2d-xでの開発もするかもしれない。でも、当分はPUNの話です。
さて、技術的な話を書くぞ。
以下はphotonを使ったことがある人向け。
PUNを使っているとこういうコードに出くわす。(シンタックスハイライトしなきゃ。でもめんどくさい)
class test : Photon.Monobehaviour
{
void test()
{
if(photonView.isMine)
{
"なんかのコード "
}
}
}
で、 "なんかのコード"部分が実行されない時がある。
それはPhotonNetwork.ConnectUsingSettings("貴方のアプリの適当なバージョン")をあらかじめ呼ばなかった場合である。photonView.isMineがfalseを返しているのだ。
自分はオフライン環境でもコードを使えるようにしていたのだが、一向に”なんかのコード”部分が実行されず二時間ぐらい唸っていた。
なお、PhotonNetwork.offlineModeの値をtrueにしても駄目だった。なぜだ……。
では、凡人はこれにて失敬。
2014年7月7日月曜日
凡人始動
何かをアウトプットしたくなった。
だからとりあえずブログにしようと思う。
ただの小言だったりならTwitterで充分だからこのブログは主に真面目な話しになる。あと技術系の話だったり、後にgoogleサイトを立てる予定だからそちらも告知だったりするかもしれない。まだ決まっていない。もしかしたら更新の内容がほぼgoogleサイトの事だけになる可能性もある。まだ分からない。
さてこれはブログだ。一回目は何を書こうか。
そうだ、このブログのタイトルについて。凡人の活動記録です。
ハッキリ言いましょう。僕は凡人です。それも超が付くほどの。
そう思ったのは僕が、一つの事に熱中出来ないからです。
天才は自分の興味のあることだったらひたすら熱中するけど、僕は興味があっても熱中することはありません。だから天才には届かない。才能ある人には届きません。
技術だってそこそこです。
でも、いいんです。逆に考えてみました。天才はその一つの事しか出来ないのだと。熱中するが故に。
けど、凡人は違う。天才が100%を目指している間に、凡人は80%を二つ三つこなせる。いろんな事を経験出来るのです。これってある意味得ですよね。
まぁきっと、こんな屁理屈を述べている僕は何者にもなれないのでしょう。
でも、それはそれでいいかなぁ。って思う。何者にもなれないまま色々な事を挑戦して、飽きて、朽ちていく。それも悪くはないかなってね。
と、長く語りましたが。結局何が言いたいかというと。僕は超凡人で。その超がつくほどの凡人がそこそこ頑張りながら粛々と活動した記録書いていく。そんなブログです。
技術系の話はunity,blender,2Dイラスト。あとはプログラミング全般をする予定。
おそらく近々書くのは、photonかも。
技術だってそこそこです。
でも、いいんです。逆に考えてみました。天才はその一つの事しか出来ないのだと。熱中するが故に。
けど、凡人は違う。天才が100%を目指している間に、凡人は80%を二つ三つこなせる。いろんな事を経験出来るのです。これってある意味得ですよね。
まぁきっと、こんな屁理屈を述べている僕は何者にもなれないのでしょう。
でも、それはそれでいいかなぁ。って思う。何者にもなれないまま色々な事を挑戦して、飽きて、朽ちていく。それも悪くはないかなってね。
と、長く語りましたが。結局何が言いたいかというと。僕は超凡人で。その超がつくほどの凡人がそこそこ頑張りながら粛々と活動した記録書いていく。そんなブログです。
技術系の話はunity,blender,2Dイラスト。あとはプログラミング全般をする予定。
おそらく近々書くのは、photonかも。
登録:
投稿 (Atom)