Files
coplaydev--unity-mcp/MCPForUnity/Editor/Tools/Physics/PhysicsSimulationOps.cs
T
2026-07-13 12:49:17 +08:00

180 lines
6.7 KiB
C#

using System.Collections.Generic;
using MCPForUnity.Editor.Helpers;
using Newtonsoft.Json.Linq;
using UnityEngine;
using MCPForUnity.Runtime.Helpers;
namespace MCPForUnity.Editor.Tools.Physics
{
internal static class PhysicsSimulationOps
{
public static object SimulateStep(JObject @params)
{
var p = new ToolParams(@params);
string dimension = (p.Get("dimension") ?? "3d").ToLowerInvariant();
int steps = Mathf.Clamp(p.GetInt("steps") ?? 1, 1, 100);
float stepSize = p.GetFloat("step_size") ?? Time.fixedDeltaTime;
string targetStr = p.Get("target");
string searchMethod = p.Get("search_method");
if (dimension != "3d" && dimension != "2d")
return new ErrorResponse($"Invalid dimension: '{dimension}'. Use '3d' or '2d'.");
if (dimension == "2d")
{
Physics2D.SyncTransforms();
for (int i = 0; i < steps; i++)
Physics2D.Simulate(stepSize);
}
else
{
UnityEngine.Physics.SyncTransforms();
var prevMode = UnityPhysicsCompat.GetPhysicsSimulationMode();
if (prevMode != UnityPhysicsCompat.SimulationMode.Script)
UnityPhysicsCompat.TrySetPhysicsSimulationMode(UnityPhysicsCompat.SimulationMode.Script);
try
{
for (int i = 0; i < steps; i++)
UnityEngine.Physics.Simulate(stepSize);
}
finally
{
if (prevMode != UnityPhysicsCompat.SimulationMode.Unknown
&& prevMode != UnityPhysicsCompat.SimulationMode.Script)
{
UnityPhysicsCompat.TrySetPhysicsSimulationMode(prevMode);
}
}
}
// Collect rigidbody states after simulation
List<object> rigidbodies;
if (!string.IsNullOrEmpty(targetStr))
{
rigidbodies = CollectTargetRigidbody(targetStr, searchMethod, dimension);
}
else
{
rigidbodies = CollectActiveRigidbodies(dimension);
}
return new
{
success = true,
message = $"Executed {steps} physics step(s) ({dimension.ToUpper()}, step_size={stepSize:F4}s).",
data = new
{
steps_executed = steps,
step_size = stepSize,
dimension,
rigidbodies
}
};
}
private static List<object> CollectTargetRigidbody(string targetStr, string searchMethod, string dimension)
{
var results = new List<object>();
var go = GameObjectLookup.FindByTarget(JToken.FromObject(targetStr), searchMethod ?? "by_name");
if (go == null)
return results;
if (dimension == "2d")
{
var rb2d = go.GetComponent<Rigidbody2D>();
if (rb2d != null)
{
results.Add(new
{
name = go.name,
instanceID = go.GetInstanceIDCompat(),
position = new[] { rb2d.position.x, rb2d.position.y },
#if UNITY_6000_0_OR_NEWER
velocity = new[] { rb2d.linearVelocity.x, rb2d.linearVelocity.y },
#else
velocity = new[] { rb2d.velocity.x, rb2d.velocity.y },
#endif
angularVelocity = rb2d.angularVelocity
});
}
}
else
{
var rb = go.GetComponent<Rigidbody>();
if (rb != null)
{
results.Add(new
{
name = go.name,
instanceID = go.GetInstanceIDCompat(),
position = new[] { rb.position.x, rb.position.y, rb.position.z },
#if UNITY_6000_0_OR_NEWER
velocity = new[] { rb.linearVelocity.x, rb.linearVelocity.y, rb.linearVelocity.z },
#else
velocity = new[] { rb.velocity.x, rb.velocity.y, rb.velocity.z },
#endif
angularVelocity = new[] { rb.angularVelocity.x, rb.angularVelocity.y, rb.angularVelocity.z }
});
}
}
return results;
}
private static List<object> CollectActiveRigidbodies(string dimension)
{
var results = new List<object>();
const int maxResults = 50;
if (dimension == "2d")
{
var allRb2d = UnityFindObjectsCompat.FindAll<Rigidbody2D>();
foreach (var rb2d in allRb2d)
{
if (results.Count >= maxResults) break;
if (rb2d.bodyType == RigidbodyType2D.Static) continue;
if (rb2d.IsSleeping()) continue;
results.Add(new
{
name = rb2d.gameObject.name,
instanceID = rb2d.gameObject.GetInstanceIDCompat(),
position = new[] { rb2d.position.x, rb2d.position.y },
#if UNITY_6000_0_OR_NEWER
velocity = new[] { rb2d.linearVelocity.x, rb2d.linearVelocity.y },
#else
velocity = new[] { rb2d.velocity.x, rb2d.velocity.y },
#endif
angularVelocity = rb2d.angularVelocity
});
}
}
else
{
var allRb = UnityFindObjectsCompat.FindAll<Rigidbody>();
foreach (var rb in allRb)
{
if (results.Count >= maxResults) break;
if (rb.isKinematic) continue;
if (rb.IsSleeping()) continue;
results.Add(new
{
name = rb.gameObject.name,
instanceID = rb.gameObject.GetInstanceIDCompat(),
position = new[] { rb.position.x, rb.position.y, rb.position.z },
#if UNITY_6000_0_OR_NEWER
velocity = new[] { rb.linearVelocity.x, rb.linearVelocity.y, rb.linearVelocity.z },
#else
velocity = new[] { rb.velocity.x, rb.velocity.y, rb.velocity.z },
#endif
angularVelocity = new[] { rb.angularVelocity.x, rb.angularVelocity.y, rb.angularVelocity.z }
});
}
}
return results;
}
}
}