【VC++游戏开发】用C++来架构一个适合windows游戏编程的框架——取名为BCF

一、序言
  众所周知:
  MFC适合桌面应用的开发,而不太适合windows游戏编程,因为它封装了很多我们游戏编程中所不需要的东西,这些东西在一定程度上都影响着GDI的效率,略显冗余了。但是MFC有丰富的类库,这在写代码时又能提供很大的方便……
  再来看看Win32 SDK,接近底层,效率肯定好,但是却没有MFC那样的类库,写代码着实不太方便……
  这样一想,我就有个问题了:在接下来的游戏效果模拟中,是继续使用MFC,还是专用Win32SDK呢?或者还有什么更好的方法?……
  这么一想,嘿,一个idea就诞生了:用C++来自行架构一个适合windows游戏编程的框架,使它既能使用MFC类库,效率又更好
  这个框架如何架构呢?请继续阅读下面的内容吧^_^
  二、架构的一个简易框架,MFC类库、效率都能兼顾
  我的架构思路:
  1>将窗口创建过程(设计窗口类结构体实例、注册窗口类、创建窗口、显示窗口、消息循环)以及消息响应函数都封装在一个名为CCWindow的C++类中
  2>在Main.cpp源文件中就实现WinMain以及窗口过程
  由于我的开源框架的源代码中有详尽的注释,F话就不多说了,直接贴上源代码:
  StdAfx.h头文件:这是使用MFC类库所必须添加的头文件
  [cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  /***
  *
  *   StdAfx.h
  *   包含一些用到的类库所在的头文件
  *
  ***/
  #pragma once
  #define _AFXDLL//动态添加MFC类库
  #include <SDKDDKVer.h>//定义最高版本windows
  #include <afxwin.h>       // MFC封装的核心组件和标准组件
  #include <atlimage.h> //CImage类包含的头文件
  #include <MMSystem.h> //播放媒体(音乐)所需包含的头文件
  #pragma comment(lib, "winmm.lib")//添加媒体库
  #pragma comment(linker,"/manifestdependency:\"type='win32' \
  name='Microsoft.Windows.Common-Controls' \
  version='6.0.0.0' processorArchitecture='x86' \
  publicKeyToken='6595b64144ccf1df' language='*'\"")
  CWindow.h头文件(CCWindow类的定义)
  [cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  #pragma once
  #include"StdAfx.h"
  #include<time.h>
  class CCWindow
  {
  //==================成员====================
  private:
  WNDCLASS    m_wndclass; //窗口类结构体实例
  public:
  HWND        m_hwnd;     //窗口句柄
  CImage      m_img;      //背景图片
  CRect       m_rect;     //窗口户区大小
  //=============窗口创建相关的成员函数=============
  public:
  //设计窗口类
  bool InitWndClass(
  HINSTANCE hInstance,    //实例句柄
  WNDPROC   wpWndProc,    //窗口过程
  LPCTSTR   lpWndName,    //窗口名称
  LPCTSTR   lpIconPath);  //图标路径
  //设计窗口类
  bool InitWndClass(WNDCLASS);
  //注册窗口类
  ATOM RegisterWndClass();
  //创建窗口(默认居中)
  void Create(
  LPCTSTR lpClassName,    //窗口类名称
  LPCTSTR lpWndName,  //窗口标题名称
  DWORD   dwStyle,        //窗口风格
  int     nWidth,         //窗口宽度
  int     nHeight);       //窗口高度
  //显示窗口
  void Show(int);
  //一般的消息循环
  int RunMsgLoop();
  //更高效的消息循环
  int RunMsgLoop(void (*Display)(), int);
  //================消息响应函数================
  public:
  //注:在这里添加需要响应的消息处理函数的声明
  public:
  //构造函数
  CCWindow(void);
  //析构函数
  ~CCWindow(void);
  };
  CWindow.cpp(CCWindow类的成员函数实现)
  [cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  #include "CWindow.h"
  CCWindow::CCWindow(void)
  {
  }
  CCWindow::~CCWindow(void)
  {
  }
  /*------------------------------
  *功能:设计窗口类
  *@hInstance:    实例句柄
  *@WndProc:      窗口过程
  *@WndName:      窗口名称
  *@IconPath:     图标路径
  -----------------------------*/
  bool CCWindow::InitWndClass(HINSTANCE hInstance,//实例句柄
  WNDPROC WndProc,    //窗口过程
  LPCTSTR WndName,    //窗口名称
  LPCTSTR IconPath)   //图标路径
  {
  ZeroMemory(&m_wndclass, sizeof(WNDCLASS));
  m_wndclass.style            = CS_HREDRAW | CS_VREDRAW;
  m_wndclass.lpfnWndProc      = WndProc;
  m_wndclass.hInstance        = hInstance;
  m_wndclass.cbClsExtra       = 0;
  m_wndclass.cbWndExtra       = 0;
  m_wndclass.hIcon            =
  static_cast<HICON>(LoadImage(NULL, IconPath, IMAGE_ICON,
  0, 0, LR_DEFAULTSIZE | LR_LOADFROMFILE));
  m_wndclass.hCursor          = ::LoadCursor(NULL, IDC_ARROW);
  m_wndclass.hbrBackground    =
  static_cast<HBRUSH>(GetStockObject(WHITE_BRUSH));
  m_wndclass.lpszMenuName     = NULL;
  m_wndclass.lpszClassName    = WndName;
  return true;
  }
  /*--------------------------------------
  设计窗口类
  --------------------------------------*/
  bool CCWindow::InitWndClass(WNDCLASS wndclass)
  {
  m_wndclass = wndclass;
  return true;
  }
  /*--------------------------------------
  注册窗口类
  --------------------------------------*/
  ATOM CCWindow::RegisterWndClass()
  {
  return RegisterClass(&m_wndclass);
  }
  /*--------------------------------------
  创建窗口
  --------------------------------------*/
  void CCWindow::Create(
  LPCTSTR lpClassName,
  LPCTSTR lpWindowName,
  DWORD dwStyle,
  int nWidth,
  int nHeight)
  {
  //获取屏幕宽度和高度
  int screenW = GetSystemMetrics(SM_CXSCREEN);
  int screenH = GetSystemMetrics(SM_CYSCREEN);
  //创建并居中显示窗口
  m_hwnd = CreateWindow(lpClassName, lpWindowName, dwStyle,
  (screenW-nWidth)/2, (screenH-nHeight)/2,
  nWidth, nHeight, NULL, NULL,
  m_wndclass.hInstance, NULL);
  }
  /*--------------------------------------
  显示窗口
  --------------------------------------*/
  void CCWindow::Show(int nCmdShow)
  {
  ShowWindow(m_hwnd, nCmdShow);
  }
  //UpdateWindow(...)更新窗口(可以省略)
  /*--------------------------------------
  一般的消息循环
  GetMessage()
  --------------------------------------*/
  int CCWindow::RunMsgLoop()
  {
  MSG msg;
  ZeroMemory(&msg, sizeof(MSG));
  while(GetMessage(&msg, NULL, 0, 0))
  {
  TranslateMessage(&msg);
  DispatchMessage(&msg);
  }
  return msg.wParam;
  }
  /*--------------------------------------
  消息循环(更好的消息循环)
  PeekMessage()
  --------------------------------------*/
  int CCWindow::RunMsgLoop(void (*Display)(), int interval)
  {
  MSG msg;
  ZeroMemory(&msg, sizeof(MSG));
  //获取运行到此处时的时间
  int last = GetTickCount();
  //如果不是退出消息
  while(msg.message != WM_QUIT)
  {
  //如果有消息
  if(PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
  {
  TranslateMessage(&msg);
  DispatchMessage(&msg);
  }
  //否则, 空闲的时候执行响应函数(大多数是绘制函数)
  else
  {
  //如果窗口客户区大小不为0就是显示(有可能窗口是在最小化)
  if(m_rect.Width() &&
  m_rect.Height())
  {
  Display();
  Sleep(interval);
  }
  }
  }
  return msg.wParam;
  }
  //----------------------------------------------------------
  //                      消息响应函数
  //----------------------------------------------------------
  //注:在这里添加需要响应的消息处理函数的实现
  Main.h头文件(主程序头文件)
  [cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  /***
  *
  *   Main.h
  *   主程序所需包含的头文件、宏定义、声明等
  *
  ***/
  #pragma once
  #include "CWindow.h"
  #define WNDNAME "【VC++游戏开发】窗口名称"//窗口名称
  #define WNDWIDTH 800//窗口宽度
  #define WNDHEIGHT 600//窗口高度
  //窗口关联对象:全局对象
  CCWindow wnd;
  //窗口过程
  LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
  Main.cpp(主程序代码:负责WinMain、WndProc)
  [cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  <span style="font-size:18px;">#include "Main.h"
  /*
  显示函数:绘制随机位置、大小、颜色的矩形
  注:由于调用很频繁,故设为内联函数
  */
  inline void Display()
  {
  //做响应的操作
  }
  //
  //==============WinMain=======================
  //
  int WINAPI WinMain(HINSTANCE hInstance,
  HINSTANCE hPrevInstance,
  LPSTR lpCmdLine,
  int nCmdShow)
  {
  //设计窗口类
  CString iconPath = "";//图标的路径(这里没有, 需自己设定)
  wnd.InitWndClass(hInstance, WndProc, WNDNAME, iconPath);
  //注册窗口类
  if(!wnd.RegisterWndClass())
  {
  ::AfxMessageBox("RegisterWndClass() Failed");
  return 0;
  }
  DWORD style = WS_OVERLAPPEDWINDOW &
  ~(WS_THICKFRAME | WS_MAXIMIZEBOX);
  //创建窗口并居中窗口
  wnd.Create(WNDNAME, WNDNAME, style,
  WNDWIDTH, WNDHEIGHT);
  //显示窗口
  wnd.Show(nCmdShow);
  /*进入消息循环
  1. 使用更好的消息循环 如:wnd.RunMsgLoop(Display, 100)
  2. 使用一般的消息循环 如:wnd.RunMsgLoop()
  */
  return wnd.RunMsgLoop();
  }
  //
  //================窗口过程:处理消息=================
  //
  LRESULT CALLBACK WndProc(
  HWND hwnd,
  UINT msg,
  WPARAM wParam,
  LPARAM lParam)
  {
  /*
  在这里添加消息映射代码(switch-case语句)
  如:
  switch(msg)
  {
  case WM_CREATE:
  wnd.OnCreate(); //窗口建立消息:进行一些初始化操作
  return 0;
  }
  */
  return DefWindowProc(hwnd, msg, wParam, lParam);
  }</span>
  下面,我简单地介绍一下这个框架的使用方法:
  1>创建一个空项目(我这里是VS2010)
  2>将这3个头文件以及2个cpp源文件添加到创建好的项目中
  3>在 CWindow.h中添加消息响应函数(CCWindow类的成员函数)的声明
  如:(名称还是遵循MFC的命名方式)
  [cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  //================消息响应函数================
  public:
  //注:在这里添加需要响应的消息处理函数的声明
  void OnCreate();;
  4>CWindow.cpp中实现这些消息响应函数
  5>在Main.cpp的窗口过程函数中调用响应的消息响应函数
  如:
  [cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  switch(msg)
  {
  case WM_CREATE:
  wnd.OnCreate(); //窗口建立消息:进行一些初始化操作
  return 0;
  }
  我还是为这个框架取一个"艺名儿",名为:BCF
  BC:我的csdn博客ID缩写——BlueCoder
  F:frame——框架的意思
  合起来就是BlueCoder的框架,当然,大家都可以用,只要你愿意,我也乐意^_^
  三、一个简单的实例,教你熟悉这个框架
  我做了一个简单的实例,来帮助大家熟悉这个框架
  这个实例呢,就是简单的贴图、贴文字,不过你会看到有趣的部分:我使用了诸如CPaintDC、CFont、CString、CImage、CRect等MFC类库。对,没错,这就是这个框架的一大特点:可以使用MFC类库,这就方便了我们写代码
  由于没什么复杂的原理,我就按照步骤贴出核心代码哈:
  (1)项目、头文件、源文件已经相继处理好了
  (2)在CCWindow类中添加如下的消息响应成员函数:
  [cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  //================消息响应函数================
  //注:在这里添加需要响应的消息处理函数
  public:
  //处理WM_CREATE消息
  void OnCreate();
  //处理WM_SIZE消息
  void OnSize();
  //处理WM_PAINT消息
  void OnPaint();
  //处理WM_KEYDOWN消息
  void OnKeyDown(WPARAM);
  //处理WM_DESTROY消息
  void OnDestroy();
  (3)这些消息响应函数的实现:
  [cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  //----------------------------------------------------------
  //                      消息响应函数
  //----------------------------------------------------------
  //窗口建立消息:进行一些初始化操作
  void CCWindow::OnCreate()
  {
  m_img.Load("res\\bg.jpg");
  if(m_img.IsNull())
  {
  AfxMessageBox("背景图片加载失败!");
  exit(0);
  }
  mciSendString("open res\\bgm.mp3 alias bgm", 0, 0, 0);
  mciSendString("play bgm repeat", 0, 0, 0);
  }
  //窗口size消息:获取窗口大小
  void CCWindow::OnSize()
  {
  ::GetClientRect(m_hwnd, m_rect);
  }
  //窗口Paint消息:绘制窗口客户区
  void CCWindow::OnPaint()
  {
  CPaintDC dc(CWnd::FromHandle(m_hwnd));
  //绘制背景图片
  dc.SetStretchBltMode(COLORONCOLOR);
  m_img.StretchBlt(dc, 0, 0, m_rect.Width(), m_rect.Height(),
  0, 0, m_img.GetWidth(), m_img.GetHeight(), SRCCOPY);
  //绘制文字
  CFont font;
  font.CreatePointFont(150, "微软雅黑");
  dc.SelectObject(font);
  CString str1 = "给自己的梦想一次破茧而出的机会,创造属于自己的幸福";
  CString str2 = "BlueCoder(黎小华)";
  dc.SetBkMode(TRANSPARENT);
  dc.SetTextColor(RGB(163, 21, 21));
  dc.TextOut(130, 220, str1);
  dc.SetTextColor(RGB(21, 155, 230));
  dc.TextOut(500, 300, str2);
  }
  //按键消息:按下Esc键退出程序
  void CCWindow::OnKeyDown(WPARAM wParam)
  {
  if(wParam == VK_ESCAPE)
  {
  DestroyWindow(m_hwnd);
  }
  }
  //窗口销毁消息:释放内存
  void CCWindow::OnDestroy()
  {
  m_img.Destroy();
  mciSendString("close bgm", 0, 0, 0);
  PostQuitMessage(0);
  }
  (4)在Main.cpp中的窗口过程中调用响应的消息成员函数:
  [cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  //窗口过程:处理消息
  LRESULT CALLBACK WndProc(
  HWND hwnd,
  UINT msg,
  WPARAM wParam,
  LPARAM lParam)
  {
  switch(msg)
  {
  case WM_CREATE:
  wnd.OnCreate(); //窗口建立消息:进行一些初始化操作
  return 0;
  case WM_SIZE:
  wnd.OnSize();   //窗口size消息:获取窗口大小
  return 0;
  case WM_KEYDOWN:    //按键消息
  wnd.OnKeyDown(wParam);
  return 0;
  case WM_PAINT:      //窗口Paint消息:绘制窗口客户区
  wnd.OnPaint();
  return 0;
  case WM_DESTROY:    //窗口销毁消息:释放内存
  wnd.OnDestroy();
  return 0;
  }
  return DefWindowProc(hwnd, msg, wParam, lParam);
  }
  注:此时,我们使用的是一般的消息循环
  看着这些代码,你是否觉得和我原先的MFC代码以及风格很相似呢?呵呵:)
  ok,来看看运行效果吧:
  有心的朋友可能已经发现在我封装的CCWindow类中有两个消息循环成员函数:
  1>RunMsgLoop()  ——  一般的消息循环:GetMessage
  2>RunMsgLoop(void (*Display)(), int) ——  更有效的消息循环:PeekMessage
  注:1、如果不熟悉这GetMessage、PeekMessage两个API函数的区别,请查阅MSDN
  2、给不明白的朋友一个提示: void (*Display)()  这是函数指针的声明的格式
  这个一般的消息循环的实例已经在刚刚这个实例中用到,下面就用第二个:更有效的消息循环
  这个更有效的消息循环有两个好处:(1)效率好  (2)我们可以省略计时器的设定
  1、所谓效率好,就是程序能利用其空闲的时候——没有消息处理的情况下,来执行一些操作(例如:贴图==)
  2、由于利用的是程序没有消息路由的空闲时间来处理一些操作,即只要没有消息,我们就能执行自己想要的代码,那么我们便可以通过Sleep这个函数来模拟计时器的效果——让这些操作的执行能有一个有序的时间间隔
  那么这个有效的消息循环,如何使用呢?
  你需要自行写一个函数void Display(),然后让这个消息循环执行这个显示函数就ok了
  还是来看看代码吧:(我实现的功能,是借用P先生《Windows程序设计》中的一个例子,很simple:不断绘制一些随机位置、大小、颜色的矩形)
  注:我并没有使用计时器,Sleep()函数模拟了计时器的作用效果
  [cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  /*--------------------------------------
  消息循环(更好的消息循环)
  PeekMessage()
  @Display:执行函数
  @interval:函数执行的时间间隔
  --------------------------------------*/
  int CCWindow::RunMsgLoop(void (*Display)(), int interval)
  {
  MSG msg;
  ZeroMemory(&msg, sizeof(MSG));
  //获取运行到此处时的时间
  int last = GetTickCount();
  //如果不是退出消息
  while(msg.message != WM_QUIT)
  {
  //如果有消息
  if(PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
  {
  TranslateMessage(&msg);
  DispatchMessage(&msg);
  }
  //否则, 空闲的时候执行响应函数(大多数是绘制函数)
  else
  {
  //如果窗口客户区大小不为0就是显示(有可能窗口是在最小化)
  if(m_rect.Width() &&
  m_rect.Height())
  {
  Display();//执行函数
  Sleep(interval);//当前线程睡眠一会儿
  }
  }
  }
  return msg.wParam;
  }
  在WinMain调用这个更有效的消息循环:
  [cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  /*进入消息循环
  1. 使用更好的消息循环wnd.RunMsgLoop(Display, 100)
  2. 使用一般的消息循环wnd.RunMsgLoop()
  */
  return wnd.RunMsgLoop(Display, 100);
  实现效果:
  可见一些随机的矩形在不断地绘制,还是很漂亮吧:》
  四、你想要的开源源代码
  等待多时的开源框架BCF的源代码总算能开始下载了:
  开源框架BCF源码以及相关实例
  希望大家帮我多测试一下BCF哈,有什么bug请及时告诉我,我将尽快纠正
  另外,还欢迎大家和我交流,留下你想说的话(不喜勿碰^_^),因为你们的支持是我继续努力开源的动力:)
  ……
  ……
  一不留神,时间飞逝,现在都凌晨1点多了——但愿我夜以继日的无私奉献,能帮助到和我有共同兴趣爱好的有志青年,让我们一起踏上美好的游戏编程之旅,扬帆起航,实现我们共同的梦想……
  电脑屏幕前的你,晚安,BlueCoder也晚安,BCF,加油,哈哈……
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值