質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.05%

[Unity 2D]キャラが攻撃中に動かなくする方法を教えてください。

解決済

回答 2

投稿

  • 評価
  • クリップ 4
  • VIEW 4,063

score 12

[Unity 2Dゲーム]キャラクターが攻撃中に動かなくする方法を教えてください。

現在色んなサイトを拝見してキャラクターの移動と攻撃は作成できたのですが、
攻撃のアニメーション実行中にもキャラクターが移動してしまいます。

色々初心者の自分なりに考えたのですが、挙動が不安定になってしまうので改善できないままに…
改善策を教えてください。

一応コードも載せてみましたがわかりにくくてすいません…

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Controller : MonoBehaviour
{
    Animator animator;
    Rigidbody2D rb2d;
    public float Speed = 10f;
    float Scroll = 0f;
    bool Attack = false;
    string State;
    string SaveState;
    void Start()
    {
        rb2d = GetComponent<Rigidbody2D>();
        animator = GetComponent<Animator>();
    }
    void Update()
    {
        GetKey();
        ChangeState();
        ChangeAnimation();
        Move();
    }
    void GetKey()
    {
        if (Input.GetMouseButtonDown(0))
        {
            Attack = true;
        }
        else if (Input.GetKey(KeyCode.D) || Input.GetKey(KeyCode.RightArrow))
        {
            Scroll = 1f;
        }
        else if (Input.GetKey(KeyCode.A) || Input.GetKey(KeyCode.LeftArrow))
        {
            Scroll = -1f;
        }
        else
        {
            Scroll = 0;
        }
    }
    void ChangeState()
    {
        if (Attack == true)
        {
            State = "Attack";
        }
        else if (Scroll != 0)
        {
            State = "Run";
        }
        else
        {
            State = "Stop";
        }
    }

    void ChangeAnimation()
    {
        if (SaveState != State)
        {
            switch (State)
            {
                case "Stop":
                    animator.SetBool("Run", false);
                    animator.SetBool("Stop", true);
                    animator.SetBool("Attack", false);
                    break;

                case "Run":
                    animator.SetBool("Stop", false);
                    animator.SetBool("Attack", false);
                    animator.SetBool("Run", true);
                    break;

                case "Attack":
                    animator.SetBool("Run", false);
                    animator.SetBool("Stop", false);
                    animator.SetBool("Attack",true);

                    break;
            }
        }
        Attack = false;
        SaveState = State;
    }
    void Move()
    {
        rb2d.velocity = new Vector2(Scroll * Speed, rb2d.velocity.y);
    }
}
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

+2

