65.9K
CodeProject 正在变化。 阅读更多。
Home

平台独立开发示例

starIcon
emptyStarIcon
starIcon
emptyStarIconemptyStarIconemptyStarIcon

1.90/5 (13投票s)

2005年3月22日

CPOL

3分钟阅读

viewsIcon

29607

downloadIcon

556

一个平台无关的游戏模型。

引言

在过去的一个月里,我读了很多关于编写平台无关应用程序的讨论。这些讨论让很多编程初学者不确定该使用哪个库,或者哪个语言才是正确的选择。我甚至读到关于C++重要性下降的争论,因为对平台无关开发的需求越来越大。在本文中,我想通过一个小的C++游戏示例来展示,你不需要拥有在特定库方面的丰富知识来移植你的应用程序。更重要的是开发对平台相关任务的良好抽象。

背景

你应该做的第一步是包装,包装,再包装。因此,你应该首先确定代码中需要使用平台相关功能的部分。在我的游戏应用程序中,我非常惊讶地发现这种功能并不多。首先,让我们来看看应用程序的主要部分

  1. 用户交互
  2. 绘图
  3. 游戏逻辑

唯一真正依赖于平台的部分是第2点。第1点和第3点可以很容易地使用C++和STL来完成。真的就这些吗?不,你还需要找到一种在某种消息循环中运行游戏循环的方法,该消息循环位于你的应用程序窗口内。所以主要的任务是创建一个包装器,它能够进行绘制并执行应用程序的主循环。我决定编写一个抽象类作为所有所需功能的接口。让我们看看它的定义

class GdiWrapper
{
public:
    GdiWrapper(){};
    //making the game known to the Wraper for callback
    void SetGameNotifier( GameNotifier* pTheGame ){ m_pTheGame = pTheGame; }
    virtual ~GdiWrapper(){};//all deinitialisation
    //asking the user for Input
    virtual bool GetUserInput( char* pstrStringOne, char* pstrStringTwo ) = 0;
    //outputs a Mesage on the Screen
    virtual void MessageOutput( char* pstrMessage ) = 0;
    virtual void OutputGameInfo( char* pstrText ) = 0;//outputs an Info Text    
    virtual int DrawLine( int x1, int y1, int x2, int y2 ) = 0;//Draws a Line
    //Draws a Scale on the Playfield
    virtual int DrawScale( int x1, int y1, int x2, int y2 ) = 0;
    //Draws the Playstone Circles
    virtual void DrawCircle( int x, int y, int Radiant, 
           bool bFilled, unsigned long dwColor ) = 0;
    //Draws something at the End of a Playfield - Row
    virtual void DrawEndLineText( int x, int y, int iCoordinate ) = 0;
    //Shows the Visualisation Window and inits the Main - Loop
    virtual void RunMainLoop(void) = 0;
    //returns if the Apps Message-loop is still running
    virtual bool LoopRunning(void) = 0;
protected:
    GameNotifier* m_pTheGame;
};

这些函数是你可视化游戏所需要的一切。这样你就不需要包装整个GUI功能,你只需要一些处理应用程序中所需任务的函数。为了移植应用程序,你所要做的就是继承自GdiWrapper并实现所需的功能。如果你看看DrawEndLineText(...)函数及其在不同GdiWrapper移植中的使用,你会注意到,只有控制台实现才真正执行了在行末绘制坐标的功能。

使用代码

所有版本的代码都以非常相似的方式初始化

#include "Game.h"


int main(int argc, char* argv[])
{
    GdiWrapperKonsole theGdi;//instance of the choosen wrapper
    Game theGame( PlaySize( 5,5 ), &theGdi );//initializing the game
    theGame.Run();//running the game
    return 0;
}

在MFC版本中,初始化是在应用程序的InitInstance()中完成的。你看到,为了移植所要做的唯一工作就是编写一个新的GdiWrapper并使用它初始化游戏实例。

结论

编写平台无关代码并不总是需要用到哪些库的问题。开发一个可移植的应用程序可能需要多花一点时间,但之后移植应用程序应该会非常容易。你并不总是需要像QT这样大型工具包的完整功能,所以通常只要使用你真正需要的应用程序的一些功能就足够了。在开发过程中测试你的代码在不同的编译器上是永远不会错的(你会惊讶地看到我使用了多少次BOOL, DWORD和其他MS特定的定义)。这些是你需要注意的一些主要方面

  1. 尽量避免平台特定的定义(例如,MS特定的DWORD, BOOL...)。
  2. 将你的应用程序数据与你的可视化分开(MVC模式,DOC/View...)。
  3. 使用不同的编译器,并在不同的系统上进行测试。
  4. 当你编写包装器时,总是将包装的任务分解为简单易懂的函数。

但是,我的代码肯定不是最优的 - 我认为OpenGL实现与SDL就说明了这一点,但这仅仅是因为在开发游戏类时,我从未计划编写这样的实现。对于编译QT、SDL和wxWindows示例时可能出现的问题,我深感抱歉,但我只在我的Linux上使用KDevelop 3.0进行了测试。MFC和控制台实现是使用VS6完成的。

© . All rights reserved.