Maemaemae

UnityでY方向に力を加える方法

質問内容

Unityにおいて、オブジェクトのY方向(上下方向)に力を加える方法を教えてください。特に以下の点について知りたいです:

  1. 基本的な力の適用方法
  2. 様々な力の適用モード(ForceMode)の違い
  3. 実践的な使用例(ジャンプ、浮力など)

回答

こんにちは!UnityでのY方向への力の適用方法について、実践的な観点から説明します。

1. 基本的な概念と構文

Unityでは主にRigidbodyコンポーネントを持つオブジェクトに対して力を加えることができます。Y方向(通常は上方向)への力の適用の基本的な方法は以下の通りです:

using UnityEngine;

public class ForceApplier : MonoBehaviour
{
    // インスペクターで設定できるパラメータ
    [SerializeField] private float forceAmount = 10f;

    // コンポーネント参照
    private Rigidbody rb;

    void Start()
    {
        // Rigidbodyコンポーネントの取得
        rb = GetComponent<Rigidbody>();
    }

    void Update()
    {
        // 例:スペースキーを押したときにY方向に力を加える
        if (Input.GetKeyDown(KeyCode.Space))
        {
            ApplyYForce();
        }
    }

    void ApplyYForce()
    {
        // 方法1: 座標を直接指定
        rb.AddForce(0, forceAmount, 0);

        // 方法2: Vector3.upを使用
        // rb.AddForce(Vector3.up * forceAmount);
    }
}

2. 異なる力の適用モード(ForceMode)

Unityでは力を加える際の挙動を制御する4つのForceModeが用意されています:

// 継続的な力を加える (F = ma) - デフォルト
rb.AddForce(Vector3.up * forceAmount, ForceMode.Force);

// 瞬間的な力(インパルス)を加える
rb.AddForce(Vector3.up * forceAmount, ForceMode.Impulse);

// 質量を無視して加速度として適用
rb.AddForce(Vector3.up * forceAmount, ForceMode.Acceleration);

// 質量を無視して速度変化として適用
rb.AddForce(Vector3.up * forceAmount, ForceMode.VelocityChange);

各モードの特徴と使い分け:

ForceMode.Force

ForceMode.Impulse

ForceMode.Acceleration

ForceMode.VelocityChange

3. 実践的な使用例

3.1 ジャンプ機能の実装

using UnityEngine;

public class CharacterJump : MonoBehaviour
{
    [SerializeField] private float jumpForce = 5f;
    [SerializeField] private Transform groundCheck;
    [SerializeField] private float groundCheckRadius = 0.2f;
    [SerializeField] private LayerMask groundLayer;

    private Rigidbody rb;
    private bool isGrounded;

    void Start()
    {
        rb = GetComponent<Rigidbody>();
    }

    void Update()
    {
        // 地面との接触を判定
        isGrounded = Physics.CheckSphere(groundCheck.position, groundCheckRadius, groundLayer);

        // ジャンプ入力
        if (Input.GetKeyDown(KeyCode.Space) && isGrounded)
        {
            Jump();
        }
    }

    void Jump()
    {
        // ジャンプにはImpulseモードが適している
        rb.AddForce(Vector3.up * jumpForce, ForceMode.Impulse);
    }
}

3.2 浮力の実装

using UnityEngine;

public class BuoyancyEffect : MonoBehaviour
{
    [SerializeField] private float volume = 1.0f;
    [SerializeField] private float waterDensity = 1.0f;
    [SerializeField] private Transform waterSurfaceCheck;

    private Rigidbody rb;
    private bool isUnderwater;

    void Start()
    {
        rb = GetComponent<Rigidbody>();
    }

    void FixedUpdate()
    {
        // 水中判定
        isUnderwater = waterSurfaceCheck.position.y < 0; // 0を水面の高さに置き換え

        if (isUnderwater)
        {
            // アルキメデスの原理に基づく浮力
            float buoyancyForce = volume * waterDensity * Physics.gravity.magnitude;
            rb.AddForce(Vector3.up * buoyancyForce);
        }
    }
}

3.3 風力や揚力の実装

using UnityEngine;

public class WindLiftEffect : MonoBehaviour
{
    [SerializeField] private float windStrength = 2.0f;
    [SerializeField] private float maxWindEffect = 10.0f;
    [SerializeField] private AnimationCurve windCurve;

    private Rigidbody rb;
    private float currentWindTime = 0f;

    void Start()
    {
        rb = GetComponent<Rigidbody>();
    }

    void FixedUpdate()
    {
        // 時間経過に基づく風の強さの変化
        currentWindTime += Time.fixedDeltaTime;
        float windEffect = windCurve.Evaluate(Mathf.PingPong(currentWindTime, 1.0f)) * maxWindEffect;

        // Y方向に風力を適用
        rb.AddForce(Vector3.up * windStrength * windEffect);
    }
}

4. 直接速度を変更する方法

AddForceの代わりに、直接速度を設定することもできます:

void SetYVelocity(float yVelocity)
{
    // 現在のX, Z速度を維持しつつ、Y速度のみを変更
    rb.velocity = new Vector3(rb.velocity.x, yVelocity, rb.velocity.z);
}

これは即時的な速度変更が必要な場合(例:二段ジャンプ、速度のリセットなど)に有効です。

実装時の注意点

参考資料とリンク

更新履歴


この回答は、Unity 2022.3 LTS を基準に作成されています。新しいバージョンでは仕様が変更されている可能性があるため、適宜公式ドキュメントを参照してください。

Unity物理演算Rigidbody力学ゲーム開発AddForce