This document is about: PUN 2
SWITCH TO

PUN Classic (v1)、PUN 2、Boltはメンテナンスモードとなっております。Unity2022についてはPUN 2でサポートいたしますが、新機能が追加されることはありません。お客様のPUNプロジェクトおよびBoltプロジェクトが停止することはなく、将来にわたってパフォーマンス性能が落ちることはありません。 今後の新しいプロジェクトについては、Photon FusionまたはQuantumへ切り替えていただくようよろしくお願いいたします。

5 - プレイヤーの構築

このセクションでは、このチュートリアルで使用するPlayer[プレハブ]を一から作成し、作成プロセスの全てのステップを説明します。

PUNが接続されていなくても動作するPlayer[プレハブ]を作成するのは、ちょっとしたテストやデバッグ、そしてネットワーク機能がない状態での動作確認をするのにいい方法です。
そこから構築を進めて修正を加え、それぞれの機能をネットワーク対応のキャラクターに合わせていきます。
通常、ユーザー入力は他のプレイヤーのコンピュータではなく、プレイヤーが所有するインスタンスでのみ有効にするべきです。
以下で詳細を説明します。

プレハブの基本

PUNについての最初に知るべきなのは、[プレハブ]がネットワーク上でインスタンス化されるためには、[Resource]フォルダの中になければいけないということです。

Resourcesフォルダ内に[プレハブ]を置くもう一つの重要な点は、その名前に注意が必要、ということです。
AssetのResourcesパス内の[プレハブ]の名前が重複してしまうと、Unityは最初に見つけたほうを選びます。Project Asset内のResourcesフォルダパス内でプレハブの名前が重複しないよう注意してください。後ほど詳細について説明します。

Unityが無料のアセットとして提供するKyle Robotを使用します。
これは、3ds Max、Maya、cinema 4D、likesなどの3Dソフトウエアで生成されるFbxファイルとして付属しています。
これらのソフトウエアを使用したメッシュやアニメーションの生成の仕方については、このチュートリアルでは割愛します。
Robot Kyle.fbxは、「*Assets\Photon\PhotonUnityNetworking\Demos\Shared Assets*」にあります。

Kyle Robot Fbx Asset
Kyle Robot Fbx Asset

プレイヤー向けにKyle Robot.fbxの使用を開始する一つの方法:

  1. 「Project Browser」のどこかに、「Resources」という名前のフォルダを作成します。通常は、コンテンツを組織することを推奨しているので'PunBasics_tutorial/Resources/' というような形になります。
  2. "PunBasics_tutorial\Scenes" に新しい空のシーンを作成し、Kyle Testとして保存します。
    「Kyle Test」シーンの目的は、プレハブを作成し、保存することです。
    一度処理が完了したら、このシーンは削除可能です。
  3. Robot Kyleを「Scene Hierarchy」にドラッグアンドドロップします。
  4. Hierarchyで生成したGameObjectの名前をMy Robot Kyleに変更します。
  5. My Robot Kyleを "PunBasics_tutorial\Resources" にドラッグアンドドロップします。

これでKyle RobotFbxアセットに基づく[プレハブ]の作成が完了し、そのインスタンスをシーンKyle TestのHierarchyの中に作成できました。
それでは作業を開始しましょう。

CharacterController

  1. CharacterController ComponentをHierarchyのMy Kyle Robotインスタンスに追加しましょう。
    直接[プレハブ]におこなうこともできますが、その場合は微調整をする必要が生じます。なのでここではより速い方法でおこないます。

    このコンポーネントは、Animatorを使った典型的なキャラクターの速い作成用にUnityから提供されるとても便利なStandard Assetです。このUnity機能を活用しましょう。
  2. My Kyle RobotをダブルクリックしてScene Viewをズームインします。「Capsule Collider」 が足にセンタリングしていることを確認してください。
    「Capsule Collider」は適切にキャラクターに合致させる必要があります。

  3. CharacterController ComponentCenter.yプロパティを1に変更します(Heightプロパティの半分です)。

    Kyle Robot Capsule Collider
    Kyle Robot Capsule Collider
  4. 「Apply」を押して変更を反映させます。
    プレハブMy Kyle Robotインスタンスの編集をしましたが、これらの変更を全てのインスタンスに加える必要があるので、これは非常に重要なステップです。このため、「Apply」を押しました。

    Apply Prefab Changes
    プレハブの変更を適用

