Unity_Lesson

Physics.Simulate() は Unity の物理システムの一部であり、物理シミュレーションを手動で進めるためのメソッドです。このメソッドを使用することで、物理エンジンの動作をより柔軟に制御でき、特定の条件下での物理的な動作をシミュレーションすることが可能です。

Physics.Simulate() の基本的な解説

1. 概要

2. 使用目的

3. 使用する際の注意点

4. 例: ボールの移動

以下は、ボールを移動させるために Physics.Simulate() を使用する簡単な例です。この例では、ボールの移動を手動で管理し、シミュレーションを進めることでボールの挙動を確認します。

using UnityEngine;

public class BallMovement : MonoBehaviour
{
    public GameObject ball;                // 操作対象のボールオブジェクト
    public float simulateStep = 0.02f;     // 物理シミュレーションの1ステップ時間
    public float moveSpeed = 5.0f;         // ボールの移動速度

    private Rigidbody ballRb;

    void Start()
    {
        ballRb = ball.GetComponent<Rigidbody>();
        ballRb.velocity = Vector3.zero; // 初期速度をゼロに設定
    }

    void Update()
    {
        // ユーザーの入力に基づいてボールを移動させる
        Vector3 moveDirection = Vector3.zero;
        if (Input.GetKey(KeyCode.W)) moveDirection += Vector3.forward;
        if (Input.GetKey(KeyCode.S)) moveDirection += Vector3.back;
        if (Input.GetKey(KeyCode.A)) moveDirection += Vector3.left;
        if (Input.GetKey(KeyCode.D)) moveDirection += Vector3.right;

        ballRb.velocity = moveDirection.normalized * moveSpeed;

        // シミュレーションを進める
        Physics.Simulate(simulateStep);
    }
}

5. プロジェクト設定

Physics.Simulate() を使用する際は、Unity のプロジェクト設定で次の手順を行う必要があります:

  1. Unityエディタのメニューから Edit > Project Settings を開きます。
  2. Physics の設定を選択します。
  3. Simulation ModeScript に変更します。

これにより、Unityは物理シミュレーションを自動的には行わず、Physics.Simulate() メソッドを呼び出すことでシミュレーションが進むようになります。

まとめ

Physics.Simulate() は、物理シミュレーションを手動で制御し、ユーザーの入力や特定のロジックに基づいて物理オブジェクトの挙動を調整するための強力な機能です。適切に使用することで、よりインタラクティブで魅力的なゲーム体験を提供できます。







以下は、サンプルプログラム「03_Move」>「Simulate」に用意した BallSimulation の解説です。

このプログラムは、Unityにおける物理シミュレーションを利用して、ボールの動きを制御し、未来の軌道を視覚化するためのものです。

サンプルプログラム2

public class BallSimulation : MonoBehaviour
{
    public GameObject ball;                // 操作対象のボールオブジェクト
    public float simulateStep = 0.02f;     // 物理シミュレーションの1ステップ時間
    public int futureSteps = 100;          // 未来予測のシミュレーションステップ数
    public LineRenderer lineRenderer;      // 未来予測用のラインレンダラー
    public LayerMask obstacleMask;         // 障害物のレイヤーマスク

    private Rigidbody ballRb;              // ボールのRigidbodyコンポーネント
    private Vector3 initialVelocity;       // ボールの初速
    private List<Vector3> pastPositions;   // 過去の位置を保存
    private List<Vector3> pastVelocities;  // 過去の速度を保存

    void Start()
    {
        // ボールの初期化処理
        ballRb = ball.GetComponent<Rigidbody>();
        initialVelocity = new Vector3(1.0f, 5.0f, 0.0f); // ボールに初速を設定
        ballRb.velocity = initialVelocity;

        // LineRendererの設定
        lineRenderer.positionCount = futureSteps;
        lineRenderer.startWidth = 0.1f;
        lineRenderer.endWidth = 0.1f;
        Material lineMaterial = new Material(Shader.Find("Sprites/Default"));
        lineRenderer.material = lineMaterial;
        lineRenderer.startColor = Color.green;
        lineRenderer.endColor = Color.blue;

        // 状態を保存するリストの初期化
        pastPositions = new List<Vector3>();
        pastVelocities = new List<Vector3>();
    }

