在独立于平台的设计中传递特定于平台的数据?

发布于 2024-08-19 14:19:07 字数 362 浏览 3 评论 0原文

我有一个用 C++ 编写的游戏引擎设计,其中独立于平台的游戏对象包含在特定于平台的应用程序对象中。

我试图解决的问题是我需要将操作系统特定的数据从应用程序传递到游戏。在这种情况下,我需要将 DirectX 的 Windows 的主 HWND 或其他平台的 OpenGL 上下文传递给我正在使用的渲染器。不幸的是,我对渲染器几乎没有控制权,它可以期待特定于平台的数据。

我意识到我可以在应用程序端初始化渲染器,但我宁愿让游戏决定何时何地执行此操作。一般来说,我可以控制应用程序端,但不能控制游戏端。游戏编写者可能会选择使用不同的渲染器。

我还考虑过拥有某种“属性管理器”的想法,我可以在其中通过字符串传递数据,但我不太喜欢这个想法。

有什么想法吗?

I have a game engine design written in C++ where a platform-independent game object is contained within a platform-specific Application object.

The problem I'm trying to solve is the case where I need to pass OS-specific data from the Application to the game. In this case, I'd need to pass the main HWND from Windows for DirectX or an OpenGL context for the other platforms to the renderer I'm using. Unfortunately I have little control over the renderer, which can expect platform-specific data.

I realize I could initialize the renderer on the Application side, but I'd rather have the game decide when and where to do it. Generally, I have control over the Application side but not the game side. The game writer might choose to use a different renderer.

I've also entertained the idea of having some kind of "Property Manager" where I can pass data around through strings, but I don't like that idea very much.

Any ideas?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

挽容 2024-08-26 14:19:07

请记住,您只需要在编译时知道目标平台。有了这些信息,您就可以为正确的平台“换入和换出”组件。

在一个好的设计中,游戏应该不需要需要任何有关其平台的信息;它应该只包含逻辑和相关组件。

您的“引擎”类应该担心平台。

Game 类只能通过非特定于平台的公共函数与 Engine 对象交互;您可以为每个平台拥有多个版本的 Engine 对象,并在编译时选择使用哪一个。

例如,您可以有一个代表游戏中纹理的纹理“引擎”类。如果您支持 OS X 和 Windows,则可能有一个“Texture.h”,其中包含“Windows/Texture.h”或“OSX/Texture.h”,具体取决于您正在编译的平台。两个标头都将定义具有相同接口的纹理类(即它们都具有相同的公共函数和相同的参数),但它们的实现将是特定于平台的。

为了澄清,游戏应该告诉应用程序初始化渲染器;游戏逻辑和实现细节之间应该有严格的界限。渲染器是一个实现细节,而不是游戏逻辑的一部分。游戏类应该对系统一无所知,而只了解游戏世界。

Remember that you only need to know the target platform at compile time. With this information, you can 'swap in and out' components for the correct platform.

In a good design, the Game should not require any information about it's platform; it should only hold the logic and related components.

Your 'Engine' classes should worry about the platform.

The Game classes should only interface with the Engine objects via public functions that aren't specific to the platform; you can have multiple versions of the Engine objects for each platform, and choose which one to use at compile time.

For example, you could have a Texture 'engine' class that represents a texture in the game. If you support OS X and Windows, you could have a "Texture.h" which includes "Windows/Texture.h" or "OSX/Texture.h" depending on the platform you're compiling on. Both headers will define a Texture class with the same interface (i.e. they'll both have the same public functions with the same arguments), but their implementation will be platform-specific.

To clarify, the Game should tell the Application to initialize the Renderer; there should be a strict line between the game logic and the implementation details. The renderer is an implementation detail, not part of the game logic. The game classes should know nothing about the system and only about the game world.

苹果你个爱泡泡 2024-08-26 14:19:07

传递的 SystemContext 类怎么样?你会有一个 Win32Context、LinuxContext 等。这就是 OGRE 处理它的方式(在这种情况下是 RenderContext)。

Renderer 类采用 SystemContext 指针。

在内部,DirectXRenderer(渲染器的后代)dynamic_casts(一次)指向 Win32Context 的指针,并从中挑选出所有与平台相关的数据。

How about a SystemContext class that gets passed? You'd have a Win32Context, LinuxContext etc. This the way that OGRE handles it (RenderContext in it's case).

Renderer class takes a SystemContext pointer.

Internally, a DirectXRenderer (descendant of Renderer) dynamic_casts (once) the pointer to a Win32Context and picks out all platform dependent data from it.

