在 Unity 中可序列化的 C# 中找到函数指针的正确语法时出现问题

问题描述 投票:0回答:2

我试图在数据结构中保存一些参数化函数,以便在运行时使用。我希望能够在编辑器中输入参数。

我排除了 UnityEvent,因为我不想在编辑器中指定将受到影响的游戏对象。

我来自 python,所以我的想法是装饰器,这显然不会在 C# 中工作。我很确定代表,也许反射或动作会发挥作用,但我只是想不出语法。

public interface IStuffInstantiatedInEditor {
    public abstract void Call(Transform transfo);
}

[Serializable]
public class EditorTranslate: IStuffInstantiatedInEditor {
    public Vector3 trans;

    public void Call(Transform transfo) {
        transfo.Translate(trans);
    }
}

[Serializable]
public class EditorRotateAround: IStuffInstantiatedInEditor {
    public Vector3 point;
    public float angle;

    public void Call(Transform transfo) {
        transfo.RotateAround(point, Vector3.forward, angle);
    }
    
}

[Serializable]
public delegate void CallWrapper(Transform transfo);

[Serializable]
public class EditorDataStructure {
    public List<CallWrapper> wrappers;
}

缺少的部分是链接

CallWrapper wrap1 = EditorTranslate(vecEnteredInEditor).Call

c# unity3d function-pointers
2个回答
0
投票

您在代码中编写的内容和您尝试做的事情彼此之间有点倒退。除非你想要事件,否则你不需要使用委托来矫枉过正它。反射在这里也无关紧要。它有不同的目的。另外,不要将委托与 c# 事件操作和 UnityEvents 混淆。

接口及其实现很好。要调用它们,您只需使用实例和方法调用的基本引用:

IStuffInstantiatedInEditor translateInterface; // default visibility is private
                                               // so make sure to set it explicitly if needed
translateInterface.Call();

分配它的方式与任何其他变量相同,除非它在不同的类中,因此需要是

internal
public
.

So类

MyClass1
有这个成员并在
myCls
中创建:

myCls.translateInterface = new EditorTranslate();
myCls.translateInterface.trans = Vector3.one;
myCls.translateInterface.Call();

然后你可以为

EditorRotateAround
做同样的事情。

只需记住

ScriptableObjects
MonoBehaviours
DO NOT使用
new ()
.

如果你想获得指向属于其他实例的其他

Call()
函数的指针,那不是最好的方法。只需将对象添加到列表中,然后在每个集合元素上调用
Call()

还要注意这个场景,虽然它只是一个例子,但您可以只使用一个

abstract
类并向下推动多态性。如果您不想过多地“外部化”代码,多态性是我的选择(但这是个人的选择)。当继承以某种方式或类的某些“方面”发生变化时,无论继承如何,接口都是最好的。


0
投票

我这样做的方法是使用 ScriptableObjects。现在接口不能用于此,因为它们不能被序列化,但你可以通过抽象继承来制定相同的契约。

public abstract class StuffInstantiatedInEditor : ScriptableObject
{
    public abstract void Call(Transform transfo);
}

然后创建这个的子类型

public class EditorTranslate: IStuffInstantiatedInEditor 
{
   ...
}

然后您可以为这些子类型提供 CreateAssetMenu 属性,如下所示

[CreateAssetMenu(menuName = "StuffInstantiatedInEditor/EditorTranslate")]
public class EditorTranslate: StuffInstantiatedInEditor 
{
   ...
}

然后您可以创建这些实例,这些实例将存在于您的资产文件夹中,并且可以序列化到您需要的任何场景中。

最后,你的收藏可以是

[Serializable]
public class EditorDataStructure 
{
    public List<StuffInstantiatedInEditor> wrappers;
}

这将按原样工作,因为 ScriptableObjects 是默认可序列化的

© www.soinside.com 2019 - 2024. All rights reserved.