    void Update()
    {
        // Aキーでシミュレーションを進める
        if (Input.GetKey(KeyCode.A)) AdvanceSimulation();
        // Bキーでシミュレーションを逆再生する
        if (Input.GetKey(KeyCode.B)) ReversePlayback();
        // Cキーで未来予測の軌道を計算する
        if (Input.GetKey(KeyCode.C)) SimulateFutureTrajectory();
    }

    private void AdvanceSimulation()
    {
        // 現在の状態を記録
        RecordState();
        // 物理シミュレーションを1ステップ進める
        Physics.Simulate(simulateStep);
    }

    private void RecordState()
    {
        pastPositions.Add(ball.transform.position);
        pastVelocities.Add(ballRb.velocity);
    }

    private void ReversePlayback()
    {
        if (pastPositions.Count == 0 || pastVelocities.Count == 0) return;

        // 過去の状態を復元
        ball.transform.position = pastPositions[^1];
        ballRb.velocity = pastVelocities[^1];

        // 最新のデータをリストから削除
        pastPositions.RemoveAt(pastPositions.Count - 1);
        pastVelocities.RemoveAt(pastVelocities.Count - 1);
    }

    private void SimulateFutureTrajectory()
    {
        // 元のボールの状態を保存
        SaveBallState(out Vector3 originalPosition, out Quaternion originalRotation, out Vector3 originalVelocity, out Vector3 originalAngularVelocity);

        // 未来予測の位置リスト
        List<Vector3> futurePositions = new List<Vector3>();
        float bounciness = GetBallBounciness();

        // 未来予測のシミュレーションを実行
        for (int i = 0; i < futureSteps; i++)
        {
            Physics.Simulate(simulateStep);
            futurePositions.Add(ball.transform.position);

            // 衝突が発生した場合、反射ベクトルを計算
            if (CheckCollision(out RaycastHit hit))
            {
                Vector3 reflectDirection = Vector3.Reflect(ballRb.velocity, hit.normal);
                ballRb.velocity = reflectDirection * bounciness;
            }
        }

        // ボールの状態を元に戻す
        RestoreBallState(originalPosition, originalRotation, originalVelocity, originalAngularVelocity);

        // LineRendererで未来の軌道を描画
        lineRenderer.positionCount = futurePositions.Count;
        lineRenderer.SetPositions(futurePositions.ToArray());
    }

    private bool CheckCollision(out RaycastHit hit)
    {
        return Physics.Raycast(ball.transform.position, ballRb.velocity.normalized, out hit, ballRb.velocity.magnitude * simulateStep, obstacleMask);
    }

    private float GetBallBounciness()
    {
        return ball.GetComponent<Collider>().material.bounciness;
    }

    private void SaveBallState(out Vector3 position, out Quaternion rotation, out Vector3 velocity, out Vector3 angularVelocity)
    {
        position = ball.transform.position;
        rotation = ball.transform.rotation;
        velocity = ballRb.velocity;
        angularVelocity = ballRb.angularVelocity;
    }

    private void RestoreBallState(Vector3 position, Quaternion rotation, Vector3 velocity, Vector3 angularVelocity)
    {
        ball.transform.position = position;
        ball.transform.rotation = rotation;
        ballRb.velocity = velocity;
        ballRb.angularVelocity = angularVelocity;
    }
}

各メソッドの詳細解説

1. クラスのメンバー変数


2. Start メソッド

