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

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

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

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

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

ステータス1

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

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

myStatusフィールド宣言と武器の親のTransformを指定するフィールドの宣言、Startメソッド内でコンポーネントの取得部分を追加します。

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

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

最後にMyStatusスクリプトのSetEquipメソッドで切り替えた武器を渡します。

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

スポンサーリンク

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

あとはMyStatusスクリプトを作っていきます。

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

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

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

敵キャラにも同じようにスクリプトを設定して、HPが0になったら消えるようにしてみましょう。

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

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

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

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

hpのSetterとGetterを用意し、自身の持つhpが0以下になったら敵キャラ処理スクリプトのEnemyにDeadメソッドを実行させます。

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

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

TakeDamageでは敵が死んだ状態でない時だけダメージ処理を行う事にします。

これでステータスのhpの値を設定出来ます。

またDeadメソッドでは

SetStateでEnemyState.Dead状態に変更し、アニメーションパラメータのDeadをOnにしています。

Deadメソッドは敵が死んだ時に呼ばれるので、Destroyを使って3秒後にゲームオブジェクトを削除します。

敵が死んだ時に敵のCharacterControllerを無効化して当たり判定を消してしまうのもいいかもしれません。

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

状態フィールドを変更し、移動値を初期化しているだけです。

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

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

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

敵のDead状態を作成する

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

敵のDead状態への遷移条件

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

敵キャラはアニメーションイベントをProcessAttackのEndDamageメソッドで敵の状態をwaitへと遷移させていましたが、この処理を削除します。

EndDamage自体は使っているアニメーション(主人公と共有している)でアニメーションイベントを設定しているのでイベントだけ受け取り処理は何もしません。

ダメージを受けてから何もしていない状態へと遷移させるとDead状態との兼ね合いからおかしくなる為やめました。

いちおう完成しましたが、敵キャラが攻撃を受けた時に一律でダメージは1と設定してます。
これでは武器を変更しても必ずダメージは1となってしまうので、後々問題になるはずです。

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

各種ステータスの設定

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

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

武器のWeaponStatusの設定

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

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

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

敵のステータスの設定

終わりに

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

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

2017/12/27に全面的に修正(ほぼ全部変わってるような・・・)したので元々の処理からだいぶ変わりました。

ブログ当初の徐々に機能を作成していくというコンセプト(大げさ!)に則って修正しているので、前の記事の内容から逸脱しないようにするのが大変です・・・(^_^;)

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

スポンサーリンク

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

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

コメント

  1. 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なんです(^_^;)
          英語が出来ないのでなるべく単語を調べてから書いてるんですが、適当感がでちゃってますね・・・。

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