Merge RVO2 benchmark adapter
This commit is contained in:
@@ -11,6 +11,7 @@ namespace FishROV.AvoidanceBenchmark
|
|||||||
case AvoidanceFrameworkKind.AstarRvo:
|
case AvoidanceFrameworkKind.AstarRvo:
|
||||||
return new AstarRvoAdapter();
|
return new AstarRvoAdapter();
|
||||||
case AvoidanceFrameworkKind.Rvo2:
|
case AvoidanceFrameworkKind.Rvo2:
|
||||||
|
return new Rvo2Adapter();
|
||||||
case AvoidanceFrameworkKind.UnityNavMesh:
|
case AvoidanceFrameworkKind.UnityNavMesh:
|
||||||
return new UnavailableAvoidanceAdapter(kind);
|
return new UnavailableAvoidanceAdapter(kind);
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -0,0 +1,513 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Reflection;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace FishROV.AvoidanceBenchmark
|
||||||
|
{
|
||||||
|
public sealed class Rvo2Adapter : IAvoidanceAdapter
|
||||||
|
{
|
||||||
|
private readonly Dictionary<BenchmarkAgent, int> agentIds = new Dictionary<BenchmarkAgent, int>();
|
||||||
|
private Rvo2ReflectionBridge bridge;
|
||||||
|
private AvoidanceBenchmarkConfig config;
|
||||||
|
private bool initialized;
|
||||||
|
|
||||||
|
public string Name => "RVO2 / RVO2-3D";
|
||||||
|
public bool IsAvailable => bridge != null && bridge.IsAvailable;
|
||||||
|
public string Status => bridge != null
|
||||||
|
? bridge.Status
|
||||||
|
: Rvo2ReflectionBridge.MissingPackageStatus;
|
||||||
|
|
||||||
|
public void Initialize(AvoidanceBenchmarkConfig config)
|
||||||
|
{
|
||||||
|
this.config = config.Clone();
|
||||||
|
agentIds.Clear();
|
||||||
|
bridge = Rvo2ReflectionBridge.Create(this.config);
|
||||||
|
initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BenchmarkAgent CreateAgent(BenchmarkAgentSpawnInfo spawnInfo, Transform parent)
|
||||||
|
{
|
||||||
|
var agent = BenchmarkAgent.CreatePrimitive(spawnInfo, parent);
|
||||||
|
|
||||||
|
if (!initialized || bridge == null || !bridge.IsAvailable)
|
||||||
|
{
|
||||||
|
return agent;
|
||||||
|
}
|
||||||
|
|
||||||
|
var id = bridge.AddAgent(spawnInfo);
|
||||||
|
if (id >= 0)
|
||||||
|
{
|
||||||
|
agentIds[agent] = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
return agent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetPreferredVelocity(BenchmarkAgent agent, Vector3 preferredVelocity)
|
||||||
|
{
|
||||||
|
if (bridge == null || !bridge.IsAvailable || !agentIds.TryGetValue(agent, out var id))
|
||||||
|
{
|
||||||
|
agent.ApplyVelocity(preferredVelocity);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bridge.SetPreferredVelocity(id, preferredVelocity);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetTarget(BenchmarkAgent agent, Vector3 target)
|
||||||
|
{
|
||||||
|
agent.Target = target;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Tick(float deltaTime)
|
||||||
|
{
|
||||||
|
if (bridge == null || !bridge.IsAvailable)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bridge.Step(deltaTime);
|
||||||
|
|
||||||
|
foreach (var pair in agentIds)
|
||||||
|
{
|
||||||
|
pair.Key.ApplyVelocity(bridge.GetVelocity(pair.Value, pair.Key.MaxSpeed));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
agentIds.Clear();
|
||||||
|
bridge?.Dispose();
|
||||||
|
bridge = null;
|
||||||
|
initialized = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private sealed class Rvo2ReflectionBridge
|
||||||
|
{
|
||||||
|
public const string MissingPackageStatus =
|
||||||
|
"RVO2 package/source not found. Place the RVO2 or RVO2-3D C# source/package in Assets or Packages with a Simulator type such as RVO.Simulator; this adapter will bind by reflection.";
|
||||||
|
|
||||||
|
private static readonly string[] SimulatorTypeNames =
|
||||||
|
{
|
||||||
|
"RVO.Simulator",
|
||||||
|
"RVO2.Simulator",
|
||||||
|
"RVO3D.Simulator",
|
||||||
|
"RVO.Simulator3D"
|
||||||
|
};
|
||||||
|
|
||||||
|
private readonly object simulator;
|
||||||
|
private readonly Type simulatorType;
|
||||||
|
private readonly Type vector2Type;
|
||||||
|
private readonly Type vector3Type;
|
||||||
|
private readonly bool use3D;
|
||||||
|
private readonly string status;
|
||||||
|
private readonly MethodInfo addAgent;
|
||||||
|
private readonly MethodInfo setAgentPrefVelocity;
|
||||||
|
private readonly MethodInfo doStep;
|
||||||
|
private readonly MethodInfo getAgentVelocity;
|
||||||
|
private readonly MethodInfo setTimeStep;
|
||||||
|
private readonly MethodInfo setAgentDefaults;
|
||||||
|
private readonly MethodInfo clear;
|
||||||
|
|
||||||
|
private Rvo2ReflectionBridge(
|
||||||
|
object simulator,
|
||||||
|
Type simulatorType,
|
||||||
|
Type vector2Type,
|
||||||
|
Type vector3Type,
|
||||||
|
bool use3D,
|
||||||
|
string status,
|
||||||
|
MethodInfo addAgent,
|
||||||
|
MethodInfo setAgentPrefVelocity,
|
||||||
|
MethodInfo doStep,
|
||||||
|
MethodInfo getAgentVelocity,
|
||||||
|
MethodInfo setTimeStep,
|
||||||
|
MethodInfo setAgentDefaults,
|
||||||
|
MethodInfo clear)
|
||||||
|
{
|
||||||
|
this.simulator = simulator;
|
||||||
|
this.simulatorType = simulatorType;
|
||||||
|
this.vector2Type = vector2Type;
|
||||||
|
this.vector3Type = vector3Type;
|
||||||
|
this.use3D = use3D;
|
||||||
|
this.status = status;
|
||||||
|
this.addAgent = addAgent;
|
||||||
|
this.setAgentPrefVelocity = setAgentPrefVelocity;
|
||||||
|
this.doStep = doStep;
|
||||||
|
this.getAgentVelocity = getAgentVelocity;
|
||||||
|
this.setTimeStep = setTimeStep;
|
||||||
|
this.setAgentDefaults = setAgentDefaults;
|
||||||
|
this.clear = clear;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsAvailable => simulator != null;
|
||||||
|
public string Status => status;
|
||||||
|
|
||||||
|
public static Rvo2ReflectionBridge Create(AvoidanceBenchmarkConfig config)
|
||||||
|
{
|
||||||
|
var simulatorType = FindType(SimulatorTypeNames);
|
||||||
|
if (simulatorType == null)
|
||||||
|
{
|
||||||
|
return Unavailable();
|
||||||
|
}
|
||||||
|
|
||||||
|
var simulator = CreateOrGetSimulator(simulatorType);
|
||||||
|
if (simulator == null)
|
||||||
|
{
|
||||||
|
return Unavailable("RVO2 Simulator type was found, but no singleton instance or public constructor could be used.");
|
||||||
|
}
|
||||||
|
|
||||||
|
var vector2Type = FindType(simulatorType, "RVO.Vector2", "RVO2.Vector2");
|
||||||
|
var vector3Type = FindType(simulatorType, "RVO.Vector3", "RVO3D.Vector3", "RVO2.Vector3");
|
||||||
|
var use3D = config.DimensionMode == AvoidanceDimensionMode.XYZ3D && vector3Type != null;
|
||||||
|
var agentVectorType = use3D ? vector3Type : vector2Type;
|
||||||
|
if (agentVectorType == null)
|
||||||
|
{
|
||||||
|
return Unavailable("RVO2 Simulator type was found, but no supported RVO.Vector2 or RVO.Vector3 type was found.");
|
||||||
|
}
|
||||||
|
|
||||||
|
var addAgent = FindMethod(simulatorType, "addAgent", "AddAgent", new[] { agentVectorType });
|
||||||
|
var setAgentPrefVelocity = FindMethod(simulatorType, "setAgentPrefVelocity", "SetAgentPrefVelocity", new[] { typeof(int), agentVectorType });
|
||||||
|
var getAgentVelocity = FindMethod(simulatorType, "getAgentVelocity", "GetAgentVelocity", new[] { typeof(int) });
|
||||||
|
var doStep = FindMethod(simulatorType, "doStep", "DoStep", Type.EmptyTypes);
|
||||||
|
var setTimeStep = FindMethod(simulatorType, "setTimeStep", "SetTimeStep", new[] { typeof(float) });
|
||||||
|
var setAgentDefaults = FindMethodByName(simulatorType, "setAgentDefaults", "SetAgentDefaults");
|
||||||
|
var clear = FindMethodByName(simulatorType, "clear", "Clear", "reset", "Reset");
|
||||||
|
|
||||||
|
if (addAgent == null || setAgentPrefVelocity == null || getAgentVelocity == null || doStep == null)
|
||||||
|
{
|
||||||
|
return Unavailable("RVO2 Simulator type was found, but required methods addAgent, setAgentPrefVelocity, getAgentVelocity, and doStep were not all available.");
|
||||||
|
}
|
||||||
|
|
||||||
|
var bridge = new Rvo2ReflectionBridge(
|
||||||
|
simulator,
|
||||||
|
simulatorType,
|
||||||
|
vector2Type,
|
||||||
|
vector3Type,
|
||||||
|
use3D,
|
||||||
|
use3D ? "RVO2-3D reflection adapter active" : "RVO2 reflection adapter active",
|
||||||
|
addAgent,
|
||||||
|
setAgentPrefVelocity,
|
||||||
|
doStep,
|
||||||
|
getAgentVelocity,
|
||||||
|
setTimeStep,
|
||||||
|
setAgentDefaults,
|
||||||
|
clear);
|
||||||
|
|
||||||
|
bridge.Configure(config);
|
||||||
|
return bridge;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int AddAgent(BenchmarkAgentSpawnInfo spawnInfo)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var result = addAgent.Invoke(simulator, new[] { ToRvoVector(spawnInfo.Position) });
|
||||||
|
return Convert.ToInt32(result);
|
||||||
|
}
|
||||||
|
catch (Exception exception)
|
||||||
|
{
|
||||||
|
Debug.LogWarning($"RVO2 addAgent failed: {exception.Message}");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetPreferredVelocity(int id, Vector3 preferredVelocity)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
setAgentPrefVelocity.Invoke(simulator, new[] { id, ToRvoVector(preferredVelocity) });
|
||||||
|
}
|
||||||
|
catch (Exception exception)
|
||||||
|
{
|
||||||
|
Debug.LogWarning($"RVO2 setAgentPrefVelocity failed: {exception.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Step(float deltaTime)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
InvokeSetTimeStep(deltaTime);
|
||||||
|
doStep.Invoke(simulator, null);
|
||||||
|
}
|
||||||
|
catch (Exception exception)
|
||||||
|
{
|
||||||
|
Debug.LogWarning($"RVO2 doStep failed: {exception.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector3 GetVelocity(int id, float maxSpeed)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var value = getAgentVelocity.Invoke(simulator, new object[] { id });
|
||||||
|
return Vector3.ClampMagnitude(FromRvoVector(value), maxSpeed);
|
||||||
|
}
|
||||||
|
catch (Exception exception)
|
||||||
|
{
|
||||||
|
Debug.LogWarning($"RVO2 getAgentVelocity failed: {exception.Message}");
|
||||||
|
return Vector3.zero;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
clear?.Invoke(simulator, null);
|
||||||
|
}
|
||||||
|
catch (Exception exception)
|
||||||
|
{
|
||||||
|
Debug.LogWarning($"RVO2 clear/reset failed: {exception.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Configure(AvoidanceBenchmarkConfig config)
|
||||||
|
{
|
||||||
|
InvokeSetTimeStep(Time.fixedDeltaTime);
|
||||||
|
InvokeAgentDefaults(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InvokeSetTimeStep(float deltaTime)
|
||||||
|
{
|
||||||
|
if (setTimeStep == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeStep.Invoke(simulator, new object[] { Mathf.Max(0.001f, deltaTime) });
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InvokeAgentDefaults(AvoidanceBenchmarkConfig config)
|
||||||
|
{
|
||||||
|
if (setAgentDefaults == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var parameters = setAgentDefaults.GetParameters();
|
||||||
|
var values = new object[parameters.Length];
|
||||||
|
for (var i = 0; i < parameters.Length; i++)
|
||||||
|
{
|
||||||
|
var parameterType = parameters[i].ParameterType;
|
||||||
|
var name = parameters[i].Name ?? string.Empty;
|
||||||
|
|
||||||
|
if (parameterType == typeof(int))
|
||||||
|
{
|
||||||
|
values[i] = config.MaxNeighbours;
|
||||||
|
}
|
||||||
|
else if (parameterType == typeof(float))
|
||||||
|
{
|
||||||
|
values[i] = GuessDefaultFloat(name, config);
|
||||||
|
}
|
||||||
|
else if (parameterType == vector2Type)
|
||||||
|
{
|
||||||
|
values[i] = CreateVector(vector2Type, 0f, 0f, 0f);
|
||||||
|
}
|
||||||
|
else if (parameterType == vector3Type)
|
||||||
|
{
|
||||||
|
values[i] = CreateVector(vector3Type, 0f, 0f, 0f);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
values[i] = parameterType.IsValueType ? Activator.CreateInstance(parameterType) : null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setAgentDefaults.Invoke(simulator, values);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static float GuessDefaultFloat(string parameterName, AvoidanceBenchmarkConfig config)
|
||||||
|
{
|
||||||
|
var lower = parameterName.ToLowerInvariant();
|
||||||
|
if (lower.Contains("radius"))
|
||||||
|
{
|
||||||
|
return config.FishRadius;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lower.Contains("maxspeed") || lower.Contains("max_speed"))
|
||||||
|
{
|
||||||
|
return config.FishSpeed;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lower.Contains("neigh") || lower.Contains("dist"))
|
||||||
|
{
|
||||||
|
return config.FishRadius * 8f;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lower.Contains("horizon"))
|
||||||
|
{
|
||||||
|
return 2.5f;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
private object ToRvoVector(Vector3 value)
|
||||||
|
{
|
||||||
|
if (use3D && vector3Type != null)
|
||||||
|
{
|
||||||
|
return CreateVector(vector3Type, value.x, value.y, value.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
return CreateVector(vector2Type, value.x, value.z, 0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Vector3 FromRvoVector(object value)
|
||||||
|
{
|
||||||
|
if (value == null)
|
||||||
|
{
|
||||||
|
return Vector3.zero;
|
||||||
|
}
|
||||||
|
|
||||||
|
var type = value.GetType();
|
||||||
|
if (use3D && type == vector3Type)
|
||||||
|
{
|
||||||
|
return new Vector3(GetFloatMember(value, "x", "X"), GetFloatMember(value, "y", "Y"), GetFloatMember(value, "z", "Z"));
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Vector3(GetFloatMember(value, "x", "X"), 0f, GetFloatMember(value, "y", "Y"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static object CreateVector(Type type, float x, float y, float z)
|
||||||
|
{
|
||||||
|
var constructor = type.GetConstructor(new[] { typeof(float), typeof(float), typeof(float) });
|
||||||
|
if (constructor != null)
|
||||||
|
{
|
||||||
|
return constructor.Invoke(new object[] { x, y, z });
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor = type.GetConstructor(new[] { typeof(float), typeof(float) });
|
||||||
|
if (constructor != null)
|
||||||
|
{
|
||||||
|
return constructor.Invoke(new object[] { x, y });
|
||||||
|
}
|
||||||
|
|
||||||
|
var value = Activator.CreateInstance(type);
|
||||||
|
SetFloatMember(value, x, "x", "X");
|
||||||
|
SetFloatMember(value, y, "y", "Y");
|
||||||
|
SetFloatMember(value, z, "z", "Z");
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static float GetFloatMember(object value, params string[] names)
|
||||||
|
{
|
||||||
|
var type = value.GetType();
|
||||||
|
foreach (var name in names)
|
||||||
|
{
|
||||||
|
var field = type.GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
|
||||||
|
if (field != null)
|
||||||
|
{
|
||||||
|
return Convert.ToSingle(field.GetValue(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
var property = type.GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
|
||||||
|
if (property != null)
|
||||||
|
{
|
||||||
|
return Convert.ToSingle(property.GetValue(value, null));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void SetFloatMember(object value, float memberValue, params string[] names)
|
||||||
|
{
|
||||||
|
var type = value.GetType();
|
||||||
|
foreach (var name in names)
|
||||||
|
{
|
||||||
|
var field = type.GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
|
||||||
|
if (field != null)
|
||||||
|
{
|
||||||
|
field.SetValue(value, memberValue);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var property = type.GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
|
||||||
|
if (property != null && property.CanWrite)
|
||||||
|
{
|
||||||
|
property.SetValue(value, memberValue, null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Rvo2ReflectionBridge Unavailable(string status = MissingPackageStatus)
|
||||||
|
{
|
||||||
|
return new Rvo2ReflectionBridge(null, null, null, null, false, status, null, null, null, null, null, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static object CreateOrGetSimulator(Type type)
|
||||||
|
{
|
||||||
|
var instanceProperty = type.GetProperty("Instance", BindingFlags.Public | BindingFlags.Static);
|
||||||
|
if (instanceProperty != null)
|
||||||
|
{
|
||||||
|
return instanceProperty.GetValue(null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
var instanceField = type.GetField("Instance", BindingFlags.Public | BindingFlags.Static);
|
||||||
|
if (instanceField != null)
|
||||||
|
{
|
||||||
|
return instanceField.GetValue(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
var constructor = type.GetConstructor(Type.EmptyTypes);
|
||||||
|
return constructor != null ? constructor.Invoke(null) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Type FindType(params string[] typeNames)
|
||||||
|
{
|
||||||
|
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
|
||||||
|
{
|
||||||
|
foreach (var typeName in typeNames)
|
||||||
|
{
|
||||||
|
var type = assembly.GetType(typeName, false);
|
||||||
|
if (type != null)
|
||||||
|
{
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Type FindType(Type anchorType, params string[] typeNames)
|
||||||
|
{
|
||||||
|
foreach (var typeName in typeNames)
|
||||||
|
{
|
||||||
|
var type = anchorType.Assembly.GetType(typeName, false);
|
||||||
|
if (type != null)
|
||||||
|
{
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return FindType(typeNames);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static MethodInfo FindMethod(Type type, string camelName, string pascalName, Type[] parameterTypes)
|
||||||
|
{
|
||||||
|
return type.GetMethod(camelName, BindingFlags.Instance | BindingFlags.Public, null, parameterTypes, null)
|
||||||
|
?? type.GetMethod(pascalName, BindingFlags.Instance | BindingFlags.Public, null, parameterTypes, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static MethodInfo FindMethodByName(Type type, params string[] names)
|
||||||
|
{
|
||||||
|
foreach (var name in names)
|
||||||
|
{
|
||||||
|
foreach (var method in type.GetMethods(BindingFlags.Instance | BindingFlags.Public))
|
||||||
|
{
|
||||||
|
if (method.Name == name)
|
||||||
|
{
|
||||||
|
return method;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 8ab9415f1c774b36a29d07f9f462c911
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -45,7 +45,7 @@ Adapter implementations may add package-specific components to created agents, b
|
|||||||
|
|
||||||
`NoAvoidanceAdapter` is the control group. It moves agents directly by preferred velocity and does not perform avoidance.
|
`NoAvoidanceAdapter` is the control group. It moves agents directly by preferred velocity and does not perform avoidance.
|
||||||
|
|
||||||
The A* RVO, RVO2, and Unity NavMesh adapters currently start as placeholders so their worktree diffs stay easy to review.
|
The A* RVO, RVO2, and Unity NavMesh adapters are selected through the same debug panel so their behavior can be compared under the same scene, count, camera, and metrics.
|
||||||
|
|
||||||
## A* Pathfinding Project Pro RVO Adapter
|
## A* Pathfinding Project Pro RVO Adapter
|
||||||
|
|
||||||
@@ -55,3 +55,13 @@ The A* RVO, RVO2, and Unity NavMesh adapters currently start as placeholders so
|
|||||||
- When the A* Pro RVO types are missing, the Game view status reports the missing package and the agents fall back to baseline preferred-velocity movement.
|
- When the A* Pro RVO types are missing, the Game view status reports the missing package and the agents fall back to baseline preferred-velocity movement.
|
||||||
- When available, the adapter creates one runtime `RVOSimulator`, adds `RVOController` components to benchmark-created agents, feeds each preferred velocity into A* RVO, and writes the reflected avoidance velocity back through `BenchmarkAgent.ApplyVelocity`.
|
- When available, the adapter creates one runtime `RVOSimulator`, adds `RVOController` components to benchmark-created agents, feeds each preferred velocity into A* RVO, and writes the reflected avoidance velocity back through `BenchmarkAgent.ApplyVelocity`.
|
||||||
- The shared benchmark scene, HUD, scenarios, count presets, metrics, and camera logic remain unchanged; the adapter is the only intended variable for this branch.
|
- The shared benchmark scene, HUD, scenarios, count presets, metrics, and camera logic remain unchanged; the adapter is the only intended variable for this branch.
|
||||||
|
|
||||||
|
## RVO2 / RVO2-3D Adapter
|
||||||
|
|
||||||
|
`Rvo2Adapter` is intentionally a reflection adapter. The benchmark must compile even when no RVO2 package or source is present.
|
||||||
|
|
||||||
|
- Without RVO2 source/package, selecting `Rvo2` creates the same benchmark primitives and reports the missing package in the Game view `Status` line.
|
||||||
|
- To enable the real framework, place a C# RVO2 or RVO2-3D implementation under `Assets/` or add it as a package under `Packages/`.
|
||||||
|
- The adapter looks for a simulator type such as `RVO.Simulator`, `RVO2.Simulator`, `RVO3D.Simulator`, or `RVO.Simulator3D`.
|
||||||
|
- The required simulator methods are `addAgent`/`AddAgent`, `setAgentPrefVelocity`/`SetAgentPrefVelocity`, `getAgentVelocity`/`GetAgentVelocity`, and `doStep`/`DoStep`.
|
||||||
|
- 2D and 2.5D modes bind to an RVO `Vector2` style type and map Unity `x/z` to RVO `x/y`. 3D mode binds to an RVO `Vector3` style type when available.
|
||||||
|
|||||||
Reference in New Issue
Block a user