Animatorの設定

Animator Controllerの割り当て

Kyle RobotFbx アセットはAnimator Graphで制御する必要があります。
このグラフについてはここでは割愛しますが、このためにコントローラーが提供されています。このコントローラーは \Assets\Photon\PhotonUnityNetworking/Demos/PunBasics-Tutorial/Animator/ 内のプロジェクトアセットにKyle Robotという名前で用意されています。

AnimatorController
AnimatorController

このKyle Robotコントローラーを[プレハブ]に割り当てるには、AnimatorコンポーネントのプロパティControllerKyle Robotを指すように設定するだけです。

Assigning AnimatorController
Assigning AnimatorController

以上のことをMy Kyle Robotのインスタンスでおこなう場合、これらの変更を[プレハブ]自体に組み込むため、「Apply」を押す必要があります。

コントローラパラメーターと連携

Animator Controllerに関して理解すべき重要な機能はスクリプトを経由して
アニメーションを制御するAnimation Parametersです。
今回のケースではSpeedDirectionJumpHiなどのパラメータがあります。

Animator Componentの素晴らしい機能の一つは、アニメーションに応じてキャラクターを動かせることです。この機能はRoot Motionと呼ばれ、Animator ComponentにはApply Root Motionというプロパティがあります。これはデフォルトでTrueになっていますので、そのまま使えます。

実際にキャラクターを歩かせるには、Speed Animation Parameterを正の値に設定します。そうすると、キャラクターが歩き始め、前に進みます。試してみましょう。

Animator Managerスクリプト

ユーザーの入力にもとづいて、文字を制御する新しいスクリプトを作成しましょう。

  1. PlayerAnimatorManagerという新しいc#スクリプトを作成します。

  2. [プレハブ]My Robot Kyleにこのスクリプトを添付します。

  3. 下記のようにNameSpaceのCom.MyCompany.MyGameでクラスを囲みます。

  4. わかりやすいようにリージョンMonoBehaviour CallBacksStart()Update()を囲みます。

    C#

    using UnityEngine;
    using System.Collections;
    
    namespace Com.MyCompany.MyGame
    {
        public class PlayerAnimatorManager : MonoBehaviour
        {
            #region MonoBehaviour Callbacks
    
            // Use this for initialization
            void Start()
            {
            }
    
            // Update is called once per frame
            void Update()
            {
            }
    
            #endregion
        }
    }
    
  5. スクリプトPlayerAnimatorManagerを保存します。

Animator Manager: 速度制御

始めにコーディングする必要があるのは、Animator Componentを制御するためのコードです。

  1. スクリプトPlayerAnimatorManagerを編集している点を確認してください。

  2. Animator型のプライベート変数animatorを作成します。

  3. Animator ComponentをStart()メソッドでこの変数内に格納します。

    C#

        private Animator animator;
        // Use this for initializationいつもコードを書くべきです。手間ですが、長い目で見るとそのほうがずっといいです。
        void Start()
        {
            animator = GetComponent<Animator>();
            if (!animator)
            {
                Debug.LogError("PlayerAnimatorManager is Missing Animator Component", this);
            }
        }
    

    Animator Componentを必須とするため、もしも取得ない場合には開発者がすぐに対処できるようエラーをログに記録します。
    コードを書くときは、常にほかの誰かによって使用されることを想定すべきです。手間はかかりますが、将来的に役立ちます。

  4. [ユーザー入力]にリッスンしてSpeed Animation Parameterを制御しましょう。そして、スクリプトPlayerAnimatorManagerを保存します。

    C#

    // Update is called once per frame
    void Update()
    {
        if (!animator)
        {
            return;
        }
        float h = Input.GetAxis("Horizontal");
        float v = Input.GetAxis("Vertical");
        if (v < 0)
        {
            v = 0;
        }
        animator.SetFloat("Speed", h * h + v * v);
    }
    
  5. スクリプトPlayerAnimatorManagerを保存します。