有深☉意 2024-08-26 14:19:07

请参阅模板模式(使用具有可在派生类中配置的纯虚函数的抽象基类)。

http://en.wikipedia.org/wiki/Template_pattern

如果您更喜欢更可控的( (而不是面向对象)方式,游戏部分应该调用应用程序部分中的可配置回调函数,以执行特定于平台的配置。

例如:

// in Application:
static void SetWindowHandle(GameEngine const& p_game_engine, void* p_callback_data)
{
  p_game_engine.DoSomethingWithHandle(static_cast<ApplicationManager*>(p_callback_data)->GetHWND());
}

void Initialize() {
  this->m_game_engine.Initialize(this, &Application::SetWindowHandle);
}

// ...
// in Game Engine:
// ...

typedef void (*TSetWindowsHandleCallback)(GameEngine const*, void*);

void* m_application_data;
TSetWindowsHandleCallback m_windows_handle_callback;

void Initialize(void *p_application_data, TSetWindowsHandleCallback p_callback)
{
  this->m_application_data = p_application_data;
  this->m_windows_handle_callback = p_callback;
}

void SetWindowsHandle()
{
  this->m_windows_handle_callback(*this, m_application_data);
}

See the Template Pattern (use an abstract base class with pure virtual functions that can be configured in a derived class).

http://en.wikipedia.org/wiki/Template_pattern

If you prefer a more controllable (and less object-oriented) way, the Game part should call a configurable callback function in the Application part, to perform the platform-specific configurations.

E.g.:

// in Application:
static void SetWindowHandle(GameEngine const& p_game_engine, void* p_callback_data)
{
  p_game_engine.DoSomethingWithHandle(static_cast<ApplicationManager*>(p_callback_data)->GetHWND());
}

void Initialize() {
  this->m_game_engine.Initialize(this, &Application::SetWindowHandle);
}

// ...
// in Game Engine:
// ...

typedef void (*TSetWindowsHandleCallback)(GameEngine const*, void*);

void* m_application_data;
TSetWindowsHandleCallback m_windows_handle_callback;

void Initialize(void *p_application_data, TSetWindowsHandleCallback p_callback)
{
  this->m_application_data = p_application_data;
  this->m_windows_handle_callback = p_callback;
}

void SetWindowsHandle()
{
  this->m_windows_handle_callback(*this, m_application_data);
}
ˇ宁静的妩媚 2024-08-26 14:19:07

我喜欢做的是让所有实现与公共数据成员共享一个基类。然后我有一个本机类,其中基类本身包含特定于平台的信息。这需要特定的目录结构。例如,您有:

code
  renderer
    context.h
  platforms
    win32
      renderer
        context_native.h
    osx
      renderer
        context_native.h

code/renderer/context.h
class RenderContextBase { /* shared members */ };
#include "renderer/context_native.h"

code/platform/win32/renderer/context_native.h
class RenderContext : public RenderContextBase { /*win32 specific */ };

code/platform/osx/renderer/context_native.h
class RenderContext : public RenderContextBase { /*osx specific */ };

使用编译器“其他包含目录”,您只需根据平台添加适当的目录即可。例如,在 win32 上,您添加“code/platform/win32”作为附加目录。当包含 renderer/renderer_native.h 时,它不会在“默认”位置找到,并且会尝试使用附加目录。

从代码中的任何位置来看,RenderContext 都是本机实现。您不需要有一个指向基类的指针并新建本机类,因为您实际上有 1 个实现。当您确实拥有给定平台的 1 个实现时,这可以避免使用基本虚拟函数。

What I like to do is to have a base class shared by all implementation with common data members. Then I have a native class with platform specific information included by the base class itself. This required a particular directory structure. For example you have:

code
  renderer
    context.h
  platforms
    win32
      renderer
        context_native.h
    osx
      renderer
        context_native.h

code/renderer/context.h
class RenderContextBase { /* shared members */ };
#include "renderer/context_native.h"

code/platform/win32/renderer/context_native.h
class RenderContext : public RenderContextBase { /*win32 specific */ };

code/platform/osx/renderer/context_native.h
class RenderContext : public RenderContextBase { /*osx specific */ };

Using your compiler "Additional include directories" you simply add the proper directory depending on the platform. For example, on win32, you add "code/platform/win32" as an additional directory. When including renderer/renderer_native.h, it won't be found in the "default" location and will try to use the additional directory.

From anywhere in the code RenderContext is the native implementation. You don't need to have a pointer to the base class and new the native class since you really have 1 implementation. This avoids having base virtual functions when you really have 1 implementation of a given platform.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文