Physics.Simulate()
は Unity の物理システムの一部であり、物理シミュレーションを手動で進めるためのメソッドです。このメソッドを使用することで、物理エンジンの動作をより柔軟に制御でき、特定の条件下での物理的な動作をシミュレーションすることが可能です。
Physics.Simulate()
の基本的な解説Physics.Simulate(float time)
メソッドは、指定した時間だけ物理シミュレーションを進めます。引数にはシミュレーションを進める時間(秒数)を指定します。FixedUpdate()
メソッド内で自動的に行われますが、Physics.Simulate()
を使用することで、特定のタイミングで物理シミュレーションを進めたり、ユーザーの入力に基づいてカスタマイズした動作を実装したりできます。FixedUpdate()
との併用: Physics.Simulate()
を使用する際は、シミュレーションモードを Script
に設定する必要があります。これにより、物理エンジンが自動でシミュレーションを進めないようになります。以下は、ボールを移動させるために 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);
}
}
Physics.Simulate()
を使用する際は、Unity のプロジェクト設定で次の手順を行う必要があります:
Edit
> Project Settings
を開きます。Script
に変更します。これにより、Unityは物理シミュレーションを自動的には行わず、Physics.Simulate()
メソッドを呼び出すことでシミュレーションが進むようになります。
Physics.Simulate()
は、物理シミュレーションを手動で制御し、ユーザーの入力や特定のロジックに基づいて物理オブジェクトの挙動を調整するための強力な機能です。適切に使用することで、よりインタラクティブで魅力的なゲーム体験を提供できます。
以下は、サンプルプログラム「03_Move」>「Simulate」に用意した BallSimulation
の解説です。
このプログラムは、Unityにおける物理シミュレーションを利用して、ボールの動きを制御し、未来の軌道を視覚化するためのものです。
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;
}
}
public GameObject ball
: 操作対象のボールオブジェクト。Unityのインスペクターから設定可能です。public float simulateStep
: 物理シミュレーションを進める際のステップ時間(秒)。小さい値を設定すると、より細かいシミュレーションが行えます。public int futureSteps
: 未来を予測するためにシミュレーションするステップ数。LineRenderer
の位置数にも影響します。public LineRenderer lineRenderer
: 未来予測の軌道を描画するための LineRenderer
コンポーネント。public LayerMask obstacleMask
: 障害物を識別するためのレイヤーマスク。物理シミュレーションで衝突判定に使用します。
private Rigidbody ballRb
: ボールの物理特性を管理するための Rigidbody
コンポーネント。private Vector3 initialVelocity
: ボールの初速を保持します。private List<Vector3> pastPositions
: ボールの過去の位置を記録するリスト。private List<Vector3> pastVelocities
: ボールの過去の速度を記録するリスト。Start
メソッドRigidbody
を取得し、初速を設定しています。LineRenderer
の設定も行い、描画する線のスタイルや色を設定します。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>();
}
Update
メソッドA
キーが押されたときに AdvanceSimulation
メソッドを呼び出し、シミュレーションを進めます。B
キーが押されたときに ReversePlayback
メソッドを呼び出し、過去の状態を再生します。C
キーが押されたときに SimulateFutureTrajectory
メソッドを呼び出し、未来の軌道を計算します。void Update()
{
if (Input.GetKey(KeyCode.A)) AdvanceSimulation();
if (Input.GetKey(KeyCode.B)) ReversePlayback();
if (Input.GetKey(KeyCode.C)) SimulateFutureTrajectory();
}
AdvanceSimulation
メソッドRecordState
メソッドを使って記録した後、物理シミュレーションを進めます。private void AdvanceSimulation()
{
RecordState();
Physics.Simulate(simulateStep);
}
RecordState
メソッド。この情報は、逆再生や衝突時に使用されます。
private void RecordState()
{
pastPositions.Add(ball.transform.position);
pastVelocities.Add(ballRb.velocity);
}
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);
}
SimulateFutureTrajectory
メソッドPhysics.Simulate
を使って未来の位置を計算します。LineRenderer
で描画します。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());
}
CheckCollision
メソッドobstacleMask
を使って特定のレイヤーに限定しています。private bool CheckCollision(out RaycastHit hit)
{
return Physics.Raycast(ball.transform.position, ballRb.velocity.normalized, out hit, ballRb.velocity.magnitude * simulateStep, obstacleMask);
}
GetBallBounciness
メソッドprivate float GetBallBounciness()
{
return ball.GetComponent<Collider>().material.bounciness;
}
SaveBallState
: ボールの現在の位置、回転、速度、角速度を保存します。RestoreBallState
: 保存した状態を用いて、ボールの位置、回転、速度、角速度を復元します。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
メソッドは、Unityにおける物理エンジンの進行を制御するために使用されます。これにより、実際のフレームレートに依存せずに、任意の時間間隔で物理シミュレーションを進めることができます。
別の奇跡表示方法例 ・MiniGame like_AngryBird