03 2012
NetworkViewを使って通信対戦 その6でRPC(リモートプロシージャコール)について。
直訳すると「遠隔で処理を呼ぶ」。つまり遠隔で処理を呼ぶって事だよ!
(実はよく理解していない可能性)
モンハンで例えよう。
敵が眠ってチャンス到来!「自分が大タル爆弾を設置する」操作を行うとする。
すると自分の端末は「大タル爆弾を設置」する処理を実行する。
ローカルだけなら問題ない。
だがネットワーク上にある自分(のコピー)は、処理まで同期していない。
味方からすれば、アワレにも足元でゴソゴソしている変な奴に見えると思う。
ここでRPCが必要になる。
RPCはネットワーク上のユーザーに処理を実行させる仕組み。
ネットワーク上に見えている自分(のコピー)に対して、「大タル爆弾を設置」と通知、
結果ネットワーク上の自分(のコピー)は「大タル爆弾を設置」って処理を実行する。
すると自分(のコピー)の足元に大タル爆弾が設置される。
同様の仕組みでバカが散弾を大タル爆弾にぶち込み、自分が死ぬ。
ガッデム。
多分こんな概念。
で、使い方。
まず、これを使うためにはNetworkViewのコンポーネントを持ってる必要が有りそう。
なのでNetworkViewコンポーネントを追加。
ココらへんの操作は過去ログに書いたような気がするので、放置。
次にローカルで大タル爆弾を設置する仕組みを作成。
これだけ。超便利。
調査ネタを募集中

直訳すると「遠隔で処理を呼ぶ」。つまり遠隔で処理を呼ぶって事だよ!
(実はよく理解していない可能性)
モンハンで例えよう。
敵が眠ってチャンス到来!「自分が大タル爆弾を設置する」操作を行うとする。
すると自分の端末は「大タル爆弾を設置」する処理を実行する。
ローカルだけなら問題ない。
だがネットワーク上にある自分(のコピー)は、処理まで同期していない。
味方からすれば、アワレにも足元でゴソゴソしている変な奴に見えると思う。
ここでRPCが必要になる。
RPCはネットワーク上のユーザーに処理を実行させる仕組み。
ネットワーク上に見えている自分(のコピー)に対して、「大タル爆弾を設置」と通知、
結果ネットワーク上の自分(のコピー)は「大タル爆弾を設置」って処理を実行する。
すると自分(のコピー)の足元に大タル爆弾が設置される。
同様の仕組みでバカが散弾を大タル爆弾にぶち込み、自分が死ぬ。
ガッデム。
多分こんな概念。
で、使い方。
まず、これを使うためにはNetworkViewのコンポーネントを持ってる必要が有りそう。
なのでNetworkViewコンポーネントを追加。
ココらへんの操作は過去ログに書いたような気がするので、放置。
次にローカルで大タル爆弾を設置する仕組みを作成。
void Update()
{
if( Input.GetKeyDown(KeyCode.Mouse0 ))
{
SetBigBom();
}
}
void SetBigBom()
{
// .. 大タルを設置する
}
こいつを、こう変える。
void Update()
{
if( Input.GetKeyDown(KeyCode.Mouse0 ))
{
networkView.RPC("SetBigBom", RPCMode.All);
}
}
[RPC]
void SetBigBom()
{
// .. 大タルを設置する
}
これだけ。超便利。
調査ネタを募集中
NetworkViewを使って通信対戦 その5
今回はスクリプトのパラメータ同期について。
UnityのNetworkViewは、Scriptだっての同期できる。
これを実現すれば、HPやパラメータ等の情報を簡単に同期できて超便利。
とはいえ、万能ではないみたい。
同期できるオブジェクトはScript一つにつき一つまで。
しかも下の9つの型しか同期できないらしい。
むむむ。
・bool
・char
・short
・int
・float
・Quaternion
・Vector3
・NetworkPlayer
・NetworkViewID
次は同期方法。
同期はOnSerializeNetworkViewメソッドで行う。
まずは記述すべきソース。
今回はキャラクターのHPを同期させてみる。
public int hp = 100;
void OnSerializeNetworkView(BitStream stream, NetworkMessageInfo info) {
int health = 0;
if (stream.isWriting) {
health = hp;
stream.Serialize(ref health);
} else {
stream.Serialize(ref health);
hp = health;
}
}
まずOnSerializeNetworkViewについて。
これは定義しておけば勝手に実行するタイプのメソッドで、
ネットワークに接続したときに一定間隔で呼ばれるようになる。
呼び出す間隔は、計測したときは一秒間に18回くらい。(接続対象の呼び出しも含まれてるかも)
ここは環境に依存するような臭いがするので、一秒間に何回も呼ばれる程度の認識で良いと思う。
ちなみに接続対象が複数居ないと呼ばれないので注意。(ホストだけでは呼ばれない)
こういった処理はIF継承で定義されてると楽だけど、IF設定がわかりにくって噂も。むむむ。
次、stream.isWritingで書きこみ状況をチェックして、パラメータを同期する。
stream.isWritingが書き込み状態ならstream.Serializeでネットワーク上のオブジェクトを更新、
stream.isWritingが読み込み状態ならstream.Serializeでネットワーク上のオブジェクトを取得を行う。
なおstream.Serializeの引数はref(参照渡し)なので、
渡した変数が変化して帰ってくる(事がある)
これでHPの同期ができた。
状態異常とかもビット演算とかで一括管理できるんじゃないかと密かに期待してたり。
とは言え、ネットワーク帯域はメモリ量の次に大切なもの。(動作>メモリ量>ネットワーク帯域>PGの命)
めったに変化しないようなパラメータなら、メッセージングで管理したほうが良い気もする。
てことで、次は任意のタイミングでメッセージを送信するRPCについてかなあ
調査ネタを募集中