【回答 1】 ← 取り消します。失礼しました。
実際に動かして確認できていませんが、取り急ぎ。
変数 Scroll の値で移動量を決めているなら、攻撃中はその値を0にしておけばよいのではないでしょうか。
    void ChangeState()
    {
        if (Attack == true)
        {
            State = "Attack";
            Scroll = 0;        // 攻撃中は Scroll = 0 にして移動させない
        }


【回答2】
あらためて回答します。さきほどは失礼しました。
考え方は nya3720197 さんの回答と同じで、攻撃中は入力を受け取らないというものです。
コードが質問者さんのものではなく自分流になってしまいましたが、ご参考まで。

メインのスクリプトはこちら。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SkeltonController : MonoBehaviour
{
    [SerializeField] float speed;
    [SerializeField] Rigidbody rb;
    [SerializeField] Animator anim;

    private float inputH, inputV;
    private bool mouseClick = false;

    private void Update ()
    {
        // 攻撃モーション中なら入力を受け取らない
        if ( anim.GetBool ( "Attack" ) == true ) return;

        // 各種入力を受け取る
        inputH = Input.GetAxis ( "Horizontal" );
        inputV = Input.GetAxis ( "Vertical" );
        mouseClick = Input.GetMouseButtonDown ( 0 );
    }

    private void FixedUpdate ()
    {
        if ( mouseClick )                   // マウス左クリックで攻撃
        {
            anim.SetBool ( "Attack", true );
            anim.SetBool ( "Walk", false );
            return;
        }

        if ( inputH == 0 && inputV == 0 )   // 待機
        {
            anim.SetBool ( "Walk", false );
        }
        else                                // 歩き
        {
            anim.SetBool ( "Walk", true );
            var moveVal = new Vector3(inputH, 0f, inputV) * speed;
            rb.MovePosition ( rb.position + moveVal );
        }
    }
}

AnimatorControllerはこのような形で設定してみました。
イメージ説明

さらに、Attackモーションの部分にStateMachineBehaviorのスクリプトをアタッチします。
イメージ説明
内容はこちら。これによって、攻撃モーションの終わり間際に、AnimatorのAttackの値をfalseに戻します。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

// Animator の Attack モーションにアタッチする StateMachineBehavior
public class AttackBehaviour : StateMachineBehaviour
{
    override public void OnStateUpdate ( Animator animator, AnimatorStateInfo stateInfo, int layerIndex )
    {
        // 攻撃モーションの最終盤で Attack パラメーターの値を false に戻す
        if ( stateInfo.normalizedTime > 0.9f )
        {
            animator.SetBool ( "Attack", false );
        }
    }
}


参考GIF
![イメージ説明
以上です。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/12/27 20:58

    攻撃キーを押したら 変数 Scrollはゼロになりますが、攻撃アニメーション再生中に移動キーを押すと、
    変数 Scroll に新たな値が入ってしまうので移動してしまいます…

    キャンセル

  • 2018/12/27 21:01

    AnimatorのHas Exit Time はオンにしているので、攻撃アニメーションしながら移動しちゃう感じです。

    キャンセル

  • 2018/12/27 22:16

    あらためて回答しなおしました。回答2を参照願います。

    キャンセル

  • 2018/12/27 23:20

    何から何まで丁寧な解説ありがとうございました(> <)
    ベストアンサーにさせていただきます!

    キャンセル

0

攻撃中はキー入力を受け取る関数を無効化して、攻撃が終わった時点でまた有効化するという考え方でなんとかなりました。

具体的には攻撃キーが押されたら変数Attackにtrueを代入します。
もしAttackがtrueならキー入力を受け取らないようにします。
そして攻撃アニメーションが終わったら関数AttackFinishを実行(←unityのanimatorで設定可能)する事で変数Attackにfalseを代入してまたキー入力受付を再開します。

プログラム初心者の僕が考えたのでもっと良い方法はあると思います…

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Controller : MonoBehaviour
{
    Animator animator;
    Rigidbody2D rb2d;
    public float Speed = 10f;
    float Scroll = 0f;
    bool Attack = false;
    string State;
    string SaveState;
    void Start()
    {
        rb2d = GetComponent<Rigidbody2D>();
        animator = GetComponent<Animator>();
    }
    void Update()
    {
        GetKey();
        ChangeState();
        ChangeAnimation();
        Move();
    }
    void GetKey()
    {
        if (Input.GetMouseButtonDown(0))
        {
            Attack = true;
        }
        //攻撃中はキー入力を受け取らない(boolで判断)
        else if (Attack == false)
        {
            if (Input.GetKey(KeyCode.D))
            {
                Scroll = 1f;
            }
            else if (Input.GetKey(KeyCode.A))
            {
                Scroll = -1f;
            }
            else
            {
                Scroll = 0;
            }
        }
    }
    void ChangeState()
    {
        if (Attack == true)
        {
            State = "Attack";
            Scroll = 0;
        }
        else if (Scroll != 0)
        {
            State = "Run";
        }
        else
        {
            State = "Stop";
        }
    }

    void ChangeAnimation()
    {
        if (SaveState != State)
        {
            switch (State)
            {
                case "Stop":
                    animator.SetBool("Run", false);
                    animator.SetBool("Stop", true);
                    animator.SetBool("Attack", false);
                    break;

                case "Run":
                    animator.SetBool("Stop", false);
                    animator.SetBool("Attack", false);
                    animator.SetBool("Run", true);
                    break;

                case "Attack":
                    animator.SetBool("Run", false);
                    animator.SetBool("Stop", false);
                    animator.SetBool("Attack",true);
                    break;
            }
        }
        SaveState = State;
    }

    void Move()
    {
        rb2d.velocity = new Vector2(Scroll * Speed, rb2d.velocity.y);
    }

    //アニメーションが終わったら実行(unityのanimatorで設定可能)
    void AttackFinish()
    {
        Attack = false;
    }
}


このコードは様々サイト+僕の考えで作ったので完全オリジナルではないです

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.05%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る