今回は標準アセットの Third Person Character を操作してスムーズに階段を上れるようにする方法を試してみました。
Third Person Character が階段と坂道を上る場合の比較
まず、標準アセットの Prototyping で用意されているプレハブから StepsPrototype04x02x02 と RampPrototype04x02x02 を使用し、走って階段を上る場合と歩いて上る場合、さら坂道を上る場合の比較を検証します。左奥の階段が StepsPrototype04x02x02、右手前が RampPrototype04x02x02 のプレハブ。

階段を走って上る場合
脚が突っかかる感じで駆け上がっています。なんとも不自然ですね。

階段を歩いて上る場合
一段上がるごとにジャンプポーズになっています。これはちょっといだだけません。

坂道を歩いて上る場合
坂道であればスムーズに上ることができるのですが…

坂の途中で立ち止まると徐々に下に滑り落ちていきます。

コライダーの変更
坂道であれば歩いて上れることを確認できたので、階段オブジェクトのコライダーを坂道のプレハブのコライダーに変更します。
シーンに配置した StepsPrototype04x02x02 を選択。[Inspector]ウィンドウ > Mesh Collider > Mesh の右側にある◎をクリック。

ファイル選択ウィンドウが開いたら RampPrototype04x02x02 をダブルクリックして選択します。

オブジェクトのタグ設定
キャラクターが階段の上にいるかどうか判定するために新しいタグを作成します。
[Inspector]ウィンドウ > Tag > Add Tag を選択。

New Tag Name フィールドに Stairs を入力して [Save]ボタンをクリック。

新しいタグ Stairs が追加されました。

階段のオブジェクト StepsPrototype04x02x02 を選択。[Inspector]ウィンドウ > Tag > Stairs を選択。

スクリプト OnStairsControl の作成
プレハブ ThirdPersonController にアタッチされている Ridgidbody コンポーネントの空気抵抗パラメータ Drug の値を大きくして、キャラクターが立ち止まっている時に坂道から滑り落ちないようにします。
スクリプトでの制御で悩んだところ
キャラクターが階段から滑り落ちるのは解決できたのですが、 今度は階段上で立ち止まっている状態で スペース キーを押してジャンプをすると宙に浮く感じでジャンプができていません。

ジャンプしている時だけ Ridgidbody コンポーネントのパラメータ Drug の値を下げたいわけですが…条件を整理すると下記のようになります。
Drug の値を大きくする条件
[キャラクターが階段上にいる] + [垂直方向の入力値が 0 の場合] + [水平方向の入力値が 0 の場合]Drug の値を 0 にする条件
[キャラクターが階段上にいる] + [垂直方向の入力値が 0 の場合] + [水平方向の入力値が 0 の場合] さらに [スペースキーを押している間]上記の条件に加えて[キャラクターの Animator パラメータ OnGround が false の場合] を追加します。

これはキャラクターが階段の端からゆっくり移動した場合、キャラクターが空気椅子状態で停止することを防ぐために追加しました。

そして、作成したスクリプトのコードはこのようになりました。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class OnStairsControl : MonoBehaviour
{
// キャラクターの Rigidbody コンポーネントを格納する変数
private Rigidbody playerRb;
// キャラクターの Animator コンポーネントを格納する変数
private Animator playerAnim;
// キャラクターが坂道で立ち止まった時の空気抵抗
public float onStairsDrug;
// キャラクターが坂道と接触しているか判定するフラグ
public bool onStairs = false;
// ゲーム開始時に実行される処理
void Start()
{
// キャラクターの Rigidbody コンポーネントを取得して変数 playerRb に格納
playerRb = GetComponent();
// キャラクターの Animator コンポーネントを取得して変数 playerAnim に格納
playerAnim = GetComponent();
}
// ゲーム実行中の毎フレーム処理
void Update()
{
// キャラクターが階段上にいる場合、
// さらに垂直方向の入力値が 0 の場合
// さらに水平方向の入力値が 0 の場合
if (onStairs && Input.GetAxis("Vertical") == 0 && Input.GetAxis("Horizontal") == 0)
{
// キャラクターの空気抵抗を onStairsDrug の値に設定
playerRb.drag = onStairsDrug;
// スペースキーを押している間、またはキャラクターの
// Animator パラメータ OnGround が false の場合
if (Input.GetKey(KeyCode.Space) || !playerAnim.GetBool("OnGround"))
{
// キャラクターの空気抵抗を 0 に設定
playerRb.drag = 0;
}
}
// キャラクターの移動入力がある場合
else
{
// キャラクターの空気抵抗を 0 に設定
playerRb.drag = 0;
}
}
// コリジョン衝突判定:コライダーに接触した場合
void OnCollisionEnter(Collision collision)
{
if (collision.gameObject.tag == "Stairs")
{
// フラグ onStairs の値を true にする
onStairs = true;
}
}
// コリジョン衝突判定:コライダーから離れた場合
private void OnCollisionExit(Collision collision)
{
// 衝突したオブジェクトのタグが"Stairs"であれば
if (collision.gameObject.tag == "Stairs")
{
// フラグ onStairs の値を false にする
onStairs = false;
}
}
}
作成したスクリプト OnStairsControl をシーンに配置している ThirdPersonController にアタッチ。[Inspector]ウィンドウでこのように表示されます。キャラクターが階段から滑り落ちないようにするためには変数 onStairsDrug 値は 50 を入力すると大丈夫でした。

キャラクターの滑り止めは解決しましたが、階段の段差にキャラクターの脚が埋まっているのが気になります。今回はひとまずこれで完成にしたいと思います。

テスト用のステージ作成
最後に、標準アセットの Prototyping のプレハブを組み合わせて動作確認用のステージを作成してみました。

ピックアップアイテムのプレハブ PickupPrototype を配置してプレイヤーがアイテムすべてに触れるとステージクリアになるようにいくつかのスクリプトを追加しています。
- ゲームスタートのカウントダウン
- ピックアップアイテムに接触するとパーティクルを発生してオブジェクトを削除
- すべてのピックアップアイテムを取るとゲームクリアタイムを表示
- 60秒を過ぎるとゲームオーバー
- ボタンクリックでゲーム再プレイ
WebGL
今回の内容をWebGLでビルドしてみました。画像クリックでファイルがダウンロード、再生されます。(ダウンロードサイズ:約24MB)
- キャラクター移動:前 W、左 A、後 S、右 Dキー
- 歩く:左:Shiftキー + 移動キー
- ジャンプ:Spaceキー
- しゃがみ:Cキー
コメント
retry✖