今回はスクリプトのパラメータ同期について。
UnityのNetworkViewは、Scriptだっての同期できる。
これを実現すれば、HPやパラメータ等の情報を簡単に同期できて超便利。
とはいえ、万能ではないみたい。
同期できるオブジェクトはScript一つにつき一つまで。
しかも下の9つの型しか同期できないらしい。
むむむ。
・bool
・char
・short
・int
・float
・Quaternion
・Vector3
・NetworkPlayer
・NetworkViewID
次は同期方法。
同期はOnSerializeNetworkViewメソッドで行う。
まずは記述すべきソース。
今回はキャラクターのHPを同期させてみる。
public int hp = 100;
void OnSerializeNetworkView(BitStream stream, NetworkMessageInfo info) {
int health = 0;
if (stream.isWriting) {
health = hp;
stream.Serialize(ref health);
} else {
stream.Serialize(ref health);
hp = health;
}
}
まずOnSerializeNetworkViewについて。
これは定義しておけば勝手に実行するタイプのメソッドで、
ネットワークに接続したときに一定間隔で呼ばれるようになる。
呼び出す間隔は、計測したときは一秒間に18回くらい。(接続対象の呼び出しも含まれてるかも)
ここは環境に依存するような臭いがするので、一秒間に何回も呼ばれる程度の認識で良いと思う。
ちなみに接続対象が複数居ないと呼ばれないので注意。(ホストだけでは呼ばれない)
こういった処理はIF継承で定義されてると楽だけど、IF設定がわかりにくって噂も。むむむ。
次、stream.isWritingで書きこみ状況をチェックして、パラメータを同期する。
stream.isWritingが書き込み状態ならstream.Serializeでネットワーク上のオブジェクトを更新、
stream.isWritingが読み込み状態ならstream.Serializeでネットワーク上のオブジェクトを取得を行う。
なおstream.Serializeの引数はref(参照渡し)なので、
渡した変数が変化して帰ってくる(事がある)
これでHPの同期ができた。
状態異常とかもビット演算とかで一括管理できるんじゃないかと密かに期待してたり。
とは言え、ネットワーク帯域はメモリ量の次に大切なもの。(動作>メモリ量>ネットワーク帯域>PGの命)
めったに変化しないようなパラメータなら、メッセージングで管理したほうが良い気もする。
てことで、次は任意のタイミングでメッセージを送信するRPCについてかなあ
調査ネタを募集中
NetworkViewを使って通信対戦 その4
少し前回の補足で、ソースコードの使い方について。
ソースコードはゲーム管理マネージャみたいなものなので、
適当なGameObjectに貼りつけておくと吉。
具体的には、GameManagerって空のGameObjectを作って、そこに貼りつけておく。
あと、インスタンス生成位置がGameManager(仮)の位置になってる。
そのまま生成すると二人が同じ位置に生成されちゃうので、
GameManager以下にNodeって名前のGameObjectを用意して、その位置に出力しても良いかもと思った。
ソースはこんな感じ?

