【Unity】壁の上端で飛び上がりを止める

あけましておめでとうございます。
本年度もよろしくお願いします。

10月くらいから処理が上手く作れなくなって、
悩みに悩んで、年を越してしまいました。

長らく休んでいると、記事の書き方を忘れてしまって、
うまく説明ができるか分かりませんが、2022年も始まったので、
心機一転、頑張って行こうと思います。

ただ、ヤル気がどこまで続くかは、分かりませんが…
(°-°;)ヾ(-_- ;) シモシモ・・


去年までの振り返りなんですが、
壁登りの処理を曲りなりにも作る事が出来ました。

ただ、壁の上端に差し掛かった所で、大きくジャンプしてしまうってのが、
気に入らないと言うか納得いかない部分でして…

上端に差し掛かった所で壁をよじ登れないかと試行錯誤していたのですが、
正直、上手く処理が作れませんでした。

何パターンか試したのですが、全然上手く行かなくて、
o(><)(;><)o ジタバタ となって、投げ出していたのが本音なんです。
(..*) オハズカシイ・・

四苦八苦しながら、一応の処理が作れたので、
順次、記事にまとめていこうと思います。

まず壁登りなんですが、AddForceでジャンプさせています。
壁上端処理①.jpg
壁の上端近くでJumpするとAddForceなので、
壁が終わっているのに大きく飛び上がる事になります。

壁の上が広い足場なら飛び上がっても問題ないのですが、
狭い足場なら飛越えてしまい、上に立つ事ができません。
やはりアクションなんで、上端に届いたら、よじ登る感じにしたいんですよね~

まず、飛び上がりを抑制する必要があるので、
少し検証してみようと思います。

動きを止める方法としては、velocityのY軸を0にすれば
飛び上がりを抑制する事ができます。

注意点としては、
・飛び上がりの抑制を連続させない
・抑制タイミングを設定する必要がある

連続で抑制を掛けると上下動ができなくなるので、
一度だけ呼び出す必要があります。
抑制タイミングについは、上端に到達した事を検知させる必要があります。

と言う事で、お決まりのモデルを作って検証でっす。(^ё^) ♪♪
ストッパーテスト①.jpg
Floorを作って青色のボックスをジャンプさせます。

ジャンプは自動で行うようにスクリプトを組みます。
BoxController

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

public class BoxController : MonoBehaviour
{
private Rigidbody2D boxRB;
private bool jump;
private float jumpPow = 600f;

private string floor = "Floor";

// Start is called before the first frame update
void Start()
{
boxRB = GetComponent<Rigidbody2D>();
}

private void FixedUpdate()
{
if (jump)
{
boxRB.AddForce(Vector2.up * jumpPow);
jump = false;
}
}

private void OnCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.tag == floor)
jump = true;
}
}

FloorオブジェクトのタグをFloorに設定して、
PLAYすると着地と同時にBoxがジャンプしてくれます。
Boxには、BoxCollider2DとRigidbody2Dをアタッチして、Z軸の回転を固定しておきます。

続いて、抑制タイミング用として、トリガーを作ります。
ストッパーテスト②.jpg
緑のBoxがストッパーになります。
このストッパーに接触したタイミングで上昇を抑制します。

ストッパーには、BoxCollider2Dをアタッチしてトリガーにチェックを入れておきます。
タグにStopperの項目を追加して、タグネームに設定しておきます。

ストッパーの用意ができたので、
BoxControllerスクリプトにストッパーの働きを追加します。
BoxController

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

public class BoxController : MonoBehaviour
{
private Rigidbody2D boxRB;
private bool stop;
private bool jump;
private float jumpPow = 600f;

private string floor = "Floor";
private string stopper = "Stopper";

// Start is called before the first frame update
void Start()
{
boxRB = GetComponent<Rigidbody2D>();
}

private void FixedUpdate()
{
if (jump)
{
boxRB.AddForce(Vector2.up * jumpPow);
jump = false;
}

if (stop)
{
boxRB.velocity = Vector3.zero;
stop = false;
}
}

private void OnTriggerEnter2D(Collider2D collision)
{
if (collision.tag == stopper)
stop = true;
}

private void OnCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.tag == floor)
jump = true;
}
}