このスクリプトの役割を確認してみましょう:

このゲームで後方に進むことはできませんので、vは0未満にしてください。ユーザーが「ダウンキー」や「S」キー(Vertical軸のデフォルト設定)を押しても、この動作を許可せず、値は強制的に0になります。

両方の入力を二乗しているのはなぜだと思いますか?これは値を常に正の絶対値にして簡単にしておくためです。これは良い秘訣です。Mathf.Abs()も問題なく使用出来ます。

左または右の入力をした際方向転換の時に加速できるよう、Speedを制御するために両方の入力を追加します。

これは全て、キャラクターデザインに関することです。もちろん、ゲームロジックによって、キャラクターがその場で方向転換したり後方に進む場合などがあるので、Animation Parametersの制御は常に各ゲームに固有のものになります。

テスト、テスト、1 2 3...

ここまで行ってきたことを検証してみましょう。
Kyle Testシーンが開かれていることを確認してください。現在、このシーンにはカメラとKyle Robotインスタンスしかありません。ロボットが立つための地表がないので、今実行したらKyle robotは転んでしまうでしょう。
また、このシーン内では照明などの詳細が省略されています。キャラクターをテストして、スクリプトが正常に動作しているか検証をすることが目的だからです。

  1. シーンに「キューブ」を追加します。
    キューブにはデフォルトで「Box Collider」がついているのでそのまま床で使えます。
  2. キューブの高さが1なので、0,-0.5,0に配置します。キューブの上面が床に配置されるようにします。
  3. キューブを30,1,30にスケールし、実験の余地を残します。
  4. カメラを選択して全体を確認するためにカメラの距離をとります。
    一つのいいトリックとして、「Scene View」から好きなビューを取得し、カメラを選択してメニュー「GameObject/Align With View」に進み、カメラをシーンビューに合致させることです。
  5. 最後のステップとしてMy Robot Kyleのyを0.1上方向に動かします。そうしないと、衝突が抜けてしまい、キャラクターが床を通過してしまうので、シミュレーションが接触できるよう常にコライダーの間に物理的な空間を残してください。
  6. シーンを再生して「上矢印キー」もしくは「a」キーを押すと、キャラクターが歩きます!
    すべてのキーをテストして確認してください。

だいぶ進みましたが、まだ作業が必要です。まだカメラを追跡させる必要がありますし、方向転換ができません。

すぐにカメラの設定をしたい場合は、カメラの専用セクションに進んでください。このページではAnimator制御と回転の実装について説明します。

Animator Manager スクリプト: 方向制御

回転の制御は少し複雑です。左右のキーを押した際に、キャラクターが突然回転せず、滑らかに方向転換するのが目標です。ダンピングを使ってAnimation Parameterの設定が可能です。

  1. スクリプトPlayerAnimatorManagerを編集していることを確認してください。

  2. 新しいリージョン「Private Fields」リージョン内に浮動小数変数directionDampTimeを作成します。

    C#

    #region Private Fields
    
    [SerializeField]
    private float directionDampTime = 0.25f;
    
    #endregion
    
  3. Update()機能の最後に、以下を追加します:

    C#

    animator.SetFloat("Direction", h, directionDampTime, Time.deltaTime);
    

    animator.SetFloat() は異なる署名があります。
    Speed 制御のために使用している署名は簡単ですが、2つのパラメータを追加する必要があります。一つはdamping time、もう一つはdeltaTimeです。
    damping timeは希望する値に達するまでの時間なので、整合性があります。では、[delta time]とは何でしょう?
    delta timeはフレームレートから独立したコーディングを可能にします。Update()がフレームレートに依存するので、deltaTimeを使います。
    このトピックについてWebなどで調べてできるだけ理解を深めてください。
    このコンセプトを理解すると、アニメーションや制御機能最大限に活用できます。

  4. スクリプトPlayerAnimatorManagerを保存します。

  5. シーンを実行し、全ての矢印キーを押してキャラクターが歩き、方向転換することを確認します。

  6. directionDampTimeの効果をテストします。例として1を入力し、その後に5にして最大の回転能力に到達するまでの時間を確認します。
    回転の半径がdirectionDampTimeに応じて増加しています。