private void CreatePlayer()
{
connected = true;
int positionNo = Random.Range(0, transform.childCount);
Transform childTransform = transform.GetChild(positionNo).transform;
Network.Instantiate(prefub, childTransform.position, childTransform.rotation, 1);
}
話を戻して、NetworkViewのパラメータ同期について。
NetworkViewその1くらいでScript、アニメーション、Transform、RigidBodyのいずれか一つを同期するって
書いたけど、そのまま使ってもTransformしか同期しない。
てことで、まずは監視対象にTransform以外を設定する方法。
今回はRigidbodyを同期対象に設定。
方法は簡単、inspectorのRigidbodyってタイトルをNetworkViewのObservedにD&Dする。
これでOK。
成功すると、Observedに設定しているオブジェクトのカッコ内が変化する。


意外と長くなってしまった。
次にスクリプトの設定について…は…まあ、明日にでも。
そういえばnUIGの無料版があるらしい。
コレ終わったらQuad UIでもやろうかと思ってたけど、先にこっちするかも。
http://forum.unity3d.com/threads/124032-NGUI-Free-Edition?p=834225
調査ネタを募集中

少し前回の補足で、ソースコードの使い方について。
ソースコードはゲーム管理マネージャみたいなものなので、
適当なGameObjectに貼りつけておくと吉。
具体的には、GameManagerって空のGameObjectを作って、そこに貼りつけておく。
あと、インスタンス生成位置がGameManager(仮)の位置になってる。
そのまま生成すると二人が同じ位置に生成されちゃうので、
GameManager以下にNodeって名前のGameObjectを用意して、その位置に出力しても良いかもと思った。
ソースはこんな感じ?
private void CreatePlayer()
{
connected = true;
int positionNo = Random.Range(0, transform.childCount);
Transform childTransform = transform.GetChild(positionNo).transform;
Network.Instantiate(prefub, childTransform.position, childTransform.rotation, 1);
}
話を戻して、NetworkViewのパラメータ同期について。
NetworkViewその1くらいでScript、アニメーション、Transform、RigidBodyのいずれか一つを同期するって
書いたけど、そのまま使ってもTransformしか同期しない。
てことで、まずは監視対象にTransform以外を設定する方法。
今回はRigidbodyを同期対象に設定。
方法は簡単、inspectorのRigidbodyってタイトルをNetworkViewのObservedにD&Dする。
これでOK。
成功すると、Observedに設定しているオブジェクトのカッコ内が変化する。
意外と長くなってしまった。
次にスクリプトの設定について…は…まあ、明日にでも。
そういえばnUIGの無料版があるらしい。
コレ終わったらQuad UIでもやろうかと思ってたけど、先にこっちするかも。
http://forum.unity3d.com/threads/124032-NGUI-Free-Edition?p=834225
調査ネタを募集中
NetworkViewを使って通信対戦 その3
今回は下の2つの手順の内、②を進めてみる。
①動かすオブジェクトの設定(プレイヤー)の設定
②ネットワークを管理するスクリプトの設定
これが完了すると、とりあえず初期実行画面はできる。
hostを押すと、ホストになる。connectを押すと、ホストに接続する。

