【Unity2d】掴む処理の再実装

Unity2D

Unity2D ARPG

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

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

流石にやったことないコードの作り方を書きながら記事を書くのは大変ですね。

記事の方は少しペースを落として着実に理解しやすいように書いていきます。

今回は以前実装していた掴む処理を再実装しましょう。

グリッド移動は一旦消して掴みからの押す引く処理を作ってからグリッド移動を実装予定です。

Gを押して掴むに切り替える

_actStateが5になったとき掴みグラフィックに変更します。

1桁目5が掴みでしたね。

状態で変化するswitchのcaseを増やしていきましょう。

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

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

現状、Gを押すとグリッド移動に切り替えるようにしていましたが
今度はちゃんと掴む状態に切り替えるようにしてみます。

  // 押しているキーによってステートを変更
  protected void setState(List<KeyCode> keyList) {
    // とりあえずステートリセット(その場止まり)
    _actState = 0;
    // 移動状態にするかどうか
    if (keyList.Contains(KeyCode.DownArrow) || keyList.Contains(KeyCode.UpArrow) || keyList.Contains(KeyCode.LeftArrow) || keyList.Contains(KeyCode.RightArrow)) {
      _actState = 1;
    }
    // 掴み状態にする(今はグリッド切り替えよう)
    if (keyList.Contains(KeyCode.G)) {
      _actState = 5;
    }
  }

現状これで切り替えられますが、前回まではどうしていたか覚えていますか?

そう、Linecastで判定を飛ばし前方に掴めるものがあったら掴みモードにするということです。

掴みに関してはLinecastでも問題なかったので再び実装していきます。

問題はどこで掴み処理を実装するかですね……

移動はMoveで作りましたがその他アクション分作っていたら今度はファイル数が肥大化してくるので、
アクションはアクション管理スクリプトでまとめていきましょう。

移動スクリプトと同じで基本的にステートを見て処理をきめます。

Action_Managerを作ってみます。

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

public class Action_Manager : MonoBehaviour
{


    // コンストラクタ
    protected virtual void Start() {}
    // 更新処理
    protected virtual void Update() {}

    // 掴み処理
    protected virtual void Grab() {

    }
    // 引っ張り処理
    protected virtual void Pull() {

    }
    // 押す処理
    protected virtual void Push() {

    }

}

とりあえず必要そうなものをvirtualで定義しています。

後から色々改変する予定ではあります。

Action_Playerを作って必要なものを実装していきましょう。

今回は掴む処理を中心に移植していきます。

Linecastを再び使おう

判定を飛ばすことのできる〇〇castですが、その中でもLinecastは簡単に扱えます。

プレイヤーの中心前方から少しだけ判定を出せば、前方のオブジェクトにぶつかっていなくても
判定に触れることが出来るのでそこから掴む処理に切り替えて、分岐処理を組むことが出来ます。

LinecastはDebug.DrwaLineというシーン上でデバッグ描写してくれる仕組みとほぼ同じ使い方ができるので
一緒に使うとどのように判定が出ているのかが視覚的にわかりやすくなります。

まずはGを押したときにそのラインが表示されるところまでやってみましょう。

改良する前に以下の関数を作っていたのを覚えていますか?

    private RaycastHit2D getLineCast2Object(int direct, bool DebugFlag = false) {
        Vector3 castPosition = DummyVector3;
        Vector3 distance = DummyVector3;
        RaycastHit2D isLcast;
        switch(direct) {
            case 0:
                castPosition = castPositionFront;
                distance = castPositionDistance;
                break;
            case 1:
                castPosition = castPositionBack;
                distance = castPositionDistance;
                break;
            case 2:
                // オブジェクト側
                switch(nowAnim - nowAnim%10) {
                    case 0:
                        castPositionObjBack.Set(is_lcastFront.collider.transform.position.x,is_lcastFront.collider.transform.position.y-8.1f,0f);
                        distance = castPositionDistance = transform.up * 0.1f;
                        break;
                    case 10:
                        castPositionObjBack.Set(is_lcastFront.collider.transform.position.x,is_lcastFront.collider.transform.position.y+8.1f,0f);
                        distance = castPositionDistance = transform.up * -0.1f;
                        break;
                    case 20:
                        castPositionObjBack.Set(is_lcastFront.collider.transform.position.x-8.1f,is_lcastFront.collider.transform.position.y,0f);
                        distance = castPositionDistance = transform.right * 0.1f;
                        break;
                    case 30:
                        castPositionObjBack.Set(is_lcastFront.collider.transform.position.x+8.1f,is_lcastFront.collider.transform.position.y,0f);
                        distance = castPositionDistance = transform.right * -0.1f;
                        break;
                    default:
                        break;
                }
                castPosition = castPositionObjBack;
                break;
            default:
                break;
        }
        // 前方Linecast
        if (DebugFlag) {
            Debug.DrawLine(
                    castPosition,
                    castPosition - distance,
                    Color.red
            );
        }
        isLcast = Physics2D.Linecast(
            castPosition,
            castPosition - distance,
            layerMask
        );

        return isLcast;
    }

