为C#库抽象特定于引擎的类/结构实现



我正在Unity中重新实现游戏,但我希望处理游戏资源的大部分代码与引擎无关,这样就可以很容易地制作工具来修改游戏,只需将它们放入一个新的C#项目中,不包括所有Unity特定的代码。

为了实现这一点,我有一些处理某些事情的实现的singleton。例如,当加载PNG纹理时,与引擎无关的代码会调用具有Unity特定PNG加载代码的纹理工厂单例。

现在的问题是,我即将开始加载模型,这些模型通常会涉及Unity的Vector3、Mesh等类,但由于我想与引擎无关,我必须对这些或封送使用某种抽象。

例如,使用Vector3实现这一点的明显方法是创建一个类似于Unity的Vector3的新Vector3类,并通过逐个创建具有相同XYZ值的Unity版本,将它们简单地转换为Unity的Vector3。问题是,我将有大量这样的数组,所以这听起来真的很低效。

我已经用Color32/Color尝试过纹理生成代码,但速度太慢了,所以我一直在想解决方案。

我已经考虑过使用一个工厂单例来创建UnityEngineVector3类,并使引擎不可知的代码简单地期望";对象";类型而不是任何特定类型,但我觉得这太混乱了,无法处理。不过,这可能真的是性能方面的最佳解决方案。

如有任何建议,不胜感激!

你不会喜欢这样的答案:不要这样做

只需用Unity特定的代码编写即可。不要指望复制粘贴,也不要创建20层来制作某种神奇的抽象转换机制。不管语言如何,这都是一个严重的设计缺陷。首先,让我们考虑您从一个C#切换到"C";Unity C#";(这里有一些讨论,但我不会深入讨论,因为它现在不相关)。Unity有不同的代码设计和体系结构范式和概念。它们与web应用程序、服务器中间件代码甚至桌面C#程序略有不同。即使你能做包装纸,背后的工作也会很难,不仅仅是";翻译";,而且还要使一种范式与另一种范式相匹配。这就像为DOS编写C,然后在Windows 11中制作一个层。当然,这是同一种语言,但概念不同(我这里不提操作系统API)。

现在,让我们假设您有一个C++游戏。如果你要切换到C#(例如使用中间库),那么,假设你想在10年后再次切换到C++。现在的C++标准与C++99非常不同,以至于那些在这25年里中断的人可能会认为它是一种新的语言或扩展。如果你真的想切换到虚幻引擎,会发生什么?你会把C#包裹起来吗?

最后,听起来这就是你无论如何都会得到的结果:视频课在旧代码上,视频课在统一代码上,然后是一个翻译层,同样适用于抓字、音频、数学。。。最终,这几乎就像制造一台新发动机。

除了可能出现的编码错误,想象一下对它进行维护。不是由你自己,而是由一个团队。一个新的团队(如果有人离开,而你有新人加入)。这里面有太多的因素,以至于整个努力都是不合理的。

迁移是最好的解决方案,只需编写尽可能接近本机的代码(从引擎的角度来看——我指的不是asm或其他什么,我的意思是,尽可能接近引擎期望的样子,而不是一些神奇的包装器或抽象层)。你会跳过抽象的性能冲击(因为相信我,添加一、二、500层神奇的代码会增加内存开销,甚至可能增加CPU开销),你甚至可能找到一些可以简化的代码。Unity有大量的本地5行代码解决方案,可以减少代码。甚至是具有扩展实用程序、插件或通用代码助手功能的资产(付费或免费)。

附言:你可能会听到一些疯狂的解决方法,比如用C或C++编写它,然后添加一个单独的绑定库,该库可以与任何语言接口,然后你可以做这个和那个。。。也不要。如果你正处于这种情况,想象一下你有自己的分配器/解除定位器,你自己的内存管理器,可能还有一个线程管理器——如果你有一些可变/不可变/原子代码,可能还有一些用于多线程的互斥/信号量,所有这些都会与C#管理器和Unity管理器发生冲突。虽然在Unity游戏中;魔术;由框架处理,实际上,所有Unity类都由引擎处理,引擎是C++,有自己的规则。虽然您可能找到了解决方法,或者也许不是问题,但随着项目的发展和扩展,您可能会有一些惊喜。依赖项过多会增加问题。

最新更新