【Unity2d】攻撃アニメーション実行の再実装

Unity2D

Unity2D ARPG

こんにちは。なおキーヌです。

ブログ毎日更新は344日目になります。

だいぶ進捗が遅れています。

本来はステージ作ってるはずなんですがね(笑)

ウダウダ言ってても仕方ないのでさっさと作っていきましょう!

やっとこさ押す引く処理の再実装が完了したのでお次は攻撃処理です。

まずは攻撃処理の再実装ですね。

アクションスクリプトに攻撃処理を作成

攻撃用のスクリプトを作ろうと思ったのですが、今回はそこまで攻撃を複雑にするつもりはないので
Action系のスクリプトで実装していきます。

とりあえずZキーを攻撃にして武器を振るところまでやってみましょう。

    // キーチェック関数
    private void KeyCheck() {
        // 十字(上下左右)
        KeyAddRemove(KeyCode.LeftArrow);
        KeyAddRemove(KeyCode.RightArrow);
        KeyAddRemove(KeyCode.UpArrow);
        KeyAddRemove(KeyCode.DownArrow);

        // 攻撃(Z)
        KeyAddRemove(KeyCode.Z);

        // 掴み(G)
        KeyAddRemove(KeyCode.G);
        // 防御(S)
        KeyAddRemove(KeyCode.S);
        // 回避(D)
        KeyAddRemove(KeyCode.D);
    }

ひとまずController_PlayerでZキーを押せるようにします。

次にZキーを押されて居たらステートを2に変更するようにします。

  // 押しているキーによってステートを変更
  protected void setState(List<KeyCode> keyList, List<KeyCode> arrowDirect) {
    // 省略

    // 攻撃状態にする
    if (keyList.Contains(KeyCode.Z)) {
      _actState = 2;
    }

    // 省略
  }

攻撃モーション中は基本的に何もしないようにしたいです。

攻撃中に防御に遷移したりするとヌルゲーになりそうですし、基本的に武器を振り終わるまでは
攻撃判定以外は無防備になっておかないとあまり面白くなさそうですね。

とりあえず攻撃モーションに切り替えます。

  // アニメーション変数設定
  protected void setNowAnim(Animator animator) {

    // アニメーション切り替え
    switch(_actState) {
      // 停止状態
      case 0:
        _switchDirectAnim(0, 10, 20, 30);
        break;
      // 歩行状態
      case 1:
        _switchDirectAnim(1, 11, 21, 31);
        break;
      case 2:
        _switchDirectAnim(2, 12, 22, 32);
        break;
      case 5:
        _switchDirectAnim(5, 15, 25, 35);
        break;
      default:
        break;
    }
    // アニメーションの設定
    animator.SetInteger("AnimIdx",_nowAnim);
  }

これで切り替えられるようになったのですが、どうやらsetDirection関数のdefaultで-1にしようとしてたのが悪さしてたようで
defautlは何もなしにbreakで変化しないようにしました。

  // 向き変数変更
  protected void setDirection(List<KeyCode> arrowDirect) {
    // 指定のステートの場合は何もしない
    if (_actState >= 5 && _actState <= 7 || _actState == 106 || _actState == 107) {
      return;
    }

    // 押されているキーが2つ以上あるか調べる
    bool flag = arrowDirect.Count > 1;


    switch(arrowDirect[0]) {
      case KeyCode.DownArrow:
        _direction = 0;
        if(flag) {
          switch (arrowDirect[1]) {
            case KeyCode.LeftArrow:
              _direction = 10;
              break;
            case KeyCode.RightArrow:
              _direction = 20;
              break;
          }
        }
        break;
      case KeyCode.UpArrow:
        _direction = 1;
        if(flag) {
          switch (arrowDirect[1]) {
            case KeyCode.LeftArrow:
              _direction = 11;
              break;
            case KeyCode.RightArrow:
              _direction = 21;
              break;
          }
        }
        break;
      case KeyCode.LeftArrow:
        _direction = 2;
        if(flag) {
          switch (arrowDirect[1]) {
            case KeyCode.DownArrow:
              _direction = 12;
              break;
            case KeyCode.UpArrow:
              _direction = 22;
              break;
          }
        }
        break;
      case KeyCode.RightArrow:
        _direction = 3;
        if(flag) {
          switch (arrowDirect[1]) {
            case KeyCode.DownArrow:
              _direction = 13;
              break;
            case KeyCode.UpArrow:
              _direction = 23;
              break;
          }
        }
        break;
      default:
        break;
    }

  }

現状だとZキーを押し続けないと攻撃モーションが全部終わらないので、
攻撃状態になったらモーションが終わるまで固定化しておきたいですね。