これを今風に改良していきます。

基本的な仕組みはなるべく一緒にしていきます。

まずは基本的な仕組みをActionManagerに書きましょう。

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

public class Action_Manager : MonoBehaviour
{
    // 衝突判定が取れたかどうかを格納する変数
    protected RaycastHit2D is_lcastFront;

    // Linecast発生ポイント座標
    protected Vector3 castPositionFront;
    protected Vector3 castPositionDistance;

    // コンストラクタ
    protected virtual void Start() {}
    // 更新処理
    protected virtual void Update() {}

    // 掴み処理
    protected virtual void Grab() {

    }
    // 引っ張り処理
    protected virtual void Pull() {

    }
    // 押す処理
    protected virtual void Push() {

    }


    protected RaycastHit2D getLineCast2Object(int direct,GameObject selfObj, LayerMask layerMask, bool DebugFlag = false) {

        RaycastHit2D isLcast;

        // 向きによるLinecast発生ポイント設定準備
        switch(direct) {
            case 0:
                castPositionDistance = transform.up * 1f;
                castPositionFront.Set(selfObj.transform.position.x,(selfObj.transform.position.y-5.5f) - 10.5f,0f);
                break;
            case 1:
                castPositionDistance = transform.up * -1f;
                castPositionFront.Set(selfObj.transform.position.x,(selfObj.transform.position.y-5.5f) + 10.5f,0f);
                break;
            case 2:
                castPositionDistance = transform.right * +1f;
                castPositionFront.Set(selfObj.transform.position.x-8f,(selfObj.transform.position.y-5.5f),0f);
                break;
            case 3:
                castPositionDistance = transform.right * -1f;
                castPositionFront.Set(selfObj.transform.position.x+8f,(selfObj.transform.position.y-5.5f),0f);
                break;
            default:
                break;
        }

        // 前方Linecast
        if (DebugFlag) {
            Debug.DrawLine(
                castPositionFront,
                castPositionFront - castPositionDistance,
                Color.red
            );
        }
        isLcast = Physics2D.Linecast(
            castPositionFront,
            castPositionFront - castPositionDistance,
            layerMask
        );

        return isLcast;
    }
}

基本的な仕組みはコチラに作って、使用する側はとてもシンプルにします。

次はAction_Playerを組んでいきましょう。

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

public class Action_Player : Action_Manager
{

    // プレイヤーオブジェクト
    private GameObject _Player;
    // プレイヤーステートスクリプトの取得
    private State_Player _State;

    [SerializeField]
    private LayerMask _layerMaskGrab;

    // コンストラクタ
    protected virtual void Start() {
        castPositionFront = new Vector3(0,0,0);
        castPositionDistance = new Vector3(0,0,0);

        // プレイヤーオブジェクトの取得
        _Player = GameObject.FindGameObjectsWithTag("Player")[0];
        _State = GameObject.FindGameObjectsWithTag("State_Manager")[0].GetComponent<State_Player>();

    }
    // 更新処理
    protected virtual void Update() {
        Grab();
    }

    // 掴み処理
    protected virtual void Grab() {
        if (_State.ActState == 5) {
            getLineCast2Object(_State.Direction, _Player, _layerMaskGrab, true);        
        }
    }
    // 引っ張り処理
    protected virtual void Pull() {

    }
    // 押す処理
    protected virtual void Push() {

    }
}

完了したらAction_Playerを取り付けるためのAction_Managerオブジェクトを作成しましょう。

Managerオブジェクトが増えてきましたので一旦見てみましょう。

私は現状こんな感じになっています。

Unity2D ARPG

Action_Playerを取り付けたオブジェクトのプロパティにあるLayerMaskGrabを「Wall」に切り替えておきましょう。

これで実行してみるとGを押すとSceneウィンドウに赤い線が出るように戻ったと思います。

掴む処理はできましたが、現状掴み状態で十字キーを押すと方向が変わってしまいます。

次回はつかみ中は方向を固定して引っ張る処理を作ります。

それでは。