OnTriggerで検知させてvelocityを0にします。
Velocityの代入はジャンプと同様、一度きりにする必要があるので、
stopフラグでコントロールします。

ストッパーの働きを確認したいので、ボタンでストッパーをON/OFFできるようにして、
PLAYしてみます。
上手く上昇抑制ができています。

早速、アンドロイド君に導入していきます。
ストッパーテスト③.jpg
WallTopSensorを作って、接触したら上昇を抑制します。
WallTopSensorは、タグとトリガーにするを設定しておきます。
ActionTest

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

public class ActionTest : MonoBehaviour
{
private bool risingStop; //上昇停止フラグ
private const string wallTop = "WallTop"; //壁上端センサータグ

private void FixedUpdate()
{
if (risingStop)
{
playerRB.velocity = new Vector2(playerRB.velocity.x, 0f);
risingStop = false;
}
}

//接触判定
private void OnTriggerEnter2D(Collider2D collision)
{
if (collision.tag == wallTop)
risingStop = true;
}
}

velocityの横移動は変えたくないので、Y軸のみ0にします。
これで上昇のみ抑制できます。

PLAYすると問題なく上昇抑制ができています。
これでよじ登らせる処理を作っていけばOKだと最初は思ったのですが…

壁に飛びつくシチュエーションを考えていたら、これではダメだって事に気付きました。
ストッパーテスト④.jpg
例えば、壁の上にJumpで飛び乗れる高さにあっても
トリガーに引っ掛かるので、動きが止まって落下します。

これでは、よじ登らせる事ができても意味が無くなります。
正直、これは悩みました。(ノ_<。)うっうっうっ

Rayに変更して検知させてみるかとか、よじ登りをあきらめるかとか…

アンドロイドのボディが上端のどの辺りに来ているか分かれば、
なんとかなりそうなものなんですが…

で、年末まで悩んでいたわけなんですね。

年末の掃除をしながら無理かな~
と考えていたら、ふと気づきました。

体の中にセンサーがあればいいのかな!?

早速試してみます。
ストッパーテスト⑤.jpg
ボディの赤枠部分にトリガーを検知するセンサーを設定すれば
問題ないかも…

早速、センサーオブジェクトを追加しようと思っていたら
そう言えば、ボディってBone毎にColliderを設定している事を思い出しました。

この赤枠部分って、腰の高さにあるなってことで
腰のColliderをセンサーにできないかなんて思いまして、
こんなスクリプトを作ってみました。
SensorCS

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

public class SensorCS : MonoBehaviour
{
public GameObject body;
private ActionTest actionTestCS;
private string wallTop = "WallTop";

// Start is called before the first frame update
void Start()
{
SensorSetting();
}

private void SensorSetting()
{
actionTestCS = body.GetComponent<ActionTest>();
}

private void OnTriggerEnter2D(Collider2D collision)
{
if (collision.tag == wallTop)
actionTestCS.WallTop();
}
}

このスクリプトをbone_腰にアタッチします。
ストッパーテスト⑥.jpg
Colliderだらけで分かりにくいですが、赤丸部分がbone_腰のColliderになります。
パブリックで設定した変数bodyにアンドロイド本体をアタッチします。

続いて、腰がトリガーに接触した時の本体スクリプトを編集します。
ActionTest

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

public class ActionTest : MonoBehaviour
{
private bool risingStop; //上昇停止フラグ

private void FixedUpdate()
{
if (risingStop)
{
playerRB.velocity = new Vector2(playerRB.velocity.x, 0f);
risingStop = false;
}
}

//Waistセンサーが反応したら
public void WallTop()
{
risingStop = true;
}
}

これは単純にフラグを立てるだけですね。

これでテストしてみます。
問題無く反応してくれました~ヽ(´▽`)/~♪

体のパーツをセンサーにするって所が、なぜ今まで思いつかなかったのか
まだまだ精進が足りませぬ(T^T) ヒック

悩み処も解消できたので、よじ登りをサクッと作って進みたいところなんですが、
この後もいろいろトラブルが発生して、四苦八苦したので、

次回は、よじ登り四苦八苦編を記事にできたらなと思います。

いよいよ新年が始まりました。
勉強されている方々が良い年になるようできるだけブログを書いていけたらと思います。

今回はこの辺で。
(^^)/~~デハデハ

この記事へのコメント