とりあえずソースと解説をば。
以下ソース
(ブログにコピペで張り付けるとインデントが無くてわかりにくかったから、全角スペースを所々に配置。
全コピだと使えなくなるかもしれない)
using gui = UnityEngine.GUI;
...
public GameObject prefub;
public string ip = "127.0.0.1";
private string port = "4211";
private bool connected = false;
private void CreatePlayer()
{
connected = true;
Network.Instantiate(prefub, transform.position, transform.rotation, 1);
}
public void OnDisconnectedFromServer(){ connected = false; }
public void OnPlayerDisconnected(NetworkPlayer pl){ Network.DestroyPlayerObjects(pl);}
public void OnConnectedToServer(){ CreatePlayer();}
public void OnServerInitialized(){ CreatePlayer(); }
public void OnGUI()
{
if( !connected)
{
ip = gui.TextField( new Rect(10,10,90,20),ip);
port = gui.TextField( new Rect(10, 40, 90, 20), port);
if( gui.Button( new Rect( 10,70,90, 20), "Connect")){ Network.Connect(ip, int.Parse(port) ); }
if( gui.Button( new Rect(10, 100, 90, 20), "host")){ Network.InitializeServer(10, int.Parse(port), false); }
}
}
MacのMonoDevelopに日本語が入力できないので、コメントはなし。
いや本当になんでだろう・・
誰か何とかする方法知らないかな
解説。
このソースは、クライアントとサーバの両方に対応したスクリプトで、
簡単に言えば、以下の処理を行う。
A.サーバーを立てたらサーバー上にPrefubのコピー(自分が操作するプレイヤー)を配置
B.サーバーに接続したらサーバー上にPrefubのコピー(自分が操作するプレイヤー)を配置
C.接続するかサーバーとなるかを設定するGUIの提供
つまり、
サーバーの場合、
1.Network.InitializeServerでサーバーをネットワーク上に立てる。
2.OnServerInitialized()が実行され、サーバー上にプレハブを配置する。
クライアントの場合、
1.Network.Connectでサーバーに接続する。
2.OnConnectedToServer()が実行され、サーバー上にプレハブを配置する。
こんな感じ。
後は切断時の動作とか云々。何となく分かるはず。
OnGUIで行ってる処理は・・・そのうち。
これでシンプルなネットワークが出来た。
次はパラメータの同期についてかな
調査対象を募集中
今回は下の2つの手順の内、②を進めてみる。
①動かすオブジェクトの設定(プレイヤー)の設定
②ネットワークを管理するスクリプトの設定
これが完了すると、とりあえず初期実行画面はできる。
hostを押すと、ホストになる。connectを押すと、ホストに接続する。
とりあえずソースと解説をば。
以下ソース
(ブログにコピペで張り付けるとインデントが無くてわかりにくかったから、全角スペースを所々に配置。
全コピだと使えなくなるかもしれない)
using gui = UnityEngine.GUI;
...
public GameObject prefub;
public string ip = "127.0.0.1";
private string port = "4211";
private bool connected = false;
private void CreatePlayer()
{
connected = true;
Network.Instantiate(prefub, transform.position, transform.rotation, 1);
}
public void OnDisconnectedFromServer(){ connected = false; }
public void OnPlayerDisconnected(NetworkPlayer pl){ Network.DestroyPlayerObjects(pl);}
public void OnConnectedToServer(){ CreatePlayer();}
public void OnServerInitialized(){ CreatePlayer(); }
public void OnGUI()
{
if( !connected)
{
ip = gui.TextField( new Rect(10,10,90,20),ip);
port = gui.TextField( new Rect(10, 40, 90, 20), port);
if( gui.Button( new Rect( 10,70,90, 20), "Connect")){ Network.Connect(ip, int.Parse(port) ); }
if( gui.Button( new Rect(10, 100, 90, 20), "host")){ Network.InitializeServer(10, int.Parse(port), false); }
}
}
MacのMonoDevelopに日本語が入力できないので、コメントはなし。
いや本当になんでだろう・・
誰か何とかする方法知らないかな
解説。
このソースは、クライアントとサーバの両方に対応したスクリプトで、
簡単に言えば、以下の処理を行う。
A.サーバーを立てたらサーバー上にPrefubのコピー(自分が操作するプレイヤー)を配置
B.サーバーに接続したらサーバー上にPrefubのコピー(自分が操作するプレイヤー)を配置
C.接続するかサーバーとなるかを設定するGUIの提供
つまり、
サーバーの場合、
1.Network.InitializeServerでサーバーをネットワーク上に立てる。
2.OnServerInitialized()が実行され、サーバー上にプレハブを配置する。
クライアントの場合、
1.Network.Connectでサーバーに接続する。
2.OnConnectedToServer()が実行され、サーバー上にプレハブを配置する。
こんな感じ。
後は切断時の動作とか云々。何となく分かるはず。
OnGUIで行ってる処理は・・・そのうち。
これでシンプルなネットワークが出来た。
次はパラメータの同期についてかな
調査対象を募集中
よく考えたら、ジャンルってコンピューター開発じゃなくてプログラミングですよね^^;
些細なことは置いておいて、[Unity]NetworkViewを使って通信対戦 その2。
今回は下の2つの手順の内、①を進めてみる。
①動かすオブジェクトの設定(プレイヤー)の設定
②ネットワークを管理するスクリプトの設定
オブジェクト(プレイヤー)の設定
基本的にオフラインの作りとほとんど同じように作れる。
移動はTransformで指定してやればいいし、
キー入力とかは、概ねそのまんまで問題ない。
注意することは2点。
・同期するTransformはワールド座標ではない。
・network.isMineを設定する
まずTransformについては、例えば、操作系は親オブジェクトに配置し
子オブジェクトのメッシュ(位置情報)だけ同期しようとしてもうまくいかない。
オブジェクトのパラメータを同期しているので、仕方がない。
もう一つ、network.isMineについて。
これはスクリプトを実行するオブジェクトが自分かどうかを判断するプロパティ。
これが無いと、別のネットワークに接続しているキャラクターも操作してしまう。
なので、isMineで自分以外のオブジェクトの操作系を外してやる必要がある。
具体的には、こんな感じ
if( true == network.isMine )
{
if( Input.GetKey(KeyCode.****)){ ... }
}
ネットワークでオブジェクトを同期させる設定
次に、作ったオブジェクトをネットワーク上で同期するように設定する。
とにもかくにも、Network View コンポーネントを同期したいオブジェクトに貼り付ける。
場所は、「Component→Miscellaneous→Network View」にある。

