如何在没有 SphereCollider.Create() 工厂方法调用的情况下为 Unity.Physics.SphereCollider 结构使用 CastRay()

How to CastRay() for Unity.Physics.SphereCollider struct without SphereCollider.Create() factory method call

如何在没有 SphereCollider.Create() 工厂方法调用的情况下为 Unity.Physics.SphereCollider 结构使用 CastRay()(我认为会导致堆分配)。

下面的代码不起作用,不确定具体原因:

using Physics = Unity.Physics;
 
bool TraceRaySphere
(
    float3 spherePos ,
    float sphereRadius ,
    float3 rayStart ,
    float3 rayEnd ,
    out Physics.RaycastHit raycastHit
)
{
    var ray = new Physics.RaycastInput{
        Start   = rayStart ,
        End     = rayEnd ,
        Filter  = Physics.CollisionFilter.Default
    };
    var geometry  = new Physics.SphereGeometry{
        Center  = spherePos ,
        Radius  = sphereRadius
    };
    var sphere = new Physics.SphereCollider{
        Geometry    = geometry ,
        Filter      = Physics.CollisionFilter.Default
    };
    return sphere.CastRay( ray , out raycastHit );
}

这行得通,但使用了提到的 SphereCollider.Create(geometry) 我想摆脱的工厂方法(如果可能的话):

public static bool TraceRaySphere
(
    float3 spherePos ,
    float sphereRadius ,
    float3 rayStart ,
    float3 rayEnd ,
    out RaycastHit raycastHit
)
{
    var ray = new RaycastInput{
        Start   = rayStart ,
        End     = rayEnd ,
        Filter  = CollisionFilter.Default
    };
    var geometry  = new SphereGeometry{
        Center  = spherePos ,
        Radius  = sphereRadius
    };
    var sphereBlobAsset = SphereCollider.Create( geometry );
    bool didHit = sphereBlobAsset.Value.CastRay( ray , out raycastHit );
    sphereBlobAsset.Dispose();
    return didHit;
}

在我的项目中,我使用以下辅助方法来转换任何 Collider(需要不安全的代码执行标志,因为它使用指针)

public static unsafe bool ColliderCast(float3 rayFrom, float3 rayTo, quaternion rotation, CollisionWorld collisionWorld, PhysicsCollider collider)
{
    ColliderCastInput input = new ColliderCastInput()
    {
        Collider = (Collider*)collider.Value.GetUnsafePtr(),
        Orientation = rotation,
        Start = rayFrom,
        End = rayTo
    };

    return collisionWorld.CastCollider(input);
}

我也有一个 CollisionGeome trySingleton class 其中包含 this

//Cache geometries (float3 = size, float3 = center)
private IDictionary<Tuple<float3, float3>, BoxGeometry> boxGeometries;

public BoxGeometry CreateOrGetBoxGeometry(float3 size, float3 center)
{
   
    if(this.boxGeometries == null)
    {
        this.boxGeometries = new Dictionary<Tuple<float3,float3>, BoxGeometry>();
    }

    Tuple<float3, float3> key = new Tuple<float3, float3>(size, center);

    if(!this.boxGeometries.ContainsKey(key))
    {
        this.boxGeometries.Add(key, new BoxGeometry { Size = key.Item1, Center = key.Item2, Orientation = quaternion.identity });
    }

    return this.boxGeometries[key];
}

这让我可以使用

BoxCollider.Create
(
    CollisionGeomeotrySingleton.Instance.CreateOrGetBoxGeometry(5, 5), 
    CollisionFilterSingleton.Instance.CollidesWithPlayerFilter
)

您现在可以更进一步,将 BoxCollider 也存储在 CollisionGeometrySingleton

SphereCollider 结构包含一些隐藏的私有字段,需要调用 Init(args) 方法才能为它们设置正确的值:

public static bool TraceRaySphere
(
    float3 spherePos ,
    float sphereRadius ,
    float3 rayStart ,
    float3 rayEnd ,
    out RaycastHit raycastHit
)
{
    var ray = new RaycastInput
    {
        Start   = rayStart ,
        End     = rayEnd ,
        Filter  = CollisionFilter.Default
    };
    var geometry  = new SphereGeometry
    {
        Center  = spherePos ,
        Radius  = sphereRadius
    };
    var sphere = default(SphereCollider);
    sphere.Init( geometry , CollisionFilter.Default , Material.Default );
    return sphere.CastRay( ray , out raycastHit );
}

不过

此方法是私有的 (chances are this may change)。 要使 Init 方法可用,您需要修改 ...\com.unity.physics@0.5.0-preview.1\Unity.Physics\Collision\Colliders\Physics_SphereCollider.cs 源文件并将其设为 public.