【Unity】障害物を乗り越える処理を考える

アクションを作ると言う事で試行錯誤しているのですが、
前回、障害物で転倒する処理を作りました。

ただ、障害物をジャンプで越えるだけでは、少しツマラナイので、
手を加えたいなと考えています。

追加するのは、「乗り越え」です。

当然、上手く作れないので、悪戦苦闘してる毎日なんですが、
とにかく挑戦あるのみでっす。(^.^; オホホホ

さて、乗り越えって事なんですが…

操作としては、障害物の近くでキー入力すると
速度を落とさずに乗り越えて行く感じにしたいな~
なんて考えています。

思いついたのはいいですが、実際作るのは難しいので、
試行錯誤しながら記事にしていこうと思います。

正直作れるかも分からないんで、興味のない方は読み飛ばして下さい。
┐(´~`;)┌ かんべんシテネ


現状、ジャンプは速度が落ちないので、乗り越えとの格差がありません。
この辺りを修正する必要があります。

まず、通常ジャンプと乗り越えで速度を変える為にスクリプトを調整します。
調整としては、ジャンプの速度を落とすようにします。
ActionTest

private const float speedMax = 10f; //最高速度
private const float speedMin = 2f; //最低速度

void Update()
{
SetLinecast();

if (bodyUnder) ←接地フラグ
{
if (runSpeed < speedMax)
SpeedController();

if (Input.anyKeyDown)
KeySelect();

AnimationChange(actionNum.run);
}
else
AirMotion();
}

//落下・上昇チェック
private void AirMotion()
{
//落下中ならFallクリップ再生
if (playerRB.velocity.y < 0)
AnimationChange(actionNum.fall);

//ジャンプ中ならJumpクリップ再生
else if (playerRB.velocity.y > 0)
{
AnimationChange(actionNum.jump);
AirSpeedDown();
}
}

//ジャンプ上昇時の速度低下
private void AirSpeedDown()
{
float tempSpeed = playerRB.velocity.x - Time.deltaTime;
runSpeed = Mathf.Clamp(tempSpeed, speedMin, speedMax);
}

キー入力・ジャンプ処理については省きます
減速用関数AirSpeedDownを作って、上昇判定時に呼び出します。
ジャンプ時の最低速度は保証したいので、最低速度を2に設定しておいて、
上昇時のみdeltaTime分だけ減速するようにしました。
ハードル①.jpg
これでPLAYすると頂点まで徐々に減速して、10→9.6まで減速します。
落下時は、速度キープするので9.6のまま着地、着地後は加速となります。

ジャンプの速度調整ができたので、乗り越えのモーションを作るのですが、
障害物のギリギリと言っても、どの辺りで働くようにするか決める必要があります。
ハードル⑥.jpg
障害物の1.5ブロック分手前から乗り越えモーションが発動するようにしようと思います。
これより遠いと通常ジャンプ、1.5ブロック内なら乗り越えとします。

目安ができたので、乗り越えモーションを作るのですが…
ちょっとColliderの仕様を変更したので、先に伝えておきます。
ハードル⑤.jpg
アンドロイドの足元を安定させる為、BoxColliderを仕込んでいるのですが、
本体に仕込んでいる為、プレイ中に目視する事ができないんですよ。(T-T) グスッ

上手くOFFできてないと障害物に引っ掛かったりした時に
何が引っ掛かってるのか分かりにくいので、Colliderを目視できるよう変更しました。

新しくアンドロイド本体に空のオブジェクトを用意して、
BoxColliderとスプライトの正方形を入れておきます。
ActionTest

[Header("足元Collider")]
public GameObject footCollider;

ゲームオブジェクトとして取り込んで、SetActiveコマンドで
ON・OFFを操作するように変更します。

前回までは、BoxColliderを直接ON・OFFしてましたが、
今回からは、footColliderオブジェクトをON・OFFしていきます。
ご了承下さいませ(ToT)>゛サーセン


さて本題に戻って、乗り越えモーションの作成に入ります。

単純に乗り越えると言っても、ジャンプと同じキー入力で乗り越えさせる必要があるので、
処理イメージとしては、障害物の1.5ブロック前に来ると乗り越えモードになる。
乗り越えモード中は、ジャンプではなく乗り越えモーションを呼び出す。

こんな処理が必要になるかと思います。
まず、乗り越えモードを作る必要があるので、障害物の1.5ブロック手前の処理を作ります。

以前作った、障害物blockに空のオブジェクトを追加します。
ハードル⑦.jpg
このオブジェクトにBoxCollider2Dをアタッチして、トリガーにするをチェックします。
タグを設定する必要があるので、OverZoneとしてタグネームに設定しておきます。

ここに接触すると乗り越えモードになる感じでっす。
スクリプトを開いて、接触時の処理を作ります。
ActionTest

private bool overComeMode; //乗り越えモードのフラグ
private const string overZone = "OverZone"; //乗り越えゾーンのタグ

//接触判定
private void OnTriggerEnter2D(Collider2D collision)
{
if (collision.tag == overZone)
{
footCollider.SetActive(false);
overComeMode = true;
}
}

接触したら乗り越えモードのフラグを立てます。
ついでに足元のColliderをOFFにしておくと処理しやすいので設定しておきます。

続いて、キー操作入力なんですが、通常ならジャンプ・乗り越えならモーション呼び出し
に切り替える必要があるので、キー判定のジャンプで分岐を作ります。
ActionTest

private bool overCome; //乗り越えモーションフラグ

void Update()
{
SetLinecast();

if (bodyUnder)
{
if (Input.anyKeyDown)
KeySelect();
}
}

//キー入力判定
private void KeySelect()
{
if (Input.GetKeyDown(KeyCode.UpArrow))
{
if (overComeMode)
overCome = true;
else
jump = true;
}

if (Input.GetKeyDown(KeyCode.DownArrow))
{
footCollider.SetActive(false);
sliding = true;
}
}

乗り越えモードの際、上キーの入力があればoverComeフラグをONにします。
これでジャンプとの切り分けができるようになったので、実際のモーション呼び出しを作ります。
ActionTest

private float overComeProgress; //乗り越え処理経過時間

//アクションナンバーの設定
private enum actionNum
{
stop = 0,
run = 1,
jump = 2,
fall = 3,
sliding = 4,
wallAttach = 5,
wallJump = 6,
fallDown=7,
overCome=8,
}

void Update()
{
SetLinecast();

//スライディングモーション
if (sliding)
{
SlidingAction();
return;
}

//乗り越えモーション
if (overCome)
{
AnimationChange(actionNum.overCome);
return;
}

//転倒モーション
if (obstacle)
{
FallDown();
return;
}

//床に接地
if (bodyUnder)
{
}
}

Updateで監視して、overComeフラグがONになったらクリップ再生させます。

乗り越え処理を呼び出すタイミングですが、転倒モーションobstacleフラグの前です。
転倒フラグは、足元のLinecastを利用しているので、障害物に接触するとONになります。
乗り越え動作中に転倒する事になるので、obstacle判定より前で処理しておく必要があります。

これで乗り越えモーションが呼び出せるようになったのですが、
このままだと乗り越えモードが終わらないので、終了させる処理を作ります。

終了処理には、二つの方法を思いついたのですが、
一つは、OnTriggerを使う。
もう一つは、時間で管理する。

さてさて、どちらの処理がいいものか… (-_-)ゞ゛ウーム

OnTriggerだとブロックを挟んで、もう一つのColliderが必要になる。
時間だと速度によってブロック通過にバラつきがある。

どちらも一長一短な感じなんで、とりあえず二つとも作ってみます。
ActionTest


OnTriggerを使った処理-----------------------------------------

private const string zoneEnd = "ZoneEnd"; //乗り越えゾーン終了タグ

//接触判定
private void OnTriggerEnter2D(Collider2D collision)
{
if (collision.tag == overZone)
{
footCollider.SetActive(false);
overComeMode = true;
}

if (collision.tag == zoneEnd)
{
overCome = false;
obstacle = false;
overComeMode = false;
}
}

時間で処理-------------------------------------------------------

private float overComeProgress; //乗り越え処理経過時間

void Update()
{
SetLinecast();

//乗り越え
if (overCome)
{
OvercomeObstacles();
return;
}
}

//障害物を乗り越える
private void OvercomeObstacles()
{
AnimationChange(actionNum.overCome);
overComeProgress += Time.deltaTime;

if (overComeProgress >= 0.5f)
{
overComeProgress = 0f;
overCome = false;
obstacle = false;
overComeMode = false;
}
}

スクリプトは、こんな感じで処理できそうです。
OnTriggerを使う場合、Unityの設定が必要になります。
ハードル⑧.jpg
終了用のColliderを設置しておきます。
タグネームの設定とトリガーにするをチェックすればスクリプトで終了させられます。

時間処理の場合は、キャラが自己完結してくれるので、
オブジェクトの追加など必要がないので楽なんですが、
移動距離を計算しておく必要があります。

今回のキャラ移動は、スピードを2~10の範囲で考えています。
スケール1のブロックを通過するのに0.5秒~0.1秒のバラつきがあります。

Animationクリップの時間設定も考える必要があるので、
結構、手間が掛かります。

移動速度が一定なら時間処理で自己完結させる方が処理は楽になりそうですね~

最後にクリップの画像を
ハードル⑨.jpg
サンプルを10にして5フレームまでモーションを設定しました。

時間処理で作った物をプレイしてみます。

正確な速度と距離の計算が出来てないので、動きがぎこちないですが、
一応は、乗り越え動作が作る事ができたかと思います。

ただ、大きな問題点もあって、乗り越えモードのまま転倒させると
モードの解除が掛からない点です。

転倒モーション後は、常に乗り越えモードになったままになるので、
対策を打たなくてはならないんですよね~ (T-T) グスッ

OnTriggerなら問題なくモード解除させられるんですが、
キャラに自己完結させる処理を作りたいなと思っていて悩んでおります。

あと、乗り越え動作がどうにもショボイので、もう少しカッコよく
越えられないかと思案しております。

その辺りが改善できたら記事にまとめてみようと思います。

乗り越え動作完成とまでは行きませんでしたが、
何かの参考になれば幸いかと思います。

今回はこのへんで~
(TωT)/~~~ BYE BYE





この記事へのコメント