いんでぃーづ

ゲームいろいろ、いろいろ自由

Unity:重力に逆らい、球面にそって垂直に歩かせてみる

最近 モニュメントバレー [iOS, Android] という錯視パズルゲームを遊んでまして、
おしゃれでよくできてるなあと感嘆しておりました。

で、錯視もさることながら、プレイヤーの姫が重力に逆らい垂直に壁を歩いていったりするのです。

今回はそれをどうにか再現しようとした、試行錯誤の記録です。


NavMeshAgent ?

モニュメントバレーはタップした場所までプレイヤーが自動で移動していくので、システム的にはNavMeshAgentがしっくりきそうです。

が、NavMeshAgentを使うにはシーンにNavMeshをベイクする必要があります。
そしてこのNavMeshをベイクできる斜面の角度には限界があります

少なくとも天井を歩くのは不可能そうです。
今回の目的には合わなさそう。

CharacterController?

ならばプレイヤー移動用のコンポーネントCharacterControllerではどうか。

が、このコンポーネントをつけると、たとえTransform自体を傾けても、CharacterControllerのコライダーが傾きません

f:id:sugar_affordance:20170124114228p:plain

これでは地面の傾きをうまく表現できないでしょう。

Rigidbody ?

重力するならRigidbodyやろー、となるところですが、
ふとそもそも物理挙動いるのか?という疑問が湧きました。

Rigidbodyつけると物理エンジン対策がいろいろ必要ですし、
衝突したくなったらKinamaticのRigidbodyつければいいんじゃないだろうか。

結局...

特別なコンポーネントはつけず、Transform + スクリプトという、単純でなんとも味気ない構成になりました。

ソース

使用したスクリプトです。

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

public class GravityFreeAgent : MonoBehaviour {

    [SerializeField]
    Transform CenterOfBalance;  // 重心

    void Start () {
    }
    
    void Update () {

        // キーボード入力で移動、回転
        if (Input.GetKey(KeyCode.LeftArrow)) {
            transform.Rotate(
                new Vector3(0, -3f, 0),
                Space.Self
            );
        } else if (Input.GetKey(KeyCode.RightArrow)) {
            transform.Rotate(
                new Vector3(0, 3f, 0),
                Space.Self
            );
        } else if (Input.GetKey(KeyCode.UpArrow)) {
            transform.position = 
                transform.position + 
                (transform.forward * 3 * Time.fixedDeltaTime);
        } else if (Input.GetKey(KeyCode.DownArrow)) {
            transform.position = 
                transform.position + 
                (transform.forward * 3 * Time.fixedDeltaTime);
        }

        RaycastHit hit;

        // Transformの真下の地形の法線を調べる
        if (Physics.Raycast(
                    CenterOfBalance.position,
                    -transform.up,
                    out hit,
                    float.PositiveInfinity))
        {
            // 傾きの差を求める
            Quaternion q = Quaternion.FromToRotation(
                        transform.up,
                        hit.normal);

            // 自分を回転させる
            transform.rotation *= q;

            // 地面から一定距離離れていたら落下
            if (hit.distance > 0.05f) {
                transform.position =
                    transform.position +
                    (-transform.up * Physics.gravity.magnitude * Time.fixedDeltaTime);
            }
        }

    }

}

ソースのCenterOfBalanceは重心(足元)として設定するTransformで、下の画像のようなオブジェクト関係になります。

f:id:sugar_affordance:20170124114204p:plain

やってることは

  • 自機と地面の傾きの差を求め、補正する
  • 地面と離れたら、自機から見て真下方向に移動させる

だけです。

実装した結果

f:id:sugar_affordance:20170124114336g:plain

うーむ、おおむねイケてる?
ちょっとカクカクするのが気になります。


これでアクションゲームとか作ってみたいという気分がムラムラと。

まさか...続...っ!?         かない


“Unity” and Unity logos are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere, and are used under license.


免責事項

当サイトの広告バナー、リンクによって提供される情報、サービス内容について、当サイトは一切の責任を負いません。

また、当サイトの情報を元にユーザ様が不利益を被った場合にも、当サイトは一切の責任を負いません。

すべて自己責任でお願いします。