我想让我的游戏与所使用的底层图形API无关(为了减少耦合,以防我想将它移植到另一个平台)。
我目前正在使用SDL,最初我想将SDL_Renderer封装在GraphicAPI_SDL类中,实现我的通用GraphicAPI接口。此API将创建Image_SDL(封装SDL_Texture),它实现了我的通用Image接口。
我的问题是,当我想使用我的GraphicAPI实例渲染图像时,底层的GraphicAPI_SDL必须将Image转换为Image_SDL,以获得SDL_Texture。这样的演员很难看。
处理这类情况的最佳方法是什么?我将把每个加载在一个向量中的SDL_Texture存储在我的GraphicAPI_SDL中,每个Image的实例只有一个对应于向量中纹理索引的整数,因此只有GraphicAPI_SDL类直接使用SDL,但是有一个更好的方法(例如使用模式)?
答案 0 :(得分:1)
如果您正在使用SDL 2.0(并且只是制作2D游戏),那么您已经在很大程度上与底层的Graphics API分离。当您设置窗口时,SDL 2.0可以为您的系统自动选择正确的渲染器(DirectX或OpenGL),您的代码根本不需要担心它。但是,如果您的游戏需要较低级别的绘图控制(即,您正在制作3D游戏),则需要自己处理渲染器。
有关详细信息,请参阅此处:http://wiki.libsdl.org/MigrationGuide#Video
答案 1 :(得分:0)
请参阅Irrlicht,它有一个简单但很好的架构,符合您的可移植性标准。基本模式为adapter,mediator和factory method。这种便携性的关键是良好的界面。我们需要GraphicsApi
,MeshRenderer
和Texture
的抽象类,以及所有图形API的实现。
对于DirectX9:
GraphicsApiDX9
实施GraphicsApi
MeshRendererDX9
实施MeshRenderer
TextureDX9
实施Texture
对于OpenGL:
GraphicsApiGL
实施GraphicsApi
MeshRendererGL
实施MeshRenderer
TextureGL
实施Texture
等等。 GraphicsApiDX9
创建TextureDX9
,保留指向IDirect3DTexture9
的内部指针,以及创建纹理的IDirect3DDevice9
。您正在使用创建的一个槽Texture
接口,因此您不关心它是如何创建的。
答案 2 :(得分:0)
首先,没有平台独立性这样的东西。在每个平台上,您都被迫做出一些假设,这些假设在您的下一个平台上可能会或可能不会成立。在任何抽象平台中,您将做出一些假设(如平台支持纹理,矩阵变换,四元数,无3D支持等)。抽象平台所做的一切都会产生不必要的复杂性。
当您考虑支持2个或更多平台时,抽象平台才开始有意义,此时您可以抽象出常见概念(如纹理和矩阵变换)。
因此,除非您计划支持多个平台,否则您可以做的最好的事情就是确保您的应用程序正确分层。
SDL和OpenGL ES在大量平台上得到支持,除非您计划将游戏移植到专业游戏机,否则SDL和OpenGL ES涵盖了大多数基础。
答案 3 :(得分:0)
我的解决方案(从我的爱好 - 黑客 - 第二代 - 游戏引擎中删除的片段)就像这样。我从任何一种纹理的句柄开始(这是独立于图形库):
struct MGTexHandle
{
MGTexHandle();
~MGTexHandle();
void* tex;
};
然后,在我的图形库接口类中,我保留了所有方法的通用接口,没有库特定类型。实现必须移植到每个图形库(我测试的唯一一个是SDL2)。
例如,将图像加载到与图形库无关的纹理对象(texHandle参数):
void* MGWindow::loadBMPImage(std::string fileName, bool transparent)
{
SDL_Surface* loadedImage = NULL;
SDL_Texture* optimizedImage = NULL;
loadedImage = SDL_LoadBMP(fileName.c_str());
if(loadedImage != NULL)
{
if(transparent)
{
// TODO: Make it possible to have other color codes than
// zero represent transparency
SDL_SetColorKey(loadedImage, SDL_TRUE, 0);
}
optimizedImage = SDL_CreateTextureFromSurface(m_Renderer, loadedImage);
SDL_FreeSurface(loadedImage);
}
return (void*)optimizedImage;
}
void MGWindow::loadBMPImage(std::string fileName, MGTexHandle &texHandle, bool transparent)
{
if(texHandle.tex)
{
SDL_DestroyTexture(static_cast<SDL_Texture*>(texHandle.tex));
}
texHandle.tex = loadBMPImage(fileName, transparent);
}
在屏幕上渲染纹理如下所示:
void MGWindow::drawSprite(const MGTexHandle &imageTexture, int srcX, int srcY, int dstX, int dstY, int width, int height)
{
increaseDrawnSpritesCounter();
SDL_Rect srcRect;
srcRect.x = srcX;
srcRect.y = srcY;
srcRect.w = width;
srcRect.h = height;
SDL_Rect dstRect;
dstRect.x = dstX;
dstRect.y = dstY;
dstRect.w = width;
dstRect.h = height;
SDL_RenderCopy(m_Renderer, static_cast<SDL_Texture*>(imageTexture.tex), &srcRect, &dstRect);
}
标题的开头如下:
class MGWindow : public IMGWindow
{
private:
int m_Width;
int m_Height;
int m_Bpp;
bool m_Fullscreen;
std::string m_Title;
SDL_Window* m_Screen;
SDL_Renderer* m_Renderer;
...
IMGWindow
是纯虚拟界面。
我可以模拟和存根图形并执行非常复杂的自动化集成测试,涉及除库特定图形例程之外的所有组件。这就是界面的重点,而不是有一天能够移植到另一个库,但现在也应该非常直接。