Animator Manager スクリプト: ジャンプ

ジャンプには、2つの理由からもう少し作業が必要です。1つは、プレイヤーが走っていないときにはジャンプさせないこと、そして2つめはジャンプをループさせないことです。

  1. スクリプトPlayerAnimatorManagerを編集していることを確認してください。

  2. Update()メソッドで、ユーザー入力を取得する前に以下を入力してください。

    C#

    // deal with Jumping
    AnimatorStateInfo stateInfo = animator.GetCurrentAnimatorStateInfo(0);          
    // only allow jumping if we are running.
    if (stateInfo.IsName("Base Layer.Run"))
    {
        // When using trigger parameter
        if (Input.GetButtonDown("Fire2"))
        {
            animator.SetTrigger("Jump");
        }
    }
    
  3. スクリプトPlayerAnimatorManagerを保存します。

  4. テストします。実行を開始し、「alt」キーを押すか、右クリックでKyleがジャンプします。

最初に理解するべきことはアニメーターが走っているかどうかをどう確認するかということです。これにはstateInfo.IsName("Base Layer.Run")を使用します。
Animatorの現在のアクティブ状態がRunかどうかを確認します。Run状態はBase Layerにあるので、Base Layerを追加する必要があります。

Run状態にある場合、Fire2 [入力]をリッスンして、必要に応じて Jumpトリガーを上げます。

以下は、これまでのところのPlayerAnimatorManagerスクリプトの全容です。

C#

using UnityEngine;
using System.Collections;

namespace Com.MyCompany.MyGame
{
    public class PlayerAnimatorManager : MonoBehaviour
    {
        #region Private Fields

        [SerializeField]
        private float directionDampTime = .25f;
        private Animator animator;

        #endregion

        #region MonoBehaviour CallBacks

        // Use this for initialization
        void Start()
        {
            animator = GetComponent<Animator>();
            if (!animator)
            {
                Debug.LogError("PlayerAnimatorManager is Missing Animator Component", this);
            }

        }

        // Update is called once per frame
        void Update()
        {
            if (!animator)
            {
                return;
            }
            // deal with Jumping
            AnimatorStateInfo stateInfo = animator.GetCurrentAnimatorStateInfo(0);          
            // only allow jumping if we are running.
            if (stateInfo.IsName("Base Layer.Run"))
            {
                // When using trigger parameter
                if (Input.GetButtonDown("Fire2"))
                {
                    animator.SetTrigger("Jump");
                }
            }
            float h = Input.GetAxis("Horizontal");
            float v = Input.GetAxis("Vertical");
            if (v < 0)
            {
                v = 0;
            }
            animator.SetFloat("Speed", h * h + v * v);
            animator.SetFloat("Direction", h, directionDampTime, Time.deltaTime);
        }

        #endregion
    }
}

この数行のコードにより、シーンで多くのことを実現できます。
次に、カメラが追跡できるようにするためにカメラの設定を行いましょう。

カメラ設定

この設定では、CameraWorkスクリプトを使用します。
スクラッチからCameraWorkを書く場合は、次のセクションで確認して、完了次第ここに戻ってきてください。

  1. My Kyle RobotプレハブにコンポーネントCameraWorkを追加します。
  2. プロパティFollow on Startをオンするとカメラが瞬時にキャラクターを追跡するようになります。
    ネットワーク実装を開始する際に、オフにします。
  3. プロパティ Center Offset0,4,0に設定して、カメラを高くします。こうすれば全体を映すことができ、カメラがプレイヤーをまっすぐ映した時のような無意味な地面の映しすぎを回避できます。
  4. シーンKyle Testを再生し、キャラクターを動かしてカメラが適切に追従しているか検証します。