ちょっと処理の流れ考えてみましょう。

  • zキーを押す
  • 攻撃モーションの開始
  • 攻撃モーション中は方向転換が出来ない
  • 攻撃モーション中はキー入力が無効

方向転換が出来ないはグリッド移動の時と同じでいけそうですね。

一度Stateが2になったら後はアニメーション終了時のイベント通知でステートを元に戻すといった感じがベストそうです。

ステート変化の禁止をしておけばキー入力無効みたいな状態になるのでこれでいきましょう。


  // 向き変数変更
  protected void setDirection(List<KeyCode> arrowDirect) {
    // 指定のステートの場合は何もしない
    if (_actState == 2 || _actState >= 5 && _actState <= 7 || _actState == 106 || _actState == 107) {
      return;
    }
  }


  // 押しているキーによってステートを変更
  protected void setState(List<KeyCode> keyList, List<KeyCode> arrowDirect) {
    // 行動ちゅうであれば抜ける
    if ( _actState == 2 || _actState == 106 || _actState == 107) {
      return;
    }
  }

この2つを適用すれば攻撃を1回押せばちゃんと最後までモーションがでるようになります。

しかし解除がまだできていないので固まってしまいます。

アニメーション終了通知は過去にやっているのでそれを流用して適用していきましょう。

過去に書いたコードはこんな感じでした

    private void PlayerAttack() {
        // 攻撃中かどうかを見る
        if (nowAnim%10 == 2) {
            // 攻撃モーションが終わっているかどうか
            if(animator.GetCurrentAnimatorStateInfo(0).normalizedTime>1) {
                // 初回攻撃モーションかつボタンカウントが5以上か調べる
                if(!isAttack && AttackPressCount > 5) {
                    // Trueなら次の攻撃モーションに切り替え
                    isAttack = true;
                    animator.SetInteger("AnimIdx",nowAnim);
                } else {
                    // アニメーションが終わったら後処理
                    //---------------------------------------------
                    // 1桁目を取り出してそれを引くことで向いてる方向のスタンド状態にする
                    nowAnim = nowAnim - nowAnim%10;
                    // アタックカウントをリセット
                    AttackPressCount = 0;
                    // アタック中フラグを解除
                    isAttack = false;
                    // それぞれのアニメーションをセット
                    animator.SetInteger("AnimIdx",nowAnim);
                    animator_hammer.SetInteger("AnimIdx",nowAnim);
                }
            }
            // 攻撃モーションが終わってなければZキー監視
            if(Input.GetKey(KeyCode.Z)) {
                // 攻撃ボタンカウントを溜める
                AttackPressCount++;
            }

        } else {
            // スタンドか移動中の場合
            if (nowAnim%10 == 0 || nowAnim%10 == 1 ) {
                // 攻撃中じゃない状態でZキーが1回押されたら
                if(Input.GetKeyDown(KeyCode.Z)) {
                    // 向いてる方向に対して攻撃モーションを適用
                    //---------------------------------------------
                    // 初回攻撃にモーション変更
                    nowAnim = (nowAnim - nowAnim%10) + 2;
                    // アニメーションのセット
                    animator.SetInteger("AnimIdx",nowAnim);
                    // ハンマーも動かす
                    animator_hammer.SetInteger("AnimIdx",nowAnim);
                }
            }
        }

    }

この中で使えそうなのが

animator.GetCurrentAnimatorStateInfo(0).normalizedTime>1

これですね。

ということはアニメーターを取得出来ればなんとかなりそうです。

Stateスクリプトでは「setNowAnim」関数でアニメーターを受け取ってますね。

ココで処理して終わったらアニメーションを元に戻すという処理を組み込んでみましょう。

まずはグリッド終了時と同じく攻撃アニメーション終了関数を作ります。

とりあえずバグ発生も備えてprivateにしておきましょう。

  // 攻撃アニメーション終了関数
  private void endAttackAnim() {
    _actState = 0;
  }

これを利用して「setNowAnim」関数を調整します。

  // アニメーション変数設定
  protected void setNowAnim(Animator animator) {
    // 省略


    // 攻撃アニメーションが終わったかどうかの監視
    if (_actState == 2) {
        if (animator.GetCurrentAnimatorStateInfo(0).normalizedTime>1) {
        // ステートを0に書き替え
        endAttackAnim();
        }
    }
  }

関数の最後にステートが2のとき、アニメーションが終わったかどうかの確認します。

終わっていればステートを0にする関数を呼び出してアニメーションを立ち状態にリセットしましょう。

関数の最初に入れたらアニメーションが始まる前に判定されてしまうので、最後にしたらいい感じに動いてくれました。

これで攻撃アニメーション開始と終了が実装出来ました。

次回はハンマーも一緒にアニメーションさせてそれに衝突判定を設けましょう。

それでは。