もふもふ技術部

IT技術系mofmofメディア

Unityで重力を設定した球体の惑星の上を歩き回る

地球上に立っている人が剛速球を投げて、地球を1回転して戻って来て自分でキャッチするための条件を確かめるためにUnityの物理エンジンでシミュレーションしようと思ったので、まずは自由に動き回れる惑星を実装してみた。ドラゴンボールの界王星みたいな感じ。

オブジェクトの配置

まず適当なプロジェクトを作り、直径30mほどの球を配置する。

Hierarchy - 3D Object - Sphere

  • Positionは全て0
  • Rotationは全て0
  • Scale X: 30, Y:30, Z:30

オブジェクトにPlanetという名前をつけておく。

目印用に適当にCubeをおいておく。

Hierarchy - 3D Object - Cube

  • Position X:0, Y:17, Z:0
  • Rotationは全て0
  • Scaleは全て1

ComponentにRigidBody, Box Colliderをセット。独自の重力を実装するためUse Gravityをオフにしておく。

次に操作するプレイヤーを作り、カメラを追従させる。だいぶ昔にやったことあるので、この辺のポストを参照。

www.mof-mof.co.jp

Hierarchy - CreateEmpty

オブジェクトにPlayerという名前をつける。

  • Position X:0, Y:16, Z:-4
  • Rotationは全て0
  • Scaleは全て1

こちらもRigidBody, Box Colliderをセット。Use Gravityをオフ。

Hierarchyビューから、Main CameraをドラッグしてPlayerの下に入れておく。

重力の実装

Use Gravityをオフにしているのでこのままだと浮いた状態になっている。そこで、Planetの中心に重力点があるようにスクリプトで実装する。

Player - Inspector - Add Component - New Script - Planet Gravity

PlayerGravity.cs

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

public class PlanetGravity : MonoBehaviour
{
    [SerializeField] private Transform sphereCenter; // 重力の中心
    [SerializeField] private float gravityStrength = 9.8f; // 重力の強さ
    private float rotationSpeed = 50f;

    private Rigidbody rb;

    // Start is called before the first frame update
    void Start()
    {
         // このオブジェクトのRigidbodyを取得
        rb = GetComponent<Rigidbody>();

        // Rigidbodyがアタッチされていない場合、警告を表示
        if (rb == null)
        {
            Debug.LogWarning("Rigidbodyがアタッチされていません。重力の適用にはRigidbodyが必要です。");
        }   
    }

    void FixedUpdate()
    {
        if (rb == null || sphereCenter == null) return;

        // 球の中心へのベクトルを計算(法線)
        Vector3 direction = (sphereCenter.position - transform.position).normalized;

        // 重力の力を計算
        Vector3 gravityForce = direction * gravityStrength * rb.mass;

        // Rigidbodyに力を適用
        rb.AddForce(gravityForce);

        // 法線ベクトルに従って、プレイヤーの縦方向のRotationを更新する
        Quaternion targetRotation = Quaternion.FromToRotation(-transform.up, direction) * transform.rotation;
        transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, rotationSpeed * Time.deltaTime);
    }
}

同様にPlayerだけでなくCubeにもこのスクリプトをAttachしておく。

次に、Planet上を歩き回るコードを実装。

Player - Inspector - Add Component - New Script - WalkOnPlanet

WalkOnPlanet.cs

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

public class WalkOnPlanet : MonoBehaviour
{
    public Transform sphereCenter; // 球体の中心
    public float speed = 5f; // プレイヤーの移動速度
    public float rotationSpeed = 80f; // プレイヤーの回転速度

    private Rigidbody rb;

    // Start is called before the first frame update
    void Start()
    {
        rb = GetComponent<Rigidbody>();
        if (rb != null)
        {
            rb.useGravity = false; // Unityのデフォルトの重力を無効化
            rb.constraints = RigidbodyConstraints.FreezeRotation; // 自動回転を防止
        }
    }

    // Update is called once per frame
    void Update()
    {
        if (sphereCenter == null) return;

        // 入力の取得
        float horizontal = Input.GetAxis("Horizontal");
        float vertical = Input.GetAxis("Vertical");

        // プレイヤーの移動
        Vector3 movement = transform.forward * vertical;
        rb.MovePosition(rb.position + movement * speed * Time.deltaTime);

        transform.Rotate(Vector3.up, horizontal * rotationSpeed * Time.deltaTime);
    }
}

これで上下キーで進行・後退、左右キーで向きを回転出来る。WASDキーでも動作する。

背景の変更

Unityのデフォルト背景だと、惑星上を移動したとき上下が変な感じになるので、上下がないような背景に変更する。今回は宇宙っぽい感じにしてみる。

Asset StoreにSkybox Series Freeというものがあったので、今回はこれを使ってみる。Open in Unityをして、開いたダイアログからImportする。

Skybox Series Free | 2D Sky | Unity Asset Store

importが済んだら、以下から設定する。

Window - Rendering - Lightning - Environment - Skybox Material - 6sidedCosmicCoolCloud

できたああああ!!