Unityでキャラクターが動く床に乗ると一緒に動く仕組みガイド

この資料では、キャラクターが移動する床(Moving Platform)に乗った際、床の動きに連動してプレイヤーを移動させる3つのアプローチを紹介します。さらに、プレイヤーの移動がTransformによる座標更新(直接的な移動)またはRigidbodyを用いた物理演算ベースの移動の場合でも対応可能な点、そして特に方法1において床上で独自に移動するための注意点について解説します。


1. 床の作成方法

2D版の場合

  • 作成手順:
    GameObject > 2D Object > Sprite を選択し、床用のスプライトを設定します。
  • コンポーネント設定:
    • Rigidbody2D: 追加し、Body TypeKinematic に設定。
    • Collider2D: 例として Box Collider2D を追加して当たり判定を設定。

3D版の場合

  • 作成手順:
    GameObject > 3D Object > Cube を選択し、Cubeを床オブジェクトとして使用します。
  • コンポーネント設定:
    • Collider: Cubeには自動的に Box Collider が付与されます。
    • Rigidbody: 追加後、「Is Kinematic」にチェックを入れ、物理演算の影響を抑制します。

2. 各連動方法

方法1:キャラクターを床の子オブジェクトにする

概要

キャラクターが床に接触した際、床の子オブジェクトとして登録することで、床の移動に合わせて自動的に位置が連動します。

実装例

【2D版】

using UnityEngine;

public class CharacterOnPlatform : MonoBehaviour
{
    void OnCollisionEnter2D(Collision2D collision)
    {
        if (collision.gameObject.CompareTag("MovingPlatform"))
        {
            transform.SetParent(collision.transform);  // 床の子オブジェクトに設定
        }
    }

    void OnCollisionExit2D(Collision2D collision)
    {
        if (collision.gameObject.CompareTag("MovingPlatform"))
        {
            transform.SetParent(null);  // 親子関係を解除
        }
    }
}

【3D版】

using UnityEngine;

public class CharacterOnPlatform : MonoBehaviour
{
    void OnCollisionEnter(Collision collision)
    {
        if (collision.gameObject.CompareTag("MovingPlatform"))
        {
            transform.SetParent(collision.transform);  // 床の子オブジェクトに設定
        }
    }

    void OnCollisionExit(Collision collision)
    {
        if (collision.gameObject.CompareTag("MovingPlatform"))
        {
            transform.SetParent(null);  // 親子関係を解除
        }
    }
}

床上でのプレイヤー独自移動への対応(方法1の場合)

親子付けによりキャラクターは床のローカル座標系に入ります。
この状態でプレイヤー入力に基づく移動を行う際は、以下の点に注意してください。

  1. ローカル座標系での入力処理の調整
    • 床の回転やスケールの影響を受けるため、入力ベクトルを床のローカル空間に合わせて変換する必要があります。
    • 例として、transform.Translate() の第二引数に Space.Self を指定する方法があります。
  2. 床の回転・スケールの影響の補正
    • プラットフォームが回転やスケール変更する場合、キャラクターの移動方向が予期せぬ方向に変わることがあるため、必要に応じて入力処理内で補正を行います。

【プレイヤー移動スクリプト例】

using UnityEngine;

public class PlayerMovement : MonoBehaviour
{
    public float speed = 5f;

    void Update()
    {
        // 左右の入力を取得
        float horizontal = Input.GetAxis("Horizontal");

        // ローカル座標系で移動(床の子になっている場合、親である床の座標系に合わせた移動となる)
        Vector3 movement = new Vector3(horizontal * speed * Time.deltaTime, 0, 0);
        transform.Translate(movement, Space.Self);
    }
}

このスクリプトでは、キャラクターが床の子オブジェクトの場合でも、床上での独自移動が正しく反映されるようにローカル座標系での移動を行っています。

メリット・デメリット

  • メリット:
    実装がシンプルで、床の移動と連動した動作が安定して得られる。
  • デメリット:
    床の子オブジェクトになっているため、床の回転やスケールがキャラクターに影響する場合がある。そのため、床上での入力移動ではローカル座標系での調整が必要。

方法2:床の移動量をキャラクターに加算する

概要

床の移動量の差分を計算し、その分だけキャラクターの位置を直接更新する方法です。
キャラクターのTransform(回転やスケール)には影響を与えずに床の動きを反映できます。

実装例

【2D版】

using UnityEngine;

public class CharacterOnMovingPlatform : MonoBehaviour
{
    private Transform platformTransform;
    private Vector3 lastPlatformPosition;
    private bool onPlatform = false;

    void OnCollisionEnter2D(Collision2D collision)
    {
        if (collision.gameObject.CompareTag("MovingPlatform"))
        {
            platformTransform = collision.transform;
            lastPlatformPosition = platformTransform.position;
            onPlatform = true;
        }
    }

    void OnCollisionExit2D(Collision2D collision)
    {
        if (collision.gameObject.CompareTag("MovingPlatform"))
        {
            onPlatform = false;
        }
    }

