Unityでキャラクター毎に自分のステータスを保持する機能

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

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

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

ステータス1


ステータス2

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

private var status : MyStatus;

まずはステータススクリプトを入れる変数の宣言を加えます。

status = GetComponent(MyStatus);

Start関数内でステータススクリプトを取得します。

Update関数内でキーの1が押され、かつ主人公の状態がattackとdamageの状態でない時に装備を変更していますが、変更後にステータススクリプトの装備品のデータを更新しています。

武器の変更が出来るのは攻撃をしている時、ダメージを受けている時、以外の時になります。

また、初期状態でステータスから装備品の取得を行う為にGetEquip関数を作っておきます。
これでChangeEquipスクリプトの修正が完了しました。

スポンサーリンク

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

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

HPや装備品をキャラクターのステータスとして宣言します。
changeE変数はスタート時の装備品を設定する時に必要になるので宣言しています。
Start関数内でChangeEquipスクリプトを取得とパラメータの初期化を行っておきます。

次に他のスクリプトからステータスを取得したい時の為にSetterとGetterを用意しておきます。
これらの関数は値の設定と取得だけをする為の関数です。

これで自分のステータスを保持するスクリプトが完成しました。

敵キャラにもMyStatusを設定

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

attackPowerは敵キャラの攻撃力です。
hpとattackPowerはインスペクタで設定出来るようにしています。

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

MoveEnemyスクリプト内では自身のステータスを取得する為の変数を宣言し、主人公から攻撃を受けた時に実行する関数NockBack内で自身のhpを減らす為ステータススクリプトを使います。

status.SetHp(status.GetHp() – 1);

これでステータスのhpの値を設定出来ます。
またDead関数では

上のようにアニメーションパラメータのDeathをOnにしています。

アニメーターにDeath状態と遷移を作成する

ステータス3

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

ステータス4

Has Exit Timeにチェックを入れて他の条件にかかわらず最後までアニメーションを再生させます。

ステータス5

Deathアニメーションにはアニメーションイベントを作成し、アニメーションの最後にDeadEndというイベントを作ります。

アニメーションはAsset Store→3D モデル→キャラクター→人型→Cyclop_Soldier
をインポートしました。

敵キャラはアニメーションイベントをProcessAttackで受け取っているのでそこにDeadEnd関数を作ります。

DeadEndイベントを受け取ったら自身(スクリプトを設定しているオブジェクト)を削除します。

これでプレハブからインスタンス化した敵キャラの削除が完成します。

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

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

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

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

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

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

private var wStatus : WeaponStatus;

と武器のステータスを保持する変数を宣言し、Start関数内でWeaponStatusを取得します。

装備品の取得が完了したら、その装備品のステータスを取得しwStatusに入れておきます。

SetEquipでも

装備品の変更をするので、変更が終わったら再度その武器のステータスに切り替えます。

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

とGetAttackPower関数とGetWeaponStatus関数を作ります。今回は武器のみの攻撃力をそのまま返していますが、主人公自身の体の強さと武器の強さを合わせてダメージとする場合もここで調整出来ます。

敵キャラのNockBack関数内でダメージを1と固定していた部分を変更します。
NockBack関数で受け取る引数を変更します。

function NockBack(player : GameObject, pos : Transform, type : String) {

第1引数は主人公ゲームオブジェクト、第2引数は接触した位置、第3引数は攻撃の種類を文字列で受け取ります。

攻撃の種類が設定されていない時は通常の打撃攻撃、何か設定されていれば遠距離攻撃とします。

1と書いていた場所を主人公キャラに設定してあるMyStatusの攻撃力にします。
これで主人公キャラの攻撃力分が敵の体力から引かれる事になります。

Update関数の実行順序でエラー!?

さて、ここまででもしかしたら何かしらのエラーが出ているかもしれません。
スクリプトの順番によってコンポーネントが取得出来ていない個所が出る為です。

そこでEdit→Project Settings→Script Exection Orderを選択し、

ステータス6

上のようにChangeEquip、MyStatusをDefault Timeより早く実行させます。
装備品の設定→自分のステータス→その他のスクリプトという流れにしたい為です。

今までStart関数内でコンポーネントの取得をしていますが、他のコンポーネントの取得をしなければAwake関数で行った方がようさそうです・・・・。そうすればスクリプトの実行順を考慮しなくてもいい場合が増えそうです。
いずれ修正するかもしれません。

これでキャラクター自身に自分のデータを持たせる事が出来るようになりました。
実際に敵を攻撃し、敵が倒れる様子や、武器の強さを変更して試してみてください。

コメント

  1. moguri より:

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

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

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

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

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