Categories: Unity

Unity:プレイヤーの体力【シングルプレイヤー】~マルチプレイヤーネットワーキングのチュートリアルに挑戦

Unityの公式チュートリアルに掲載されているマルチプレイヤーネットワーキングを勉強を進めている様子をお送りします。前回の記事はこちらからどうぞ

プレイヤーの体力【シングルプレイヤー】

公式サイトのチュートリアルページ プレイヤーの体力【シングルプレイヤー】

今回のステップではプレイヤーに体力ゲージを追加して弾丸のダメージ処理を行います。

弾丸の衝突判定スクリプトを作成する

最初は弾丸のプレハブに衝突判定用のコリジョンコンポーネントを追加します。

  1. プレハブ Bullet を選択
  2. [Inspector]ウィンドウ > [Add Component]ボタン > New Script を選択
  3. 新しいスクリプトを “Bullet” という名前で作成・追加
  4. スクリプト Bullet を開き、サンプルコードを全て削除
  5. 他のコライダーに衝突した時に弾丸を破壊するためのロジックを追加
  6. スクリプト Bullet を保存

作成したスクリプトのコードにコメントを加えたものがこちら。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Bullet : MonoBehaviour {

    // コリジョンと衝突した場合の処理
    void OnCollisionEnter()
    {
        // オブジェクトを削除
        Destroy(gameObject);
    }
}

動作確認

  1. シーンをスタンドアロンのアプリケーションとして Build and Run を実行
  2. ゲーム内 UI から[Host]ボタンをクリックしてゲームをホストとして開始
  3. プレイヤーゲームオブジェクトを動かす
  4. Unity に戻ってPlay モードを開始
  5. ゲーム内 UI から[LAN Client]ボタンをクリックしてクライアントとしてホストに接続
  6. スタンドアロン プレイヤーを終了
  7. Unity に戻ってPlay モードを終了

ここで、ありがちなミスをしてしまいました。
プリミティブオブジェクト Cylinder を使って銃を作成した際に Capsule Collider コンポーネントを削除する手順を忘れていたので、弾が発射されると同時に削除されてしまいました。

修正後、チュートリアルの解説通り、他のオブジェクトに衝突した弾丸は破壊されるようになりました。

Player の体力(Health)

プレイヤーの体力値を制御するスクリプトを作成します。

  1. [Project]ウィンドウ > プレハブ Player を選択
  2. [Inspector]ウィンドウ > [Add Component]ボタン > New Script を選択
  3. 新しいスクリプトを “Health” という名前で作成・追加
  4. スクリプト Health を開き、サンプルコードを全て削除
  5. フィールド health を追加し、開始(あるいは最高)の定数値を 100 に設定
  6. フィールド Current Health を追加し、初期値を Max Health に設定
  7. プレイヤーが撃たれた時に体力が減少するロジックを追加
  8. スクリプト Health を保存

作成したスクリプトのコードにコメントを加えたものがこちら。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Health : MonoBehaviour
{
    // 体力値を格納する変数(定数値 100)
    public const int maxHealth = 100;
    // 現在の体力値を格納する変数(初期値は maxHealth)
    public int currentHealth = maxHealth;

    // ダメージ処理
    public void TakeDamage(int amount)
    {
        // 現在の体力値から 引数 amount の値を引く
        currentHealth -= amount;
        // 現在の体力値が 0 以下の場合
        if (currentHealth <= 0)
        {
            // 現在の体力値に 0 を代入
            currentHealth = 0;
            // コンソールに"Dead!"を表示する
            Debug.Log("Dead!");
        }
    }
}

スクリプト Bullet の修正

弾丸が衝突した際のダメージ処理をスクリプトの追加します。

  1. スクリプト Bullet を開く
  2. 関数 OnCollisionEnter を Collision パラメーターを持つように変更
  3. 関数 OnCollisionEnter 内に、スクリプト Health 内の関数 TakeDamageを呼び出す処理を追加
  4. Bullet スクリプトを保存

作成したスクリプトのコードにコメントを加えたものがこちら。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Bullet : MonoBehaviour
{
    // コリジョンと衝突した場合の処理
    void OnCollisionEnter(Collision collision)
    {
        // 変数 hit に衝突したオブジェクトを格納
        var hit = collision.gameObject;
        // 変数 healthに、変数 hit に格納されたオブジェクトのコンポーネント Health を格納
        var health = hit.GetComponent<Health>();
        // 変数 health が空でなければ
        if (health != null)
        {
            // ダメージ処理を実行(体力値-10)
            //(スクリプト health の関数 TakeDamage を実行)
            health.TakeDamage(10);
        }
        // オブジェクトを削除
        Destroy(gameObject);
    }
}

動作確認してみると、10回相手のプレイヤーオブジェクトに弾を当てるとコンソールに Dead! と表示されました。そのまま弾を当て続けると体力値がすでに 0 なので Dead! が続けて表示されます。

簡単な体力ゲージ(Healthbar)の作成