PhotonViewコンポーネント

プレハブにPhotonViewコンポーネントをアタッチさせる必要があります。
A PhotonViewとは、各コンピュータの様々なインスタンスをつなぎ、度のコンポーネントを監視するか、またどのように監視するかを定義するものです。

  1. My Robot KylePhotonViewコンポーネントを追加します。
  2. Unreliable On ChangeObserve Optionを設定します。
  3. PhotonViewは、効果を表すには監視対象を設定する必要があると警告を表示します。
    チュートリアルの後半で監視コンポーネントの設定を行うので、今の時点では無視しておいても問題ありません。

ビーム設定

まだロボットキャラクターは武器を持っていません。目から発射するレーザービームを作成してみましょう。

ビームモデルの追加

簡単にするために、シンプルなキューブ四角形を使用して、かなり細長い形にスケールします。
これを手早く作成するテクニックを紹介します。Headの子として直接キューブを追加しないで、作成、移動、スケールアップしてから頭に添付します。目にビームを合わせるため、適切な回転値を推測することを防ぎます。

もう1つの重要なテクニックは、両方のビームで1つだけコライダーを使用することです。
これは物理エンジンの動作のためです。細長いコライダーは信頼性がなく、決して扱いやすいものではありません。なので、大きなボックスコライダーを作成し確実にターゲットを攻撃できるようにします。

  1. Kyle testシーンを開きます。
  2. シーンにキューブを追加し、Beam Leftと名付けます。
  3. 長いビームに見えるように修正し、左目に対して適切に配置します。
  4. My Kyle RobotインスタンスをHierarchyから選択します。
  5. Headの子を確認します。
Kyle Robot Head Hierarchy
Kyle Robot Head Hierarchy
6. `Head`GameObjectの子としてからのGameObjectを追加し、`Beams`と名付けます。 7. `Beams`内に`Beam Left`をドラッグアンドドロップします。 8. `Beams Left`を複製し、`Beams Right`と名付けます。 9. 右目に会うように配置します。 10. `Beams Right`からボックスコライダーコンポーネントを削除します。 11. `Beams Left`'の「Box Collider」中心とサイズを調整して両方のビームをカプセル化するようにします。 12. `Beams Left`の「Box Collider」の`IsTrigger`プロパティを`True`に変更し、ビームが衝突した際ではなく、プレイヤーに接触した場合にのみ通知を受けるようにします。 13. 新しいマテリアルを作成し、`Red Beam`と名付けます。その後、'DemoAnimator_tutorial/Scenes/'に保存します。 14. `Red Beam`マテリアルを両方のビームに割り当てます。 15. プレハブにも変更を適用します。

注:レーザービームは、自身を傷つけないようキャラクターのコライダーの外側に設定する必要があります。

これで以下のようになっているはずです。

Kyle Robot Beams
Kyle Robot Head Beams
Kyle Robot Updated Head Hierarchy
Kyle Robot Updated Head Hierarchy

ユーザー入力でビームを制御

これでビームがで完成しました。次に、それをトリガーするためのFire1入力をつなぎましょう。

新しいC#スクリプトを作成し、PlayerManagerと呼びます。
以下はビームを作動させるためのの完全なコードです。

C#

using UnityEngine;
using UnityEngine.EventSystems;

using Photon.Pun;

using System.Collections;

namespace Com.MyCompany.MyGame
{
    /// <summary>
    /// Player manager.
    /// Handles fire Input and Beams.
    /// </summary>
    public class PlayerManager : MonoBehaviourPunCallbacks
    {
        #region Private Fields

        [Tooltip("The Beams GameObject to control")]
        [SerializeField]
        private GameObject beams;
        //True, when the user is firing
        bool IsFiring;
        #endregion

        #region MonoBehaviour CallBacks

        /// <summary>
        /// MonoBehaviour method called on GameObject by Unity during early initialization phase.
        /// </summary>
        void Awake()
        {
            if (beams == null)
            {
                Debug.LogError("<Color=Red><a>Missing</a></Color> Beams Reference.", this);
            }
            else
            {
                beams.SetActive(false);
            }
        }

