Unityでキャラクターや武器のステータスを保持する機能

今回は今までそれぞれのスクリプトで制御していた(武器だけですが・・・)キャラクターに関するパラメータをパラメータスクリプトを作ってそこで管理し、必要に応じてそこからデータを取得し利用するようにしてみます。

今回の機能は以前作成した機能に処理を追加するので、以前作成した機能を知りたい方は

Unityを使った3Dゲームの作り方(かめくめ)で、はじめてUnityの学習をする時の当ブログの記事を読む順番を書きました。機能を積み上げていく形になるので便利かも?

から機能作成の流れを確認してみてください。

↑のような感じになります。

前回作ったChangeEquipですがさっそく改良する必要が出ました。(^_^;)

まずはスクリプトを追加するオブジェクトを変更します。
今までEquipというオブジェクトに設定していましたが、主人公のroot、わたしの場合は「masasi」君に設定します。

ステータス1

ChangeEquipスクリプトをキャラクターのルートに設定

配置する位置を変更した事で、スクリプト内の処理にも変更を加えます。

myStatusフィールド宣言と武器の親のTransformを指定するフィールドの宣言を追加します。

ChangeEquipスクリプトを設定するゲームオブジェクトを変えたので、今装備している武器を削除する処理ではtransformの代わりにequipTransformを指定します。

武器をインスタンス化する時の親もequipTransformにします。

最後にMyStatusスクリプトのSetEquipメソッドで切り替えた武器を渡します(現時点ではMyStatusスクリプトを作成していない為エラーになります)。

これでChangeEquipスクリプトの修正が完了しました。

スポンサーリンク

キャラクターのステータス保持スクリプトMyStatusの作成

主人公キャラクターのステータス管理を行うMyStatusスクリプトを作っていきます。

キャラクターのHPと装備している武器の情報を保持しているだけです。

今回はMyStatusは特に使わないので適当な感じです・・・(^_^;)

敵キャラ用のステータススクリプトの作成

敵キャラにも同じようにステータスを管理するスクリプトを設定してみましょう。

主人公も敵キャラも同じようなステータスを持つので共通のHPや攻撃力等をStatusクラスとして作っておき、それを継承してそれぞれのクラスを作った方がいいと思いますが、

個別に作ってしまいます・・・・(^_^;)

EnemyStatusスクリプトを作成します。

hpとattackPowerはインスペクタで設定出来るようにしています。

hpのSetterとGetterを用意します。

敵の操作をするEnemyスクリプト内では自身のステータスを取得する為のフィールドを宣言し、主人公から攻撃を受けた時に実行するTameDamageメソッド内で自身のhpを減らす為にステータススクリプトを使います。

追加分だけを記述しているので、他の処理に追加してください。

敵が死んだときの状態をEnemyStateに追加しています。

TakeDamageではEnemyStatusスクリプトが保持しているHPからダメージ分を減らし、敵のHPが0以下になったらDeadメソッドを呼び出します。

Deadメソッドでは

SetStateでEnemyState.Dead状態に変更しています。

SetStateメソッドの処理にDeadの処理を追記します。

アニメーションパラメータ―のDeadをトリガーして3秒後に敵自身のゲームオブジェクトを削除します。

敵のAnimatorControllerにDead状態と遷移を作成する

敵のAnimatorControllerにDead状態を作成します。

アニメーションパラメータにTrigger型のDeadを作成します。

敵のDead状態を作成する

敵キャラのアニメーターではDeadという状態を作りAny StateからDeadがトリガーされた時に遷移するようにします。

敵のDead状態への遷移条件

SettingsのCan Transition To Selfのチェックを外しDead状態からDead状態へと遷移しないようにします。

いちおう完成しましたが、敵キャラが攻撃を受けた時に一律でダメージは1に設定してます。

これでは武器を変更しても必ずダメージは1となってしまうので、後々問題になるはずです。

武器のステータス管理スクリプトを作成する

武器固有で攻撃力を保持するようにして、そこから値を取得するようにします。
WeaponStatusというスクリプトを作り武器のプレハブにスクリプトを設定します。

WeaponStatusの中身は攻撃力を保持し、値を返すメソッドが宣言されているだけになります。

attackPowerは打撃武器として使用した時の力
shotPowerは遠距離攻撃として使用した時の力
weaponTypeは武器の種類。
weaponRangeは遠距離攻撃の武器の射程距離

を表します。次にMyStatusのスクリプトを変更します。

自身の力と武器のステータスを保持するフィールドを宣言します。

武器のステータスはSetEquipメソッドが呼ばれた時に設定します。

また敵キャラに与えるダメージを計算する為に

主人公自身の力と武器の力を合わせたものを返してダメージとします。

剣に設定したAttackSwordスクリプトを変更します。

剣が敵に当たったら敵の状態がDamage、Dead状態でない時にダメージを与えます。

主人公キャラのステータスMyStatusからGetAttackPowerでダメージ力を取得し、敵のTakeDamageメソッドを呼び出す時に渡します。