体力値を表示するゲージの前景を作成します。

  1. シーン内に UIオブジェクト Image を 1つ新規作成して名前を “Background” に変更
  2. 自動的に作成されたUIオブジェクト Canvas の名前を “Healthbar Canvas” に変更
  3. オブジェクト Background を選択
  4. RectTransform コンポーネント > Width 100 / Height 10 に設定
  5. Image コンポーネント > Source Image を InputFieldBackground に設定
  6. Image コンポーネント > Color を Red に設定
[Scene]ビューで確認するとこのようになっています。

体力値ゲージの前景を作成します。

  1. オブジェクト Background の複製を作成して名前を “Foreground” に変更
  2. オブジェクト Foreground を Background の子にする
  3. オブジェクト Foreground が選択
  4. Image コンポーネント > Color を Green に設定
  5. RectTransform コンポーネント > Anchor Presets > Pivot と Position を Middle・Left に設定

Foreground の [Inspector]ウィンドウで RectTransform コンポーネントはこのように表示されています。

Foreground を [Scene]ビューで確認するとこのようになっています。

プレハブ Player に体力ゲージを組み込む

作成した体力ゲージをプレイヤープレハブに組み込みます。

  1. [Project]ウィンドウ > プレハブ Player を選択
  2. [Hierarchy]ウィンドウにドラッグしてインスタンスを作成
  3. Healthbar Canvas を選択
  4. Healthbar Canvas を Player ゲームオブジェクトの子にする
  5. [Inspector]ウィンドウ > Canvas > Render Mode > World Space に変更
  6. Healthbar Canvas を選択
  7. RectTransform コンポーネント > 歯車アイコン > Reset を選択
  8. RectTransform コンポーネント > Scale を X0.01, Y0.01, Z0.01 に設定
  9. RectTransform コンポーネント > Position を X0.0, Y1.5, Z0.0 に設定
  10. オブジェクト Player を選択して[Inspector]ウィンドウ > [Apply]を適用
  11. シーンを保存

Healthbar Canvas を[Inspector]ウィンドウで確認するとこのようになっています。

[Scene]ビューで Player を確認するとこのようになっています。

スクリプト Health の修正

体力ゲージの表示処理をスクリプトに追加します。

  1. Health スクリプトを開く
  2. 名前空間 UnityEngine.UI を追加
  3. Healthbar の Foreground 要素に、RectTranform への参照を含めるフィールドを追加
  4. Current Health の値を反映するよう、Healthbar の表示更新ロジックを追加

作成したスクリプトのコードにコメントを加えたものがこちら。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
// UIコンポーネント関数を使用するため名前空間の追加
using UnityEngine.UI;

public class Health : MonoBehaviour
{
    // 体力値を格納する変数(定数値 100)
    public const int maxHealth = 100;
    // 現在の体力値を格納する変数(初期値は maxHealth)
    public int currentHealth = maxHealth;
    // RectTranform コンポーネントを格納する変数
    public RectTransform healthBar;

    // ダメージ処理
    public void TakeDamage(int amount)
    {
        // 現在の体力値から 引数 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);
    }
}

プレハブ Player を選択して [Inspector]ウィンドウで Health コンポーネントはこのように表示されています。

Health (体力)

スクリプトコンポーネントのフィールド設定を行います。

  1. [Hierarchy]ウィンドウ > Player を選択
  2. Health コンポーネント > Healthbar フィールドにオブジェクトForeground を割り当て
  3. オブジェクト Player を選択して[Inspector]ウィンドウ > [Apply]を適用
  4. シーンから Player ゲームオブジェクトのインスタンスを削除してシーンを保存

スクリプト Billboard を作成

体力ゲージが常にメインカメラ方向を向く処理を行うスクリプトを作成します。

  1. [Project]ウィンドウ > Player > Healthbar Canvas を選択
  2. [Inspector]ウィンドウ > [Add Component]ボタン > New Script を選択
  3. 新しいスクリプトを “Billboard” という名前で作成・追加
  4. スクリプト Billboard を開く
  5. 関数 Update 内に Healthbar が常にカメラを向くロジック追加

作成したスクリプトのコードにコメントを加えたものがこちら。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Billboard : MonoBehaviour {
    // ゲーム実行中の繰り返し処理
    void Update()
    {
        // メインカメラの方向に向くようにする
        transform.LookAt(Camera.main.transform);
    }
}

動作確認

  1. シーンをスタンドアロンのアプリケーションとして Build and Run を実行
  2. ゲーム内 UI から[Host]ボタンをクリックしてゲームをホストとして開始
  3. プレイヤーゲームオブジェクトを動かす
  4. Unity に戻ってPlay モードを開始
  5. ゲーム内 UI から[LAN Client]ボタンをクリックしてクライアントとしてホストに接続
  6. スタンドアロン プレイヤーを終了
  7. Unity に戻ってPlay モードを終了

このステップを終えてゲームを実行。今回はビルドしたゲームを2つ実行してウィンドウを並べました。ゆっくり互いに撃ち合ってみると体力ゲージは変化はほぼ同期しています。

しかし、チュートリアルの解説に書いてある通り、連射すると下図左側のローカル(ホスト)画面と右側のリモート(クライアント)画面で体力ゲージ表示が同期されていないことが確認できます。

corevale