【開発メモ】アクション「壁ジャンプ」の実装

というわけで、今回のお題はこれです!

20160313

所謂「壁ジャンプ」「壁キック」と言われるものです!
壁を蹴ってジャンプし、高い足場へも登れるようにします。

実は旧ブログでこっそりと実装していたりしましたが、実用性のない微妙なものだったので、ちょっと作り変えてみました!
両側に壁がある場合に連続で壁ジャンプできるようにしたのが大きな変更です。

基本的な仕様

完全な2Dアクションならともかく、3Dアクションでどこでも壁蹴り出来るようにするのは厳しいです。
壁との接触判定が難しい上、意図しない場面で壁ジャンプが暴発する可能性もあります。

ということで、任天堂の某SFアクションと同じように「壁ジャンプ専用の壁」を用意します。
その壁に接触中にジャンプボタンを押した場合に壁ジャンプを行うようにします。

モーションはダッシュジャンプ時と一緒で、くるくる回転させます。
専用モーションを作るのが面倒なので、とりあえず回らせれば見栄えがよくなるためです!
壁ジャンプ実行前にAnimator.Play()で切り替えてしまいます。

壁ジャンプ専用オブジェクトとスクリプトの作成

まず「壁ジャンプ専用の壁」を作ります。
Cubeを生成し、適当にそれっぽいマテリアルを作って適用します。

shot2ss20160313142132946

判定をCollisionで行うのは厳しいため、壁本体の判定とは別でTrigger用の判定を付けておきます。
Triggerの判定を壁ジャンプが可能な方向に少しずらしておきます。

次にスクリプトを作成します。
以下は壁用オブジェクトに設定する「ClimbWall」クラスです。

【ClimbWallクラス】

using UnityEngine;
using System.Collections;

public class ClimbWall : MonoBehaviour {

    public Vector3 climbVect;

    private CharacterMotor charMotor;

    protected void OnTriggerStay(Collider c) {
        if (c.gameObject.tag == "Player") {
            if (Input.GetButtonDown("Jump")) {
                charMotor = c.gameObject.GetComponent<CharacterMotor>();

                if (!charMotor.IsGrounded()) {
                    c.GetComponent<Animator>().Play("DashJump");

                    charMotor.movement.velocity.y = 0;
                    charMotor.jumping.enabled = false;
                    iTween.Stop(c.gameObject);

                    c.transform.LookAt(c.transform.position + new Vector3(climbVect.x, 0f, climbVect.z));

                    iTween.ValueTo(c.gameObject, iTween.Hash(
                        "from", climbVect,
                        "to", Vector3.zero,
                        "time", 0.5f,
                        "delay", 0.1f,
                        "onupdate", "Thrust",
                        "onupdatetarget", c.gameObject,
                        "oncomplete", "resetJump",
                        "oncompletetarget", gameObject
                    ));
                }
            }
        }
    }

    private void resetJump() {
        charMotor.jumping.enabled = true;
    }
}

「移動系ならiTween.MoveToでOK」と思ったのですが、今回はValueToを使用しています。
理由は単純で、iTweenのMove系は接触判定を突き抜ける可能性が非常に高いためです。
恐らくpositionを直接変化させているためだと思われますが・・・。
CharacterController的には CharacterController.Move() を使う必要があるので、仕方なくPlayerクラスにMove専用の関数を設定し、そこで一定時間Moveを呼んでもらうことにします。

【Playerクラス(一部)】

public abstract class Player : MonoBehaviour {
    protected void characterMove( Vector3 moveVect) {
        charControl.Move(moveVect * Time .deltaTime * 100);
    }
}

壁ジャンプする方向は「climbVect」としてフィールドに持たせ、インスペクターから設定します。
当初はプレイヤーとオブジェクトの方向から自動的に算出しようとしましたが、2点間のベクトルに斜め方向も加わってしまい、想定した動きにならなかったので挫折。
ステージに配置する際のRotationを、なるべくカメラに対して直角になるよう調節する必要があります。
一応climbVectにY軸のみを設定することで真垂直に壁キックができるというメリットはあります。
また、CharacterControllerのジャンプ機能が働いていると大ジャンプになってしまうことがあるので、iTweenの実行中は無効化しておきます。

iTweenのonupdateやoncompleteのターゲットには注意が必要です。
ClimbWallクラスで行うのか、Playerクラスで行うのかを考えると分かりやすいです。
勿論指定を誤ると上手く動きません。
そもそも移動処理をClimbWallクラスで行うのが間違っている気がしますが、そのうちいい感じにします!

まとめ

ということで「壁ジャンプ」を実装してみました!
やや挙動がおかしい上、たまに正常に動作しなかったりしますが、とりあえずこれがあることを前提にステージを作っていきます。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

*