// gameapp.h #ifndef __GAMEAPP_H__ #define __GAMEAPP_H__ //我们的游戏类必须从 SexyAppBase 类派生. 后者声明在这个头文件. #include "SexyAppFramework/SexyAppBase.h" // 声明我们定义在 Board.h 中的窗体部件类. class Board; ////////////////////////////////////////////////////////////////////////// // 游戏类. // 直接从 SexyAppBase 派生. 并实现基类中的几个函数(做初始化,加载资源等工作). // 它的作用是创建窗体部件 Board (游戏的界面. 逻辑. 处理用户输入等等工作都由窗体部件来做) // 并且要加载程序中用到的资源. /////////////////////////////////////////////////////////////////////////// class GameApp : public SexyAppBase { Board* mBoard; //我们的窗体部件 public: GameApp(); virtual ~GameApp(); ////////////////////////////////////////////////////////////////////////// // 初始化. // 如果我们的程序要有一个前导. 放在这里. // 框架会在这个函数返回后自动调用 后边的 LoadingThreadProc() ////////////////////////////////////////////////////////////////////////// virtual void Init(); ////////////////////////////////////////////////////////////////////////// // 加载程序用到的资源 // 这个函数在一个单独的线程中进行. // 如果加载时间稍长. 我们需要一个类似 " Loading ... " 的前导. // 可以在这个函数中更新加载进度条. // 这个函数执行完毕时. 框架自动调用后边的 LoadingThreadCompleted() ////////////////////////////////////////////////////////////////////////// virtual void LoadingThreadProc(); ////////////////////////////////////////////////////////////////////////// // 资源全部加载完毕以后 应该执行的动作. ////////////////////////////////////////////////////////////////////////// virtual void LoadingThreadCompleted(); }; #endif // __GAMEAPP_H__ //board.h #ifndef __BOARD_H__ #define __BOARD_H__ #include "SexyAppFramework/Widget.h" class Graphics; class GameApp; ////////////////////////////////////////////////////////////////////////// // Board 类 // 从 Widget 派生. 游戏的所有的功能. 游戏绘图,更新,处理输入. 都在这个类完成. // 因为Widget(窗口部件)被加入到 GameApp 的 WidgetManager 时. 会自动启动游戏的消息循环. // 自动调用Widget的 Update() 和 Draw(). 并在需要的时候处理用户输入. 每秒100帧. // 这样游戏的逻辑应该不能执行的太慢. ////////////////////////////////////////////////////////////////////////// class Board : public Widget { GameApp* mApp; //持有主程序类的指针. 在本类中要调用GameApp的一些函数. public: Board(GameApp* theApp){ mApp = theApp;} virtual ~Board(){} ////////////////////////////////////////////////////////////////////////// // 绘制 // 这个函数被 GameApp 的 WidgetManager 自动调用. // 参数 g 用来在屏幕上绘制图像和文字 ////////////////////////////////////////////////////////////////////////// virtual void Draw(Graphics* g); ////////////////////////////////////////////////////////////////////////// // 更新 // 这个函数被 GameApp 的 WidgetManager 自动调用. (每秒100次). // 它处理游戏的逻辑. ////////////////////////////////////////////////////////////////////////// virtual void Update(); }; #endif // __BOARD_H__ //gameapp.cpp #include "GameApp.h" #include "Board.h" #include "SexyAppFramework/WidgetManager.h" #include "SexyAppFramework/Common.h" //SexyAppFramework 把所有的东西都声明在名字空间 Sexy 中. using namespace Sexy; ////////////////////////////////////////////////////////////////////////// GameApp::GameApp() { // 游戏的名字. 在内部使用. mProdName = "Demo 1"; // 版本 mProductVersion = "1.0"; // 游戏运行时. 在窗口的标题栏显示的内容 mTitle = StringToSexyStringFast("SexyAppFramework: " + mProdName + " - " + mProductVersion); // 注册表读写的路径 mRegKey = "PopCap\SexyAppFramework\Demo1"; // 设置宽高. 这些成员都是在GameApp的基类中定义的. mWidth = 640; mHeight = 480; // 窗体部件. 在后边的函数中创建窗体. mBoard = NULL; } ////////////////////////////////////////////////////////////////////////// GameApp::~GameApp() { // 对所有的窗体部件来说. 在 delete 之前. 必须将之从 mWidgetManager 中 RemoveWidget(). // 否则运行的时候会有一个 assert. mWidgetManager->RemoveWidget(mBoard); delete mBoard; } ////////////////////////////////////////////////////////////////////////// void GameApp::Init() { // 在这里总是必须先调用基类的 Init(). SexyAppBase::Init(); //在这个例子中. 我们的Init()无事可作. 但以后的例子中会使用它. // 这个函数执行完后. 框架自动调用 LoadingThreadProc() 来加载资源. } ////////////////////////////////////////////////////////////////////////// void GameApp::LoadingThreadProc() { // 这个函数用一个单独的线程来加载资源. 并更新加载进度(如果有的话). // 在这个例子中. 它没有什么资源要加载. 但以后的例子中会使用它. // 它执行完毕后. 框架会自动调用 LoadingThreadCompleted(). } ////////////////////////////////////////////////////////////////////////// void GameApp::LoadingThreadCompleted() { //调用基类的LoadingThreadCompleted() SexyAppBase::LoadingThreadCompleted(); // 当所有的资源加载都没有失败时. mloadingfailed被设置为false. 否则设置为 true. // 所以在这里要检查该变量. 若资源加载失败则返回. if (mLoadingFailed) return; // 创建我们定义的 Board 窗体部件. mBoard = new Board(this); // 设置窗体部件的大小和位置. 这个步骤不可以省略. 因为缺省时它们是0,0. 我们看不到. // 这里mBoard是我们的主窗口控件. 所以设置它的大小为 GameApp 的大小(mWidth, mHeight). // 其中(mWidth, mHeight)我们已经在构造函数中指定了值. mBoard->Resize(0, 0, mWidth, mHeight); // 然后将刚才创建的窗体部件加入 mWidgetManager. // 这也是一个重要的步骤. 它意味着我们的 mBoard 对象从此可以自动的被调用 Update(). Draw(). 以及处理输入事件. mWidgetManager->AddWidget(mBoard); } //board.cpp #include "Board.h" #include "SexyAppFramework/Graphics.h" #include "SexyAppFramework/Color.h" // 使用 Color 类. #include "SexyAppFramework/Point.h" // 使用 Point 类. using namespace Sexy; ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// void Board::Update() { // 调用基类的 Update(). 将会++mUpdateCnt. (它表示Update()被调用了多少次) // 因为这个函数每秒被调用100次. 所以我们也可以用 mUpdateCnt 的值做为游戏的计时器使用. Widget::Update(); // 下边这个函数告诉 widget manager 该部件已经变脏. 这样就会重画它. // 如果不需要重画(比如游戏变为不活动的)也可以不调用它. 节约一点cpu时间. MarkDirty(); } // 绘制函数. 它自动被 WidgetManager 调用. 而且是自动双缓冲的. void Board::Draw(Graphics* g) { //填充矩形. //缺省时. 颜色是黑色. g->FillRect(0, 0, mWidth, mHeight); //设置当前颜色 g->SetColor(Color(255, 128, 64)); //Color可以有3个或4个参数. //画线 //参数为X1, Y1, X2, Y2 g->DrawLine(0, 0, 200, 150); //绘制矩形(但不填充矩形内部) g->DrawRect(200, 150, (mWidth - 200) - 200, (mHeight - 150) - 150); //绘制多边形 // 先定义一个 Point数组. 保存多边形的每个顶点的坐标. // 然后用 PolyFill() 来绘制多边形. Point trianglePoints[3]; trianglePoints[0] = Point(30, 30); trianglePoints[1] = Point(30, 60); trianglePoints[2] = Point(60, 45); g->SetColor(Color(255, 255, 0)); // yellow g->PolyFill(trianglePoints, 3); } // main.cpp #include "GameApp.h" using namespace Sexy; // 主函数 // int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { // 设置 gHInstance . 这个动作不能省略. gHInstance = hInstance; // 创建并初始化游戏主类. GameApp* anApp = new GameApp(); anApp->Init(); // 开始执行. anApp->Start(); delete anApp; return 0; }