Unityの公式チュートリアルに掲載されているマルチプレイヤーネットワーキングを勉強を進めている様子をお送りします。前回の記事はこちらからどうぞ
プレイヤーの体力をネットワーク化する
公式サイトのチュートリアルページ プレイヤーの体力をネットワーク化する
今回は体力値の変更をサーバーで行い、その後クライアントで同期するように改造します。
スクリプトHealthの修正
体力値の変更をサーバー上のみで行うようにスクリプトを修正します。
- Health スクリプトを開く
- 名前空間 UnityEngine.Networking を追加
- スクリプトを、NetworkBehaviour から派生するように変更
- 変数 currentHealth を作成して [SyncVar]属性を付ける
- ダメージがサーバー上のみで適用されるように、関数 TakeDamage に isServer のチェックを追加
- スクリプトを保存
修正したスクリプトのコードにコメントを加えたものがこちら。
using System.Collections; using System.Collections.Generic; using UnityEngine; // UIコンポーネント関数を使用するため名前空間の追加 using UnityEngine.UI; // ネットワークコンポーネント関数を使用するため名前空間の追加 using UnityEngine.Networking; public class Health : NetworkBehaviour { // 体力値を格納する変数(定数値 100) public const int maxHealth = 100; // 現在の体力値を格納する変数(ネットワーク同期、初期値は maxHealth) [SyncVar] public int currentHealth = maxHealth; // RectTranform コンポーネントを格納する変数 public RectTransform healthBar; // ダメージ処理(サーバー上のみ) public void TakeDamage(int amount) { // サーバーでない場合 if (!isServer) { // 以降の処理を中断 return; } // 現在の体力値から 引数 amount の値を引く currentHealth -= amount; // 現在の体力値が 0 以下の場合 if (currentHealth <= 0) { // 現在の体力値に 0 を代入 currentHealth = 0; // コンソールに"Dead!"を表示する Debug.Log("Dead!"); } // RectTranform コンポーネントのサイズを体力値に合わせて変更 //(X値に currentHealth を代入、Y値は RectTranform コンポーネントのY値を代入) healthBar.sizeDelta = new Vector2(currentHealth, healthBar.sizeDelta.y); } }
動作確認
- シーンをスタンドアロンのアプリケーションとして Build and Run を実行
- ゲーム内 UI から[Host]ボタンをクリックしてゲームをホストとして開始
- プレイヤーゲームオブジェクトを動かす
- Unity に戻ってPlay モードを開始
- ゲーム内 UI から[LAN Client]ボタンをクリックしてクライアントとしてホストに接続
- スタンドアロン プレイヤーを終了
- Unity に戻ってPlay モードを終了
このステップを終えてゲームを実行。ビルドしたゲームを2つ実行してウィンドウを並べました。画面左のホスト(サーバー&クライアント)のみ体力ゲージが処理されています。
スクリプト Health の修正
体力値ゲージの RectTransform を他のクライアントでも同期するようにスクリプトを修正します。
- Health スクリプトを開く
- Healthbar を変化させるコードを、新規関数 OnChangeHealth 内に移動
- currentHealth の SyncVar 属性内に、新規関数 OnChangeHealth へのフックを設定
- スクリプトを保存
修正したスクリプトのコードにコメントを加えたものがこちら。
using System.Collections; using System.Collections.Generic; using UnityEngine; // UIコンポーネント関数を使用するため名前空間の追加 using UnityEngine.UI; // ネットワークコンポーネント関数を使用するため名前空間の追加 using UnityEngine.Networking; public class Health : NetworkBehaviour { // 体力値を格納する変数(定数値 100) public const int maxHealth = 100; // 現在の体力値を格納する変数(ネットワーク同期、初期値は maxHealth) // 変数値が変更されたら関数 OnChangeHealth を実行 // OnChangeHealth の引数 health に currentHealth の値を渡す [SyncVar(hook = "OnChangeHealth")] public int currentHealth = maxHealth; // RectTranform コンポーネントを格納する変数 public RectTransform healthBar; // ダメージ処理(サーバー上のみ) public void TakeDamage(int amount) { // サーバーでない場合 if (!isServer) { // 以降の処理を中断 return; } // 現在の体力値から 引数 amount の値を引く currentHealth -= amount; // 現在の体力値が 0 以下の場合 if (currentHealth <= 0) { // 現在の体力値に 0 を代入 currentHealth = 0; // コンソールに"Dead!"を表示する Debug.Log("Dead!"); } } // 体力値ゲージの変更処理 // (引数 health には 変数 currentHealth の値が渡される ) void OnChangeHealth(int health) { // RectTranform コンポーネントのサイズを体力値に合わせて変更 //(X値に health を代入、Y値は RectTranform コンポーネントのY値を代入) healthBar.sizeDelta = new Vector2(health, healthBar.sizeDelta.y); } }
チュートリアルの解説部分で書かれている 関数 void OnChangeHealthの引数名が、関数部分だけ書かれている部分では下記の通り記述されています。
{
healthBar.sizeDelta = new Vector2(health, currentHealth.sizeDelta.y);
}
一方、スクリプト Health の全コードが書かれている部分では void OnChangeHealth (int health) と記述されていたので、しばらく???となりましたが、意味を考えると Health の全コードが書かれている
void OnChangeHealth (int health) の方が正しいと判断しました。
動作確認
- シーンをスタンドアロンのアプリケーションとして Build and Run を実行
- ゲーム内 UI から[Host]ボタンをクリックしてゲームをホストとして開始
- プレイヤーゲームオブジェクトを動かす
- Unity に戻ってPlay モードを開始
- ゲーム内 UI から[LAN Client]ボタンをクリックしてクライアントとしてホストに接続
- スタンドアロン プレイヤーを終了
- Unity に戻ってPlay モードを終了
このステップを終えてゲームを実行。ビルドしたゲームを2つ実行してウィンドウを並べました。
画面左のホスト(サーバー&クライアント)側、画面右のクライアント側のどちらも外力ゲージが変化して同期されるようになりました。
今回のポイントはこの部分ですね。
ダメージ処理はサーバー側だけで行い、その変数の変化に合わせてクライアント側で体力ゲージの処理を行うといういうのはうまくできているな~と思いました。