敵キャラのTakeDamageメソッド内でダメージを1と固定していた部分を変更します。

ダメージ値を引数として受け取るようにし、1と書いていた場所を主人公キャラに設定してあるMyStatusの攻撃力にします。

これで主人公キャラの攻撃力分が敵の体力から引かれる事になります。

主人公の力を考慮しなくていい場合はAttackSwordスクリプトとWeaponStatusが武器に設定されているので、そこから直接WeaponStatusの攻撃力を取得しても良さそうですね。

敵の攻撃判定用コライダのオフ

最後に一つ修正を加えます。

敵が攻撃中にダメージを受けた場合、アニメーションイベントのAttackEndが呼ばれる前にDamage状態へと遷移してしまい、手の攻撃用のコライダがオフにならない事があります。

これはアニメーターのビヘイビアを使うと出来ますが、まだやっていないので、ダメージを受けた時に手のコライダをオフにする処理を加えます。

Enemyスクリプトに処理を追加します。

手のコライダをインスペクタで設定しておき、TakeDamageメソッドが呼ばれたら手のコライダをオフにするようにします。

各種ステータスの設定

機能を作り終えたのでステータスの設定をします。

まずは武器毎に設定するWeaponStatusの設定です。

武器のWeaponStatusの設定

上の画像ではWeaponTypeを文字列で設定していますが、列挙型に変更したので選択式で選択出来ます。

次に主人公に設定するMyStatusの設定です。

主人公のステータスの設定

最後に敵キャラクターに設定するEnemyStatusの設定です。

敵のステータスの設定

終わりに

これでキャラクターや武器に自分のデータを持たせる事が出来るようになりました。

実際に敵を攻撃し、敵が倒れる様子や、武器の強さを変更して試してみてください。

主人公側のダメージ処理はやっていませんが・・・同じような感じで出来ると思いますのでやってみてください。

スポンサーリンク

記事をシェアして頂ける方はこちら

フォローして頂くとやる気が出ます

コメント

  1. 匿名 より:

    記載道理にしているのですが、そもそもキャラクターの攻撃で敵の体力が減りません。
    敵のダメージアクションは動いているのですが、敵の体力が減らないため、倒れません。

  2. moguri より:

    MoveEnemyスクリプトのNockBack関数の引数を
    function NockBack(player : GameObject, pos : Transform, type : String) {
    に変えたところまでは分かったのですが
    playerの部分に主人公のGameObjectを引数として与えるにはどうしたらいいですか?
    また、typeの部分はnullでいいのでしょうか?

    • えーと昔のスクリプトを見てみると(すっかり忘れているので・・)。
      (このスクリプト名ってKnockBackが正しいんじゃなかろうか・・・(謎))

      第1引数では主人公キャラクターのゲームオブジェクトを受け取り、第2引数で当たった部位、第3引数は主人公が攻撃した手段を文字列で渡しているようです。
      NockBack関数は主人公が敵を攻撃した時に呼び出す関数なので

      https://gametukurikata.com/program/charaattackenemy

      で記載している通り武器に相手方検出スクリプトを取りつけ呼び出します。

      剣が敵と接触していたら↑のような感じでキャラクターのゲームオブジェクト、接触した場所、攻撃の種類をわたします。
      キャラクターのゲームオブジェクトを渡しているのは主人公のステータスを取得する為です。
      剣の↑のスクリプトが設定されている部分からtransform.rootでキャラクターのtransformを取得出来ます(剣のルートがキャラクターなので)。
      またtransform.gameObjectでtransformからゲームオブジェクトが取得できるので

      transform.root.gameObjectでキャラクターのゲームオブジェクトが取得出来ます。

      ↑の例ではtypeにnullを渡していますが、例えば剣で攻撃したのであれば”Sword”、銃であれば”Gun”等と文字列(自分で勝手に付けた名前)を渡して攻撃の種類を渡しています。
      武器の種類によって敵を下げる方向を変える為にこのtypeを作ったんだと思います。

      typeはNockBack関数内で処理を分ける為に使用する単なる文字列だと思います。
      剣なら主人公が向いている方向に下げ、銃なら銃口の先に下げるという感じです。

      でも武器の種類ならばplayerからGetComponentでステータススクリプトを取得してそこから武器の種類も得られるのでいらないっちゃいらないですね・・・。
      武器の種類を識別する為に渡すだけなのでこの引数自体を無くしても問題はなさそうです。

      剣と銃口の先で敵を下げる時の処理を分けていたんですが、どういう違いが出たのか今となっては謎です。

      • moguri より:

        お答えいただいてありがとうございます。
        KnockBackに関しては単純にスペルミスでした。

        • いえいえ・・・わたくしのソースコードがすでにNockBackなんです(^_^;)
          英語が出来ないのでなるべく単語を調べてから書いてるんですが、適当感がでちゃってますね・・・。

          英語が出来ればもっとプログラミングも楽しくなるだろうなぁ・・・・(-.-)