読者です 読者をやめる 読者になる 読者になる

いんでぃーづ

個人でゲーム開発してる上で吸収したモノたち紹介。UnityからGIMPまでなんでも。デザインとかゲーム論まで語っちゃうよ的なアレ。

MENU

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

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


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

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

Amazon.co.jpアソシエイト