我正在为Unity3d设计一个物理类库,并希望能够将功能注入Unity3d的Rigidbody
类,但我的理解是,没有办法直接做到这一点,同时仍然能够针对所有平台。
我认为下一个最好的事情可能是创建一个直接继承Rigidbody
的新类。然而,它看起来像unity已经阻止了这种情况发生在任何事情,但UnityEngine名称空间要求internal sealed ExtensionOfNativeClassAttribute
上的任何继承原生类。此外,Unity不能很好地序列化继承的类。
所以,回顾一下,我不能直接挂钩到Rigidbody
(如果这是错误的,请纠正我!),我不能直接从Rigidbody
继承(如果这是错误的,请纠正我!)。我认为下一个最好的选择是:
- 创建一个新的Monobehavior,假设它叫做
ModRigidbody
,它并行实现了Rigidbody
的所有成员。这个类实际上并不继承Rigidbody
,而只是拥有与Rigidbody
具有相同名称/签名的成员。 - 在
ModRigidbody
上添加[RequireComponent(typeof(Rigidbody))]
属性。现在我可以添加功能到一些ModRigidbody的成员,因为我认为合适,并有其他成员简单地"通过"到transform.GetComponent<Rigidbody>()
。 - 让任何最终用户(程序员)将所有对
Rigidbody
的引用更改为ModRigidbody
。
对我来说这感觉很马虎。有没有办法修改Rigidbody
的功能,以便将来这个库的用户不必将所有的Rigidbody
更改为ModRigidbody
?
考虑到Unity所施加的限制,你的主张似乎是合理的,但为什么不创建一个扩展方法呢?
扩展方法使您能够"添加";方法,而无需创建新的派生类型、重新编译或以其他方式修改原始类型。
我首先会说,即使直接扩展Rigidbody
也会导致您的消费者在实现中迁移到使用新类型,因此创建代理当然是一个好的开始。但是,如果您希望直接使用Rigidbody
而不是新类型来促进消费者,那么我建议创建扩展方法:
public static class ForceApplicationRigidbodyExtensions {
public static void ApplyDecayingForce(
this Rigidbody rigidbody,
Vector3 startingForce,
float decayRate,
TimeSpan lifetime) {
...
}
}
这允许消费者直接从他们的Rigidbody
实例调用你的方法:
var rigidbody = transform.GetComponent<Rigidbody>();
rigidbody.ApplyDecayingForce(Vector3.up * 10, 0.05f, TimeSpan.FromSeconds(5));
如果您不是扩展方法的粉丝,那么您可以创建一些专注于突变给定Rigidbody
的东西:
public class RigidbodyForceApplicator {
private reaodnly Rigidbody _rigidbody;
public RigidbodyForceApplicator(Rigidbody rigidbody) =>
_rigidbody = rigidbody;
public void ApplyDecayingForce(
Rigidbody rigidbody,
Vector3 startingForce,
float decayRate,
TimeSpan lifetime) {
...
}
}
这允许消费者在只使用他们需要的东西时是显式的:
var rigidbody = transform.GetComponent<Rigidbody>();
var forceApplicator = new RigidbodyForceApplicator(rigidbody);
forceApplicator.ApplyDecayingForce(Vector3.up * 10, 0.05f, TimeSpan.FromSeconds(5));
如果您要创建代理,那么我建议您记住以下几点:
- 不要指望
Rigidbody
完全支持你想要的突变,因为这几乎从来没有像我们想要的那样工作。 - 不要创建直接手动完成
Rigidbody
的直通实现,因为这只是增加了一个不必要的额外方法调用。 - 只公开提供
Rigidbody
补充功能的函数。