    void Update()
    {
        if (onPlatform)
        {
            Vector3 platformMovement = platformTransform.position - lastPlatformPosition;
            transform.position += platformMovement;
            lastPlatformPosition = platformTransform.position;
        }
    }
}

【3D版】

using UnityEngine;

public class CharacterOnMovingPlatform : MonoBehaviour
{
    private Transform platformTransform;
    private Vector3 lastPlatformPosition;
    private bool onPlatform = false;

    void OnCollisionEnter(Collision collision)
    {
        if (collision.gameObject.CompareTag("MovingPlatform"))
        {
            platformTransform = collision.transform;
            lastPlatformPosition = platformTransform.position;
            onPlatform = true;
        }
    }

    void OnCollisionExit(Collision collision)
    {
        if (collision.gameObject.CompareTag("MovingPlatform"))
        {
            onPlatform = false;
        }
    }

    void Update()
    {
        if (onPlatform)
        {
            Vector3 platformMovement = platformTransform.position - lastPlatformPosition;
            transform.position += platformMovement;
            lastPlatformPosition = platformTransform.position;
        }
    }
}

メリット・デメリット

  • メリット:
    キャラクターのTransform(回転・スケール)には影響せず、床の移動量だけを反映できる。
  • デメリット:
    床の動きが急激な場合、キャラクターの移動が滑らかでなくなる可能性があります。

方法3:FixedJoint(FixedJoint2D)を使った物理的接続

概要

FixedJoint系のジョイントコンポーネントを利用して、キャラクターと床を物理的に結合する方法です。
物理演算に基づいた自然な連動動作が得られます。

実装例

【2D版 (FixedJoint2D)】

using UnityEngine;

public class AttachToPlatformWithJoint : MonoBehaviour
{
    private FixedJoint2D fixedJoint;

    void OnCollisionEnter2D(Collision2D collision)
    {
        if (collision.gameObject.CompareTag("MovingPlatform"))
        {
            fixedJoint = gameObject.AddComponent<FixedJoint2D>();
            fixedJoint.connectedBody = collision.rigidbody;
        }
    }

    void OnCollisionExit2D(Collision2D collision)
    {
        if (collision.gameObject.CompareTag("MovingPlatform"))
        {
            Destroy(fixedJoint);
        }
    }
}

【3D版】

using UnityEngine;

public class AttachToPlatformWithJoint : MonoBehaviour
{
    private FixedJoint fixedJoint;

    void OnCollisionEnter(Collision collision)
    {
        if (collision.gameObject.CompareTag("MovingPlatform"))
        {
            fixedJoint = gameObject.AddComponent<FixedJoint>();
            fixedJoint.connectedBody = collision.rigidbody;
        }
    }

    void OnCollisionExit(Collision collision)
    {
        if (collision.gameObject.CompareTag("MovingPlatform"))
        {
            Destroy(fixedJoint);
        }
    }
}

メリット・デメリット

  • メリット:
    物理演算により自然な連動動作が実現可能です。
  • デメリット:
    物理計算負荷が増すため、パフォーマンス面で注意が必要な場合があります。また、物理ベースの挙動を十分に調整する必要があります。

3. 適用可能な移動方式について

  • Transformによる座標操作(直接的な位置変更)
    → 方法1(親子付け)および方法2(移動量加算)は、Transform操作によるプレイヤー移動に適用可能です。
  • 物理演算ベースの移動(Rigidbodyを使用した移動)
    → 方法1、方法2も使用可能ですが、物理エンジンとの整合性(衝突判定、力の影響など)に注意が必要です。
    → より自然な物理連動を実現するには、方法3(FixedJoint/FixedJoint2D)の利用が推奨されます。

4. まとめ

Unityにおけるキャラクターと動く床の連動動作は、以下の3つの方法で実現できます。

  • 方法1:キャラクターを床の子オブジェクトにする
    • メリット: シンプルな実装で、床の移動と自動的に連動。
    • デメリット: 床の回転やスケールの影響を受けるため、床上でのプレイヤー移動ではローカル座標系への対応が必要。
  • 方法2:床の移動量をキャラクターに加算する
    • メリット: キャラクターのTransform(回転・スケール)に影響せず、床の移動を反映可能。
    • デメリット: 急激な床の動きには滑らかさが損なわれる可能性がある。
  • 方法3:FixedJoint/FixedJoint2Dを使用して物理的に接続する
    • メリット: 自然な物理挙動に基づく連動が実現できる。
    • デメリット: 物理計算負荷やパフォーマンスへの影響に注意が必要。

また、これらの方法は、プレイヤーの移動がTransform操作による単純な座標更新の場合でも、Rigidbodyを用いた物理演算ベースの場合でも対応可能です。特に方法1の場合、床上でのプレイヤー移動を実現するためには、入力処理をローカル座標系に合わせて調整するなどの工夫が必要となります。プロジェクトの仕様やパフォーマンス要件に合わせ、最適な手法を選択して実装してください。

Unity

Posted by hidepon