void Start()
{
    ballRb = ball.GetComponent<Rigidbody>();
    initialVelocity = new Vector3(1.0f, 5.0f, 0.0f); // ボールに初速を設定
    ballRb.velocity = initialVelocity;

    // LineRendererの設定
    lineRenderer.positionCount = futureSteps;
    lineRenderer.startWidth = 0.1f;
    lineRenderer.endWidth = 0.1f;
    Material lineMaterial = new Material(Shader.Find("Sprites/Default"));
    lineRenderer.material = lineMaterial;
    lineRenderer.startColor = Color.green;
    lineRenderer.endColor = Color.blue;

    pastPositions = new List<Vector3>();
    pastVelocities = new List<Vector3>();
}

3. Update メソッド

void Update()
{
    if (Input.GetKey(KeyCode.A)) AdvanceSimulation();
    if (Input.GetKey(KeyCode.B)) ReversePlayback();
    if (Input.GetKey(KeyCode.C)) SimulateFutureTrajectory();
}

4. AdvanceSimulation メソッド

private void AdvanceSimulation()
{
    RecordState();
    Physics.Simulate(simulateStep);
}

5. RecordState メソッド

。この情報は、逆再生や衝突時に使用されます。

private void RecordState()
{
    pastPositions.Add(ball.transform.position);
    pastVelocities.Add(ballRb.velocity);
}

6. ReversePlayback メソッド

private void ReversePlayback()
{
    if (pastPositions.Count == 0 || pastVelocities.Count == 0) return;

    ball.transform.position = pastPositions[^1];
    ballRb.velocity = pastVelocities[^1];

    pastPositions.RemoveAt(pastPositions.Count - 1);
    pastVelocities.RemoveAt(pastVelocities.Count - 1);
}

7. SimulateFutureTrajectory メソッド

private void SimulateFutureTrajectory()
{
    SaveBallState(out Vector3 originalPosition, out Quaternion originalRotation, out Vector3 originalVelocity, out Vector3 originalAngularVelocity);
    List<Vector3> futurePositions = new List<Vector3>();
    float bounciness = GetBallBounciness();

    for (int i = 0; i < futureSteps; i++)
    {
        Physics.Simulate(simulateStep);
        futurePositions.Add(ball.transform.position);

        if (CheckCollision(out RaycastHit hit))
        {
            Vector3 reflectDirection = Vector3.Reflect(ballRb.velocity, hit.normal);
            ballRb.velocity = reflectDirection * bounciness;
        }
    }

    RestoreBallState(originalPosition, originalRotation, originalVelocity, originalAngularVelocity);
    lineRenderer.positionCount = futurePositions.Count;
    lineRenderer.SetPositions(futurePositions.ToArray());
}

8. CheckCollision メソッド

private bool CheckCollision(out RaycastHit hit)
{
    return Physics.Raycast(ball.transform.position, ballRb.velocity.normalized, out hit, ballRb.velocity.magnitude * simulateStep, obstacleMask);
}

9. GetBallBounciness メソッド

private float GetBallBounciness()
{
    return ball.GetComponent<Collider>().material.bounciness;
}

10. 状態管理メソッド

private void SaveBallState(out Vector3 position, out Quaternion rotation, out Vector3 velocity, out Vector3 angularVelocity)
{
    position = ball.transform.position;
    rotation = ball.transform.rotation;
    velocity = ballRb.velocity;
    angularVelocity = ballRb.angularVelocity;
}

private void RestoreBallState(Vector3 position, Quaternion rotation, Vector3 velocity, Vector3 angularVelocity)
{
    ball.transform.position = position;
    ball.transform.rotation = rotation;
    ballRb.velocity = velocity;
    ballRb.angularVelocity = angularVelocity;
}

Physics.Simulate の解説

Physics.Simulate メソッドは、Unityにおける物理エンジンの進行を制御するために使用されます。これにより、実際のフレームレートに依存せずに、任意の時間間隔で物理シミュレーションを進めることができます。

メリット

デメリット



別の奇跡表示方法例 ・MiniGame like_AngryBird