        /// <summary>
        /// MonoBehaviour method called on GameObject by Unity on every frame.
        /// </summary>
        void Update()
        {

            ProcessInputs();

            // trigger Beams active state
            if (beams != null && IsFiring != beams.activeInHierarchy)
            {
                beams.SetActive(IsFiring);
            }
        }

        #endregion

        #region Custom

        /// <summary>
        /// Processes the inputs. Maintain a flag representing when the user is pressing Fire.
        /// </summary>
        void ProcessInputs()
        {
            if (Input.GetButtonDown("Fire1"))
            {
                if (!IsFiring)
                {
                    IsFiring = true;
                }
            }
            if (Input.GetButtonUp("Fire1"))
            {
                if (IsFiring)
                {
                    IsFiring = false;
                }
            }
        }

        #endregion
    }
}

この段階での当スクリプトの主なポイントはビームを有効化・無効化することです。
有効化した場合は、他のモデルで衝突が発生したときにビームが効果的にトリガーします。このため、各キャラクターの体力に影響を与える目的で、後にこれらのトリガーを取得します。

My Kyle RobotプレハブのHierarchy内でGameObjectを正確に参照できるパブリックプロパティBeamsを公開しました。
では、Beamsの接続方法を説明します。Assetsブラウザではプレハブは最初の子しか表示せず、サブチャイルドを表示しないのでBeamsがプレハブ階層で埋もれてしまいます。そのため、シーンのインスタンスから行い、プレハブ自体に適用して戻す必要があります。

  1. Kyle testシーンを開きます。
  2. シーンHierarchy内でMy Kyle Robotを選択します。
  3. My Kyle RobotPlayerManagerコンポーネントを追加します。
  4. インスペクター内のPlayerManager Beamsプロパティに My Kyle Robot/Root/Ribs/Neck/Head/Beamsをドラッグアンドドロップします。
  5. プレハブに戻ってインスタンスからの変更を適用します。

これでPlayを選択しFire1 Inputを押す(デフォルトで左クリックか左のctrlキーです)と、ビームが現れ、手を離すとすぐに消えます。

体力の設定

ビームがプレイヤーに当たったときに体力が減少する非常に単純なシステムを実装してみましょう。
弾丸ではなく、一定のエネルギーの流れなので、二方向で体力への影響を考える必要があります。ビームが当たった時と、ビームが当たっている間のダメージです。

  1. PlayerManagerスクリプトを開きます。

  2. Public Fieldsリージョン内にパブリックHealthプロパティを追加します。

    C#

    [Tooltip("The current Health of our player")]
    public float Health = 1f;
    
  3. 以下の2つのメソッドを MonoBehaviour Callbacksリージョンに追加します。そのあとでPlayerManagerスクリプトを保存します。

    C#

    /// <summary>
    /// MonoBehaviour method called when the Collider 'other' enters the trigger.
    /// Affect Health of the Player if the collider is a beam
    /// Note: when jumping and firing at the same, you'll find that the player's own beam intersects with itself
    /// One could move the collider further away to prevent this or check if the beam belongs to the player.
    /// </summary>
    void OnTriggerEnter(Collider other)
    {
        if (!photonView.IsMine)
        {
            return;
        }
        // We are only interested in Beamers
        // we should be using tags but for the sake of distribution, let's simply check by name.
        if (!other.name.Contains("Beam"))
        {
            return;
        }
        Health -= 0.1f;
    }
    /// <summary>
    /// MonoBehaviour method called once per frame for every Collider 'other' that is touching the trigger.
    /// We're going to affect health while the beams are touching the player
    /// </summary>
    /// <param name="other">Other.</param>
    void OnTriggerStay(Collider other)
    {
        // we dont' do anything if we are not the local player.
        if (! photonView.IsMine)
        {
            return;
        }
        // We are only interested in Beamers
        // we should be using tags but for the sake of distribution, let's simply check by name.
        if (!other.name.Contains("Beam"))
        {
            return;
        }
        // we slowly affect health when beam is constantly hitting us, so player has to move to prevent death.
        Health -= 0.1f*Time.deltaTime;
    }
    

    PlayerManagerMonoBehaviourPunCallbacksを拡張します。
    MonoBehaviourPunCallbacksMonoBehaviourPunを拡張します。
    MonoBehaviourPun には photonView プロパティがあり、'lazy initialization' が設定されています。
    このようにして、photonViewPlayerManagerに含まれます。

  4. PlayerManagerスクリプトを保存します。

