オブジェクトの移動方法をまとめて実験してみる[Unity2D]

Unity

ゲーム開発訳わかめ

どうも!現在鬼ごっこゲームを作成しているのですが

まぁ上手くいきません!もう色々上手くいきません。

一つ問題をクリアしたら新たに一つ問題が発生しています…。


これはブログに書くチャンスですね!

ということで今回のゲーム開発中に色々分からなくなったことを

以下に記載していこうと思います!

ゲームオブジェクトの移動方法まとめ

Image by David Mark from Pixabay

移動については何度も調べているのですが、まぁ覚えられないんですよ。

色々あってなにがなんだかって感じです。

とりあえず私が分かる範囲では以下の5つゲームオブジェクトの移動方法があるようです。

transform.Translate(x,y,z);
transform.position += new Vector3(x,y,z) * Time.deltaTime;
Vector3.MoveTowards(スタート,ゴール,移動距離)
Rigidbody.Addforce
Rigidbody.MovePosition

Rigidbody系とそれ以外での違い

Rigidbody系は物理演算によるオブジェクトの位置制御を行います。

ということでRigidbody系の場合は移動しようとしても壁があればぶつかって止まります。

それ以外は止まらないっぽいです。(すり抜けちゃう)


ちょっと実験してみましょう。

Rigidbodyでの移動とそうでない移動での衝突判定がどうなるかが

ポイントだと思うので全てRigidbodyをつけた状態で実験してみます。

ということで中央に壁を置いてRigidbody.MovePositionとTranslate(x,y,z)で

どうなるのかですね。

以下のようなシーンを作成してみました。

真ん中の黄色いのは壁です。
移動して来てもここで止まってほしいです。

まずプレイヤーにアタッチされているのは以下です。

敵も同様です。

Rigidbody2Dの設定は両者とも同じで以下になっています。

Body Type : Dynamic
Gravity Scale : 0
ということで重力の影響だけ受けないような設定にしています。

またCircle Collider 2Dの設定は以下のようになっています。

Is Trigger のチェックが入っていないので侵入せず衝突します。

最後にスクリプトですね。
こちらは以下のようにしました。

まずPlayerMoveです。

5つの移動方法を記載しています。
やりたい移動方法のみコメントアウトしてどうなるか実験しようって思っています。

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

public class PlayerMove : MonoBehaviour
{
    Rigidbody2D rb;

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

    // Update is called once per frame
    void Update()
    {
//        transform.Translate(-0.2f, 0f, 0f);
//        transform.position += new Vector3(-0.2f, 0f, 0f);
//        transform.position = Vector3.MoveTowards(transform.position, transform.position + new Vector3(-5f, 0, 0), 0.2f);
//        rb.AddForce(new Vector2(-10, 0));
//        rb.MovePosition(transform.position + new Vector3(-0.2f, 0, 0));
    }
}

EnemyMoveもx座標の符号が変わっただけで同じですが一応載せておきます。

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

public class EnemyMove : MonoBehaviour
{
    Rigidbody2D rb;

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

    // Update is called once per frame
    void Update()
    {
//        transform.Translate(0.2f, 0f, 0f);
//        transform.position += new Vector3(0.2f, 0f, 0f);
//        transform.position = Vector3.MoveTowards(transform.position, transform.position + new Vector3(5f, 0, 0), 0.2f);
//        rb.AddForce(new Vector2(10, 0));
//        rb.MovePosition(transform.position + new Vector3(0.2f, 0, 0));
    }
}

では以下でスクリプトの上から順にコメントを削除していってどうなるか見ていきましょう!

transform.Translate

おわかりいただけましたでしょうか?
衝突すべき壁をすり抜けてしまいますね。

分かりにくいですが
どうやら壁の中で敵とプレイヤーは衝突しているらしく
壁から抜け出たときに若干上下に移動しています。

transform.position

Translateと変化がありませんが載せておきます。

こちらもすり抜けてしまいますね。

Vector3.MoveTowards

一応お伝えしておきます。
上記二つと全く同じ挙動なので同じものに見えてしまいますが
ちゃんと別々で録画しています。

まぁ…すり抜けますね。

Rigidbody.AddForce

Rigidbobyでの移動にするとちゃんと壁で衝突してくれましたね。

ちょっと分かりにくいですがAddForceは力を加え続けるので
ちょっとづつ加速していきます。

Rigidbody.MovePosition

こちらもちゃんと止まってくれましたね。

ということで移動しているオブジェクトに衝突判定を行いたい場合は
Rigidbody系の移動方法を行いましょう。

おまけ:速すぎるとどうなる?

Rigidbody.MovePositionで
1フレームの移動距離が大きすぎた場合どうなるのか?

気になったので実験してみました。
PlayerMoveのスクリプトを以下のように変更してみました。

    void Update()
    {
//        transform.Translate(-0.2f, 0f, 0f);
//        transform.position += new Vector3(-0.2f, 0f, 0f);
//        transform.position = Vector3.MoveTowards(transform.position, transform.position + new Vector3(-5f, 0, 0), 0.2f);
//        rb.AddForce(new Vector2(-10, 0));
        rb.MovePosition(transform.position + new Vector3(-2f, 0, 0));
    }

x座標の移動距離を伸ばしてみたんです。
これで実行したのが以下です。

分かりにくいですがプレイヤーは壁にめり込んでいます。

AddForceも同様に加速する値が大きすぎると壁をすり抜けてしまいました。

タイトルとURLをコピーしました