在不同的游戏引擎实现程序集中填充SharpDX和OpenTK?

时间:2014-08-20 20:01:32

标签: c# .net-assembly extensibility

我希望我的C#引擎能够让用户在使用Direct3D或OpenGL之间进行选择。 我的内部引擎设计为着色器类的抽象示例:

internal class Shader
{
    private IShaderImplementation _implementation;

    internal Shader(ShaderType type, string code)
    {
        switch (Engine.GraphicsInterface)
        {
            case GraphicsInterface.Direct3D:
                _implementation = new Direct3DShader(type, code);
                break;
            case GraphicsInterface.OpenGL:
                _implementation = new OpenGLShader(type, code);
                break;
            default:
                throw new UnsupportedInterfaceException("Shader");
                break;
        }
    }

    internal void Compile()
    {
        _implementation.Compile();
    }
}

我认为这是一个很好的设计模式。 (我也更喜欢在工厂方法中调用构造函数,你可能已经注意到了,但这只是一个副作用。)

然而:

  • 我不想在一个类库中填充OpenTK(用于OpenGL的东西)程序集引用和SharpDX(用于Direct3D的东西)程序集引用。我甚至都不知道这是不是一个好主意。从当前设计开始,这将是必需的,因为Direct3DShader和OpenGLShader类直接引用D3D或OGL方法。即使用户仅希望使用OpenGL,我也不需要发布OpenTK / SharpDX程序集吗?
  • 我更喜欢有一个主程序集,其中只包含上面所见的常规界面内容(假设为“Awful.Engine.dll”,另一个仅包含OpenGL内容(“Awful.Engine.OpenGL.dll”))另一个用于Direct3D的东西(“Awful.Engine.Direct3D”)。但是如何在主程序集中引用它?正如你所看到的,我有一个接口的枚举,这将不再起作用。

以更通用的形式询问,我的主程序集接口和类如何在子程序集中实现和扩展?

PS:我听说过我知道一两分钟的反思,然后是托管可扩展性框架,但我还没弄清楚它是如何融入我的设计的。

1 个答案:

答案 0 :(得分:1)

将其设计为图形和声音层的3个类库。

类库1:界面层

  • 包含包装器将实现的所有包装器和接口。
  • 将接口设计为在自己的应用程序域中工作,并为所有内容传递接口。

类库2(OpenTK):

  • 引用类库1和OpenTK。
  • 添加类似OpenAL的声音API。
  • 实现包含对OpenTK的调用并播放声音的接口。

类库3(SharpDX):

  • 参考类库1和夏普DX。
  • 实现包含SharpDX调用的接口,并通过SharpDX播放声音。

游戏代码

  • 添加对类库1的硬引用,因此您拥有所有接口类型,枚举等。
  • 动态加载类库2或带有反射的类库3.
  • 为您的硬件层创建一个新的应用程序域。
  • 使用AppDomain.Load加载类库2或3。
  • 加载硬件程序集并拥有Assembly对象后,使用反射来获取对接口的引用,可能是这样的:

    // Making up this pseudo code
    GameApi gameApi = (GameApi)hardwareAsm.GetType(GameApi).GetMethod("Initialize").Invoke();
    
    TheGame gameWorld = gameApi.CreateGame(...);
    gameWorld.ResolutionChanged += Resolution_Changed(...);
    gameWorld.Terminated += Terminated(...);
    gameWorld.KeyDown += Key_Down(...);
    // etc....
    gameWorld.Start();
    

让整个图层在自己的应用程序域中运行的好处很多:

  • 可以卸载应用程序域,导致卸载的任何程序集也被卸载。 (如果用户可以在运行时从DirectX切换到OpenGL,这将是必需的,这将是整洁和可能的,以及我以前从未见过的人。)
  • 应用程序域可以使用自己的安全描述符,ACE等进行保护。您可以阻止在应用程序域中运行的代码访问创建文件,发出Internet请求等。(如果您正在为游戏插件设计插件层,则非常有用)。
  • 可以编写应用程序域,以便能够正常崩溃,记录崩溃,并在不影响根进程的情况下重新启动。