2つのメソッドはほとんど同じですが、TriggerStayの場合はフレームレートに減少速度を依存させないよう、Time.deltaTimeを使用して体力を減少させます。
これは通常アニメーションに適用する概念ですが、この場合はすべての端末で予測可能な方法で体力を減少させるために使用します。速いコンピューター上では体力の減少も速くなってしまったら公平ではないからです。
Time.deltaTimeは一貫性を保証するためにあります。
Time.deltaTimeに関するご質問がありましたらお問い合わせください。また、概念を理解するためにUnityコミュニティを検索することをお勧めします。

理解するべきである二つ目の重要な側面は、ローカルプレイヤーの体力にのみ影響を与えるべきだということです。そのため、メソッドから早く出ます。PhotonViewはMineではありません。

最後に、プレイヤーに当たるObjectがビームである場合のみ体力に影響を与えるようにします。

デバッグを容易におこなうため、Health浮動小数はパブリック浮動小数となっています。これは、UIが構築されるのを待つ間に簡単に値を確認できるようにするためです。

だいぶ完成に近づきましたが、プレイヤーの体力がゼロになりゲームオーバー状態になるまで体力システムは完全ではありません。 この設定をおこないましょう。

ゲームオーバーのための体力確認

単純化するため、プレイヤーの体力が0に達したときはルームから退室します。既にGameManagerスクリプトでルームを退出するメソッドを作成しています。
同じ機能のために再びコーディングをするのではなく、同じメソッドを利用できるのが理想的です。どのような場合も、同じ結果を生じるコードの重複は避けるべきです。
ここで、「Singleton」という便利なプログラミングの概念を紹介します。
「Singleton」そのものは全て説明すると長くなるので、今は最小限の実装のみ行います。
SingletonのUnityコンテキスト内での変化や、有効な機能を作成する方法などを理解すると非常に便利です。
このチュートリアルだけでなく、Singletonについて勉強することをお勧めします。

  1. GameManagerスクリプトを開きます。

  2. この変数をPublic Fieldリージョンに追加します。

    C#

    public static GameManager Instance;
    
  3. Start()メソッドを下記のように追加します。

    C#

    void Start()
    {
        Instance = this;
    }
    
  4. GameManagerスクリプトを保存します。

Instance変数に[静的な]キーワードを実装した点に留意してください。つまり、GameManagerのインスタンスにポインタを保持しなくても、この変数を使用することができます。
結果としてコード内のどこからでもGameManager.instance.xxx()を実行でき、
非常に効率的です。
上記が、このゲームのロジック管理の点にどのように合致するかをみてみましょう。

  1. PlayerManagerスクリプトを開きます。
  2. Update()メソッド内でProcessInputsを行った後、以下を追加してPlayerManagerスクリプトを保存します。

    C#

    if (photonView.IsMine)
    {
        ProcessInputs();
        if (Health <= 0f)
        {
            GameManager.Instance.LeaveRoom();
        }
    }
    
  3. PlayerManager スクリプトを保存します。

*注:レーザービームによるダメージの強度は一定ではないので、体力が負の数値になり得ることを考慮します
*注:実際にコンポーネントなどを入手することなく、GameManagerインスタンスのLeaveRoom()パブリックメソッドに到達します。
現在のシーンで、GameObjectにGameManagerコンポーネントが存在するという仮定にもとづいています。

OK, now we are diving into networking!

次のセクション.
前のセクション.

Back to top