で、同期させたいオブジェクトをObserverd(監視)に設定する。
自分の環境だと、コンポーネントを貼りつけた地点で貼りつけたオブジェクトが設定されてる。

ちなみに、Network ViewのObservedで指定しているオブジェクトしか同期しない。
つまり子オブジェクトを同期したい場合は、子オブジェクトにもNetwork Viewを設定する必要がある。
例えば、FPSのキャラクターの位置と銃の方向を同期したい場合、
キャラクター(親オブジェクト・位置+向き)に1枚、銃(カメラの方向・上下)に一枚って形。
次は②、ネットワークを管理するスクリプトの設定だ。
調査対象を募集中
些細なことは置いておいて、[Unity]NetworkViewを使って通信対戦 その2。
今回は下の2つの手順の内、①を進めてみる。
①動かすオブジェクトの設定(プレイヤー)の設定
②ネットワークを管理するスクリプトの設定
オブジェクト(プレイヤー)の設定
基本的にオフラインの作りとほとんど同じように作れる。
移動はTransformで指定してやればいいし、
キー入力とかは、概ねそのまんまで問題ない。
注意することは2点。
・同期するTransformはワールド座標ではない。
・network.isMineを設定する
まずTransformについては、例えば、操作系は親オブジェクトに配置し
子オブジェクトのメッシュ(位置情報)だけ同期しようとしてもうまくいかない。
オブジェクトのパラメータを同期しているので、仕方がない。
もう一つ、network.isMineについて。
これはスクリプトを実行するオブジェクトが自分かどうかを判断するプロパティ。
これが無いと、別のネットワークに接続しているキャラクターも操作してしまう。
なので、isMineで自分以外のオブジェクトの操作系を外してやる必要がある。
具体的には、こんな感じ
if( true == network.isMine )
{
if( Input.GetKey(KeyCode.****)){ ... }
}
ネットワークでオブジェクトを同期させる設定
次に、作ったオブジェクトをネットワーク上で同期するように設定する。
とにもかくにも、Network View コンポーネントを同期したいオブジェクトに貼り付ける。
場所は、「Component→Miscellaneous→Network View」にある。
で、同期させたいオブジェクトをObserverd(監視)に設定する。
自分の環境だと、コンポーネントを貼りつけた地点で貼りつけたオブジェクトが設定されてる。

ちなみに、Network ViewのObservedで指定しているオブジェクトしか同期しない。
つまり子オブジェクトを同期したい場合は、子オブジェクトにもNetwork Viewを設定する必要がある。
例えば、FPSのキャラクターの位置と銃の方向を同期したい場合、
キャラクター(親オブジェクト・位置+向き)に1枚、銃(カメラの方向・上下)に一枚って形。
次は②、ネットワークを管理するスクリプトの設定だ。
調査対象を募集中