精华内容
下载资源
问答
  • 但是我被困在制作游戏引擎中! 该存储库现在重点关注的是什么。 目标 创建游戏引擎需要大量工作。 因此,我的目标并不是要与流行的游戏引擎(例如Unity,Unreal,Source,Godot或Lumberyard)竞争。 相反,我尝试使...
  • coelum:C语言制作游戏引擎
  • Kong雀:制作精美游戏的游戏引擎
  • 手工制作:小型教育游戏引擎
  • JavaFX-游戏引擎 使用 JavaFX 制作游戏引擎
  • 引擎 一个用c ++制作的简单游戏引擎
  • 利用2D游戏引擎HGE开发的拼图游戏,适合新手学习用,内附 HGE教程和中文帮助文档 资源都在,声音文件自己加,源码可以自行改造等多关
  • unity3D游戏引擎制作,简易版炸弹人,包含发布的游戏和源码。
  • 生存虚幻游戏 使用Unreal Engine 4游戏引擎制作的生存游戏。
  • 空心车游戏引擎 一个用于制作简单迷宫游戏的游戏引擎。 模板 我使用作为模板,因此我可能需要另一个JavaScript文件。
  • 使用H5游戏引擎制作的日语《五十音图连连》看小游戏
  • 尝试制作游戏引擎 游戏引擎
  • 引擎 按照 thebennybox 的教程制作的 Java 游戏引擎
  • mattock_fight 使用Godot游戏引擎制作的2D多人游戏
  • 2D游戏引擎制作:图片与文字

    千次阅读 2018-02-26 22:41:58
    上一篇除笔者外只有3个浏览记录,好悲伤,如果不是引擎制作而是游戏制作是不是人会多一点。 正文以下代码接上篇文章。 接下来绘制图片,需要引入新头文件:#include 在初始化d2d后添加初始化WIC(direct2D中常用...

    图片与文字


    前言

      基础部分就稍快一点,但是一天一篇笔者也累啊!上一篇除笔者外只有3个浏览记录,好悲伤,如果不是引擎制作而是游戏制作是不是人会多一点。 


    正文

    以下代码接上篇文章。
    接下来绘制图片,需要引入新头文件:

    #include <Wincodec.h>

    在初始化d2d后添加初始化WIC(direct2D中常用WIC来加载图片)的方法:

    IWICImagingFactory* wicFactory = NULL;
    ID2D1Bitmap* pBitmap = NULL;
    
    CoInitialize(NULL);
    CoCreateInstance(CLSID_WICImagingFactory, nullptr, CLSCTX_INPROC_SERVER,IID_PPV_ARGS(&wicFactory));

    加载每个图片的方法一样,可以封装到一个方法里:

    IWICBitmapDecoder* decoder;
    IWICBitmapFrameDecode* source;
    IWICFormatConverter* converter;
    IWICBitmap* wicBitmap;
    
    wicFactory->CreateDecoderFromFilename(bitmapName.c_str(), NULL, GENERIC_READ, WICDecodeMetadataCacheOnLoad, &decoder);
    
    decoder->GetFrame(0, &source);
    wicFactory->CreateFormatConverter(&converter);
    converter->Initialize(source, GUID_WICPixelFormat32bppPBGRA, WICBitmapDitherTypeNone, nullptr, 0, WICBitmapPaletteTypeMedianCut);
    wicFactory->CreateBitmapFromSource(converter, WICBitmapCacheOnDemand, &wicBitmap);
    pRenderTarget->CreateBitmapFromWicBitmap(wicBitmap, &pBitmap);
    
    decoder->Release();
    decoder = NULL;
    source->Release();
    source = NULL;
    converter->Release();
    converter = NULL;
    wicBitmap->Release();
    wicBitmap = NULL;

    绘制图片,在原有绘制矩形函数前加一句:

    pRenderTarget->DrawBitmap(pBitmap, D2D1::RectF(100.f, 100.f, 500.f, 500.f));

    运行效果。
    这里写图片描述

    添加文字,需要引入新头文件:

    #include <dwrite.h>
    #pragma comment(lib,"dwrite.lib")

    初始化方法:

    DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), (IUnknown**)&writeFactory);
    writeFactory->CreateTextFormat(L"宋体", NULL,DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, 30, L"chs", &textFormat);
    //每需要一种字体需要生成一个textFormat,只生成一个在改属性也可以。

    绘制文字,在原有绘制图片函数后加一句:

    pRenderTarget->DrawTextW(text.c_str(), text.size(), textFormat, D2D1::RectF(100.f, 100.f, 500.f, 500.f), pBlackBrush);

    运行效果。
    这里写图片描述

    至此,简单显示部分算完成了,绘制其它图形方法相似,只是更改函数,至于画路径那种的暂时用不到,使用到了再看即可,想学习其它方法的读者可以到上篇文章中Direct2D教程链接中查看。


    结束语

      多说一句,编写博客的工具Markdown,功能是很强大,但好像直接从word中拷贝文字复制过来会显示不正常,可能是文字中有隐藏的字符吧!

    展开全文
  • 一个相对简单的python游戏引擎。 谢谢,我很牛。 看看它在样子 这是 Python 中的 2D 物理游戏引擎。 目前,它使用库进行窗口和 opengl 绑定,尽管我对最终转向某种 gui 工具包很感兴趣。 这是非常不确定的。 我...
  • 本文提供一个完整的游戏引擎代码,并有详细代码解析。后续将根据这个游戏引擎开发小游戏,逐渐完善该引擎并介绍游戏编程相关的知识。 假设你起码拥有C++的知识。以《游戏编程入门》 Micheal Morrison为基本教材,PDF...

    本文提供一个完整的游戏引擎代码,并有详细代码解析。后续将根据这个游戏引擎开发小游戏,逐渐完善该引擎并介绍游戏编程相关的知识。

    假设你起码拥有C++的知识。

    以《游戏编程入门》 Micheal Morrison为基本教材,PDF书籍下载光盘内容下载

    开发环境为Win7,VC 6++ 企业版

    接上文 游戏编程入门(1):游戏专业概论


    搭建开发环境

    VC 6++ 企业版下载

    解压后,进入文件夹内,点击AUTORUN.EXE进行安装。

    无毒,建议把360关了,老提醒些有的没的,一般就是下一步下一步,没什么难的。

    安装过程不会的话,点击这里

    测试VC 6++

    安装好了后,我们进行一个简单的测试,测试VC 6++是否正常运作

    点击文件,新建,选择工程中的Win32 Console Application(Win32控制台程序)

    这里写图片描述

    选择 一个“Hello World”程序

    这里写图片描述

    初始文件结构如下:

    这里写图片描述

    进入Test.cpp。编译,出现错误。

    C1083: Cannot open precompiled header file: ‘Debug/Test.pch’: No such file or directory 报错

    错误原因

    预编译头文件还没有编译

    解决方法

    右键点击项目工程中的该cpp文件,选择setting(设置),在c/c++栏,,选择PreCompiled headers(预编译的头文件),然后设置第一项(选择不使用预编译头选项)。

    这里写图片描述

    再次编译,问题解决

    VC6++打开,添加文件,会崩溃 的问题

    点击打开文件,或者添加文件,会导致崩溃。

    错误原因

    VC6与新版本windows不兼容

    解决方法

    (1)下载 FileTool.dll 文件,将下载的FileTool.rar文件解压得到FileToll.dll,然后将FileToll.dll放到VC目录下的 \Common\MSDev98\AddIns 文件夹中,如图:

    这里写图片描述

    (2)打开VC6,点击“工具”菜单,选择“定制”,打开定制对话框,如图:

    这里写图片描述

    (3)在“定制”对话框中选择“附加项和宏文件”,勾选“File Tool……”项(如果没有该项的话,点击“浏览”,定位到刚才的FileTool.dll文件并打开,就会出现该项),完成后点击关闭,如图:

    这里写图片描述

    (4)关闭“定制”对话框后,就会出现下图所示的两个按钮,分别是对应“打开”和“向工程中添加文件”的功能。

    这里写图片描述

    现在就可以正常使用了,但是点击原来的“打开”或者Ctrl+O依旧会崩溃(没啥影响)

    强迫症患者可以继续去该Blog解决问题->
    http://www.cnblogs.com/leftshine/p/5211605.html

    游戏引擎 源代码

    先给出游戏引擎源代码。后面开始进行分析。(不习惯的朋友可以先看后面的分析,再来看这部分源代码)

    GameEngine 分为 GameEngine.h 和 GameEngine.cpp。

    在头文件GameEngine.h中我们存储功能函数、数据接口的声明,而在GameEngine.cpp中我们具体实现一部分。

    GameEngine.h 源代码

    #pragma once /*该头文件仅编译一次(因为同一头文件会在许多源文件中多次引用。如
    果没有指定编译一次,则编译时出现重定义错误。*/
    
    //-----------------------------------------------------------------
    //包含的头文件 
    //-----------------------------------------------------------------
    #include <windows.h>
    
    //-----------------------------------------------------------------
    //Windows函数声明 
    //-----------------------------------------------------------------
    /*WinMain函数应初始化应用程序,显示主窗口,进入一个消息接收一发送循环,
    这个循环是应用程序执行的其余部分的顶级控制结构。*/ 
    int WINAPI        WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                        PSTR szCmdLine, int iCmdShow);
    //窗口过程,指向一个应用程序定义的窗口过程的指针。                   
    LRESULT CALLBACK  WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
    
    //-----------------------------------------------------------------
    //游戏事件函数声明 
    //-----------------------------------------------------------------
    BOOL GameInitialize(HINSTANCE hInstance);//初始化游戏 
    void GameStart(HWND hWindow);            //启动游戏 
    void GameEnd();                          //结束游戏 
    void GameActivate(HWND hWindow);         //激活游戏 
    void GameDeactivate(HWND hWindow);       //停用游戏 
    void GamePaint(HDC hDC);                 //绘制游戏 
    void GameCycle();                        //循环游戏 
    
    //-----------------------------------------------------------------
    // GameEngine类定义 
    //-----------------------------------------------------------------
    class GameEngine
    {
    protected:
      //成员变量
      static GameEngine*  m_pGameEngine; //指向自身的静态指针,用于游戏程序的外部访问
      HINSTANCE           m_hInstance;           //应用程序实例句柄
      HWND                m_hWindow;             //主窗口句柄
      TCHAR               m_szWindowClass[32];   //窗口类的名称
      TCHAR               m_szTitle[32];         //主游戏窗口的名称
      WORD                m_wIcon, m_wSmallIcon; //游戏的两个程序图标的数字ID
      int                 m_iWidth, m_iHeight;   //游戏屏幕的宽度和高度
      int                 m_iFrameDelay;         //游戏周期之间的间隔,单位是ms
      BOOL                m_bSleep;              //表示游戏是否在休眠
    
    public:
      //构造函数和析构函数
    
      //游戏引擎构造函数使用默认的屏幕大小(640*480)创建游戏,这是实际的游戏区
              GameEngine(HINSTANCE hInstance, LPTSTR szWindowClass, LPTSTR szTitle,
                WORD wIcon, WORD wSmallIcon, int iWidth = 640, int iHeight = 480);
      virtual ~GameEngine();
    
      //常规方法
    
      //在引擎外部使用这个静态方法访问指向引擎的静态指针 
      static GameEngine*  GetEngine() 
      { 
             return m_pGameEngine; 
      };
      //创建引擎后,初始化游戏程序 
      BOOL                Initialize(int iCmdShow);
      //处理引擎内的标准Windows事件 
      LRESULT             HandleEvent(HWND hWindow, UINT msg, WPARAM wParam,LPARAM lParam);
    
      //访问方法
      HINSTANCE GetInstance() 
      { 
                return m_hInstance; 
      };
      HWND      GetWindow() 
      { 
                return m_hWindow; 
      };
      void      SetWindow(HWND hWindow) 
      { 
                m_hWindow = hWindow; 
      };
      LPTSTR    GetTitle() 
      { 
                return m_szTitle; 
      };
      WORD      GetIcon() 
      { 
                return m_wIcon; 
      };
      WORD      GetSmallIcon() 
      {
                 return m_wSmallIcon; 
      };
      int       GetWidth() 
      {
                 return m_iWidth; 
      };
      int       GetHeight() 
      { 
                return m_iHeight; 
      };
      int       GetFrameDelay() 
      { 
                return m_iFrameDelay; 
      };
      //指定帧速率,当值为30时会使游戏以30帧/秒的速率运行
      void      SetFrameRate(int iFrameRate) 
      { 
                m_iFrameDelay = 1000 /iFrameRate; 
      };
      BOOL      GetSleep() 
      { 
                return m_bSleep; 
      };
      void      SetSleep(BOOL bSleep) 
      { 
                m_bSleep = bSleep; 
      };
    };

    GameEngine.cpp 源代码

    
    //-----------------------------------------------------------------
    //包含的头文件
    //-----------------------------------------------------------------
    #include "GameEngine.h"
    
    //-----------------------------------------------------------------
    // 初始化静态的游戏指针 
    //-----------------------------------------------------------------
    GameEngine *GameEngine::m_pGameEngine = NULL;
    
    //-----------------------------------------------------------------
    // Windows函数  
    //-----------------------------------------------------------------
    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
      PSTR szCmdLine, int iCmdShow)
    {
      MSG         msg;
      static int  iTickTrigger = 0;
      int         iTickCount;
    
      if (GameInitialize(hInstance)) //通过调用GameInitialize()初始化游戏 
      {
        // 初始化游戏引擎 
        if (!GameEngine::GetEngine()->Initialize(iCmdShow))
          return FALSE;
    
        // 进入主消息循环 
        while (TRUE)
        {
          if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
          {
            //处理消息 
            if (msg.message == WM_QUIT)
              break;
            TranslateMessage(&msg);
            DispatchMessage(&msg);
          }
          else  //这段代码创建游戏的计时机制 
          {
            // 确保游戏引擎没有休眠 
            if (!GameEngine::GetEngine()->GetSleep())
            {
              // 检查滴答计数,查看是否过了一个游戏周期 
              iTickCount = GetTickCount();
              if (iTickCount > iTickTrigger)
              {
                iTickTrigger = iTickCount +
                  GameEngine::GetEngine()->GetFrameDelay();
                GameCycle();
              }
            }
          }
        }
        return (int)msg.wParam;
      }
    
      // 结束游戏 
      GameEnd();
    
      return TRUE;
    }
    
    LRESULT CALLBACK WndProc(HWND hWindow, UINT msg, WPARAM wParam, LPARAM lParam)
    {
      // 将所有Windows消息传递给游戏引擎 
      return GameEngine::GetEngine()->HandleEvent(hWindow, msg, wParam, lParam);
    }
    
    //-----------------------------------------------------------------
    // GameEngine的构造函数和析构函数 
    //-----------------------------------------------------------------
    GameEngine::GameEngine(HINSTANCE hInstance, LPTSTR szWindowClass,
      LPTSTR szTitle, WORD wIcon, WORD wSmallIcon, int iWidth, int iHeight)
    {
      // 设置游戏引擎的成员变量 
      m_pGameEngine = this;
      m_hInstance = hInstance;
      m_hWindow = NULL;
      if (lstrlen(szWindowClass) > 0)
        lstrcpy(m_szWindowClass, szWindowClass);
      if (lstrlen(szTitle) > 0)
        lstrcpy(m_szTitle, szTitle);
      m_wIcon = wIcon;
      m_wSmallIcon = wSmallIcon;
      m_iWidth = iWidth;
      m_iHeight = iHeight;
      m_iFrameDelay = 50;   // 默认为20帧每秒(50ms/1000=20帧/秒) 
      m_bSleep = TRUE;
    }
    
    GameEngine::~GameEngine()
    {
    }
    
    //-----------------------------------------------------------------
    // Game Engine 常规方法 
    //-----------------------------------------------------------------
    //Initialize方法处理一些通常在WinMain()中执行的杂乱方法 
    BOOL GameEngine::Initialize(int iCmdShow)
    {
      WNDCLASSEX    wndclass;
    
      // 创建主窗口的窗口类 
      wndclass.cbSize         = sizeof(wndclass);
      wndclass.style          = CS_HREDRAW | CS_VREDRAW;
      wndclass.lpfnWndProc    = WndProc;
      wndclass.cbClsExtra     = 0;
      wndclass.cbWndExtra     = 0;
      wndclass.hInstance      = m_hInstance;
      wndclass.hIcon          = LoadIcon(m_hInstance,
        MAKEINTRESOURCE(GetIcon()));
      wndclass.hIconSm        = LoadIcon(m_hInstance,
        MAKEINTRESOURCE(GetSmallIcon()));
      wndclass.hCursor        = LoadCursor(NULL, IDC_ARROW);
      wndclass.hbrBackground  = (HBRUSH)(COLOR_WINDOW + 1);
      wndclass.lpszMenuName   = NULL;
      wndclass.lpszClassName  = m_szWindowClass;
    
      // 注册窗口类 
      if (!RegisterClassEx(&wndclass))
        return FALSE;
    
      /* 根据游戏大小计算窗口大小和位置 (这段代码允许确定实际游戏屏幕的确切大小,
      这个大小与整个应用程序窗口的大小不同) */
      int iWindowWidth = m_iWidth + GetSystemMetrics(SM_CXFIXEDFRAME) * 2,
          iWindowHeight = m_iHeight + GetSystemMetrics(SM_CYFIXEDFRAME) * 2 +
            GetSystemMetrics(SM_CYCAPTION);
      if (wndclass.lpszMenuName != NULL)
        iWindowHeight += GetSystemMetrics(SM_CYMENU);
      int iXWindowPos = (GetSystemMetrics(SM_CXSCREEN) - iWindowWidth) / 2,
          iYWindowPos = (GetSystemMetrics(SM_CYSCREEN) - iWindowHeight) / 2;
    
      // 创建窗口 
      m_hWindow = CreateWindow(m_szWindowClass, m_szTitle, WS_POPUPWINDOW |
        WS_CAPTION | WS_MINIMIZEBOX, iXWindowPos, iYWindowPos, iWindowWidth,
        iWindowHeight, NULL, NULL, m_hInstance, NULL);
      if (!m_hWindow)
        return FALSE;
    
      // 显示和更新窗口 
      ShowWindow(m_hWindow, iCmdShow);
      UpdateWindow(m_hWindow);
    
      return TRUE;
    }
    
    //接受并处理通常在WinProc()中处理的消息 
    LRESULT GameEngine::HandleEvent(HWND hWindow, UINT msg, WPARAM wParam, LPARAM lParam)
    {
      // 将Windows消息传递给游戏引擎成员函数 
      switch (msg)
      {
        case WM_CREATE:
          // 设置游戏窗口并开始游戏 
          SetWindow(hWindow);
          GameStart(hWindow);  //响应WM_CREATE消息,开始游戏 
          return 0;
    
        case WM_SETFOCUS:
          // 激活游戏并更新休眠状态 
          GameActivate(hWindow);
          SetSleep(FALSE);
          return 0;
    
        case WM_KILLFOCUS:
          // 停用游戏并更新休眠状态 
          GameDeactivate(hWindow);
          SetSleep(TRUE);
          return 0;
    
        case WM_PAINT:
          HDC         hDC;
          PAINTSTRUCT ps;
          hDC = BeginPaint(hWindow, &ps);
    
          // 绘制游戏 
          GamePaint(hDC);      //响应WM_PAINT消息,绘制游戏 
    
          EndPaint(hWindow, &ps);
          return 0;
    
        case WM_DESTROY:
          // 结束游戏并退出应用程序 
          GameEnd();
          PostQuitMessage(0);  //响应WM_DESTROY消息,结束游戏 
          return 0;
      }
      return DefWindowProc(hWindow, msg, wParam, lParam);
    }
    

    游戏引擎 解析

    游戏引擎是什么

    游戏引擎是指一些已编写好的可编辑电脑游戏系统或者一些交互式实时图像应用程序的核心组件。这些系统为游戏设计者提供各种编写游戏所需的各种工具,其目的在于让游戏设计者能容易和快速地做出游戏程序而不用由零开始。

    此处自行编写的游戏引擎包含两部分:GameEngine.h 和 GameEngine.cpp。

    下面给出两部分的结构图,方便理解。

    GameEngine.h 结构图

    这里写图片描述

    GameEngine.cpp 结构图

    这里写图片描述

    游戏事件函数

    将游戏分解为事件

    每一个Windows程序都可以分解为事件,即在程序运行时发生的事情,例如单击鼠标和更改窗口大小。正如Windows程序包含必须处理的事件一样,游戏也有其在开发过程中必须考虑的一组特有事件。可以将游戏的初始化过程视为一个事件,它负责加载游戏的图形和声音、清空游戏区域、将得分归零等。

    类似的,游戏中也有用户输入,意味着单击鼠标和按键操作是游戏必须自己处理的事件。此外还要牢记一点,在Windows中,可以最小化某些游戏或者将其置于后台,意味着可能希望暂停游戏。可以使用两个事件来表示这个激活和停用过程。

    许多事件当然都可以包括在游戏引擎中,但是下面这些事件适用于任何游戏的部分核心事件。

    • 初始化
    • 启动
    • 结束
    • 激活
    • 停用
    • 绘制
    • 循环

    初始化事件在一开始运行游戏时发生,这时游戏将执行重要的初始设置任务,包括创建游戏引擎本身。启动和结束事件对应于游戏的开始和结束,这时很适合执行与特定的游戏会话相关联的初始化和清理任务。

    在最小化游戏或者将其发送到后台,然后再恢复时,就将发生激活和停用事件。当游戏需要绘制自身时,将发送绘制事件,类似于Windows WM_PAINT消息,最后,循环事件使游戏执行一个单独的游戏周期。

    当游戏中发生一个事件时,就会调用相应的事件处理程序,使游戏有机会做相应的响应。下面列出了这些函数,它们直接对应于游戏事件。

    Bool GameInitialize(HINSTANCE hInstance); //初始化游戏
    void GameStart(HWND hWindow);             //启动游戏
    void GameEnd();                           //结束游戏
    void GameActivate(HWND hWindow);          //激活游戏
    void GameDeactivate(HWND hWindow);        //停用游戏
    void GamePaint(HDC hDC);                  //绘制游戏
    void GameCycle();                         //循环游戏

    HINSTANCE 数据类型

    第一个函数GameInitialize(),属于HINSTANCE类型的hInstance参数。

    H表示句柄,HINSTANCE对应的资源是instance。

    HINSTANCE数据类型应用程序实例的句柄,相当于装入到了内存的资源ID。它允许程序访问其资源(因为资源与应用程序一起存储在内存中)。句柄实际上是一个无符号长整数。

    应用程序实例实际上是已经加载到内存中并在Windows中运行的一个程序。如果使用过Alt+Tab组合键来切换Windows中正在运行的应用程序,那么就会很熟悉不同的应用程序实例。

    HWND 数据类型

    h 是类型描述,表示句柄(handle), Wnd 是变量对象描述,表示窗口,所以hWnd 表示窗口句柄

    Windows 运行环境,通过给应用程序中的每个窗体和控件分配一个句柄(或 hWnd)来标识它们。hWnd 属性用于Windows API调用。许多 Windows 运行环境函数需要活动窗口的 hWnd 作为参数。

    HDC 数据类型

    MFC中的设备上下文句柄,封装了用于绘制线条等的 Windows API。

    GameEngine类

    虽然在游戏事件处理程序与游戏引擎之间存在紧密的联系,但是实际上是独立的。因为就结构来说,将游戏引擎放在它自己的C++类中会更好。这个类名为GameEngine。

    class GameEngine
    {
    protected:
      //成员变量
      static GameEngine*  m_pGameEngine; //指向自身的静态指针,用于游戏程序的外部访问
      HINSTANCE           m_hInstance;           //应用程序实例句柄
      HWND                m_hWindow;             //主窗口句柄
      TCHAR               m_szWindowClass[32];   //窗口类的名称
      TCHAR               m_szTitle[32];         //主游戏窗口的名称
      WORD                m_wIcon, m_wSmallIcon; //游戏的两个程序图标的数字ID
      int                 m_iWidth, m_iHeight;   //游戏屏幕的宽度和高度
      int                 m_iFrameDelay;         //游戏周期之间的间隔,单位是ms
      BOOL                m_bSleep;              //表示游戏是否在休眠
    
    public:
      //构造函数和析构函数
    
      //游戏引擎构造函数使用默认的屏幕大小(640*480)创建游戏,这是实际的游戏区
              GameEngine(HINSTANCE hInstance, LPTSTR szWindowClass, LPTSTR szTitle,
                WORD wIcon, WORD wSmallIcon, int iWidth = 640, int iHeight = 480);
      virtual ~GameEngine();
    
      //常规方法
    
      //在引擎外部使用这个静态方法访问指向引擎的静态指针 
      static GameEngine*  GetEngine() 
      { 
             return m_pGameEngine; 
      };
      //创建引擎后,初始化游戏程序 
      BOOL                Initialize(int iCmdShow);
      //处理引擎内的标准Windows事件 
      LRESULT             HandleEvent(HWND hWindow, UINT msg, WPARAM wParam,
      LPARAM lParam);
    
      //访问方法
      HINSTANCE GetInstance() 
      { 
                return m_hInstance; 
      };
      HWND      GetWindow() 
      { 
                return m_hWindow; 
      };
      void      SetWindow(HWND hWindow) 
      { 
                m_hWindow = hWindow; 
      };
      LPTSTR    GetTitle() 
      { 
                return m_szTitle; 
      };
      WORD      GetIcon() 
      { 
                return m_wIcon; 
      };
      WORD      GetSmallIcon() 
      {
                 return m_wSmallIcon; 
      };
      int       GetWidth() 
      {
                 return m_iWidth; 
      };
      int       GetHeight() 
      { 
                return m_iHeight; 
      };
      int       GetFrameDelay() 
      { 
                return m_iFrameDelay; 
      };
      //指定帧速率,当值为30时会使游戏以30帧/秒的速率运行
      void      SetFrameRate(int iFrameRate) 
      { 
                m_iFrameDelay = 1000 /iFrameRate; 
      };
      BOOL      GetSleep() 
      { 
                return m_bSleep; 
      };
      void      SetSleep(BOOL bSleep) 
      { 
                m_bSleep = bSleep; 
      };
    };

    命名类的成员变量时使用m_开始,表示他们是类成员。此外,在命名全局变量时以g_开始,表示变量时全局的。

    以下对出现在代码中几个数据类型,做解释。具体的函数,将会在后面介绍。

    TCHAR 数据类型

    TCHAR是windows中定义的一个类型不是标准C中的,TCHAR是通过define定义的字符串宏。

    因为C++支持两种字符串,即常规的ANSI编码(使用”“包裹)和Unicode编码(使用L”“包裹),这样对应的就有了两套字符串处理函数,比如:strlen和wcslen,分别用于处理两种字符串。

    为了存储这样的通用字符,就有了TCHAR:
    当没有定义_UNICODE宏时,TCHAR = char,_tcslen =strlen
    当定义了_UNICODE宏时,TCHAR = wchar_t , _tcslen = wcslen

    WORD 数据类型

    不是C++标准的类型,是微软SDK中的类型,WORD的意思为字,是2byte的无符号整数,表示范围0~65535。

    LPTSTR 数据类型

    表示指向字符/字符串的指针

    LP:长指针(long pointer)。
    T:win32环境中有一个_T宏,用来标识字符是否采用Unicode编码(两字节表示一个字符),若程序中定义了Unicode,该字符/字符串被作为Unicode字符串,否则就是标准的ANSI(单字节表示一个字符)字符串。
    STR:表示这个变量是一个字符串。

    LRESULT 数据类型

    LRESULT就是long result,也就是长整型结果值,指的是从窗口程序或者回调函数返回的32位值

    UINT 数据类型

    UINT类型在WINDOWS API中有定义,它对应于32位无符号整数,代表消息名称

    WPARAM 数据类型

    WPARAM的实质是消息响应机制中的一个参数。例如对鼠标消息而言,WPARAM参数中包含了发生该消息时,SHIFT、CTRL等键的状态信息

    LPARAM 数据类型

    LPARAM的实质是消息响应机制中的一个参数。例如对鼠标消息而言,一般包含鼠标的位置信息。

    消息机制

    Windows中发生的一切都可以用消息来表示,消息用于告诉操作系统发生了什么,所有的Windows应用程序都是消息驱动的。

    一个消息是由消息的名称(UINT)和两个参数(WPARAM, LPARAM)组成。消息的参数中包含有重要的信息。例如对鼠标消息而言,LPARAM中一般包含鼠标的位置信息,而WPARAM参数中包含了发生该消息时,SHIFT、CTRL等键的状态信息,对于不同的消息类型来说,两个参数也都相应地具有明确意义。

    1、消息的组成:一个消息由一个消息名称(UINT),和两个参数(WPARAM,LPARAM)构成。当用户进行了输入或是窗口的状态发生改变时系统都会发送消息到某一个窗口。例如当菜单选中之后会有WM_COMMAND消息发送,WPARAM的高字中(HIWORD(wParam))是命令的ID号,对菜单来讲就是菜单ID。当然用户也可以定义自己的消息名称,也可以利用自定义消息来发送通知和传送数据。

    2、谁将收到消息一个消息必须由一个窗口接收。在窗口的过程(WNDPROC)中可以对消息进行分析,对自己感兴趣的消息进行处理。例如你希望对菜单选择进行处理那么你可以定义对WM_COMMAND进行处理的代码,如果希望在窗口中进行图形输出就必须对WM_PAINT进行处理。

    3、未处理的消息到那里去了:M$为窗口编写了默认的窗口过程,这个窗口过程将负责处理那些你不处理消息。正因为有了这个默认窗口过程我们才可以利用Windows的窗口进行开发而不必过多关注窗口各种消息的处理。例如窗口在被拖动时会有很多消息发送,而我们都可以不予理睬让系统自己去处理。

    4、窗口句柄:说到消息就不能不说窗口句柄,系统通过窗口句柄来在整个系统中唯一标识一个窗口,发送一个消息时必须指定一个窗口句柄表明该消息由那个窗口接收。而每个窗口都会有自己的窗口过程,所以用户的输入就会被正确的处理。例如有两个窗口共用一个窗口过程代码,你在窗口一上按下鼠标时消息就会通过窗口一的句柄被发送到窗口一而不是窗口二。

    5、示例:下面有一段伪代码演示如何在窗口过程中处理消息

    LONG yourWndProc(HWND hWnd,UINT uMessageType,WPARAM wP,LPARAM)
    {
    switch(uMessageType)
    {
    //使用SWITCH语句将各种消息分开
        case(WM_PAINT):
            doYourWindow(...);//在窗口需要重新绘制时进行输出
            break;
        case(WM_LBUTTONDOWN):
            doYourWork(...);//在鼠标左键被按下时进行处理
            break;
        default:
            callDefaultWndProc(...);//对于其它情况就让系统自己处理
            break;
    }
    }

    接下来谈谈什么是消息循环:系统将会维护一个或多个消息队列,所有产生的消息都会被放入或是插入队列中。系统会在队列中取出每一条消息,根据消息的接收句柄而将该消息发送给拥有该窗口的程序的消息循环。每一个运行的程序都有自己的消息循环,在循环中得到属于自己的消息并根据接收窗口的句柄调用相应的窗口过程。而在没有消息时消息循环就将控制权交给系统所以Windows可以同时进行多个任务。

    下面的伪代码演示了消息循环的用法

    while(1)
    {
        id=getMessage(...);
        if(id == quit)
            break;
        translateMessage(...);
    }

    当该程序没有消息通知时getMessage就不会返回,也就不会占用系统的CPU时间。

    WinMain( )

    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
      PSTR szCmdLine, int iCmdShow)
    {
      MSG         msg;
      static int  iTickTrigger = 0;
      int         iTickCount;
    
      if (GameInitialize(hInstance)) //通过调用GameInitialize()初始化游戏 
      {
        // 初始化游戏引擎 
        if (!GameEngine::GetEngine()->Initialize(iCmdShow))
          return FALSE;
    
        // 进入主消息循环 
        while (TRUE)
        {
          if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
          {
            //处理消息 
            if (msg.message == WM_QUIT)
              break;
            TranslateMessage(&msg);
            DispatchMessage(&msg);
          }
          else  //这段代码创建游戏的计时机制 
          {
            // 确保游戏引擎没有休眠 
            if (!GameEngine::GetEngine()->GetSleep())
            {
              // 检查滴答计数,查看是否过了一个游戏周期 
              iTickCount = GetTickCount();
              if (iTickCount > iTickTrigger)
              {
                iTickTrigger = iTickCount +
                  GameEngine::GetEngine()->GetFrameDelay();
                GameCycle();
              }
            }
          }
        }
        return (int)msg.wParam;
      }
    
      // 结束游戏 
      GameEnd();
    
      return TRUE;
    }

    WinMain是一个函数,该函数的功能是被系统调用,作为一个32位应用程序的入口点

    WinMain函数应初始化应用程序,显示主窗口,进入一个消息接收一发送循环,这个循环是应用程序执行的其余部分的顶级控制结构。

    虽然这个WinMain函数与所有Windows应用程序中的相似,但是存在一个重要的区别。这个区别就是,这个WinMain函数创建了一个游戏循环,处理以指定的时间间隔生成游戏周期事件的任务。

    Windows程序中最小事件单元是滴答(Tick),它相当于1ms,对执行精确的计时任务很有用。在这里,WinMain以滴答计数,以便确定应该何时通知游戏开始一个新的周期。iTickTrigger和iTickCount变量用来创建WinMain中的游戏循环计时机制。

    在WinMain中调用的第一个函数是GameInitialize( ),它初始化游戏。GameInitialize( )是一个游戏事件函数,属于这个游戏的专用代码,因此它不是游戏引擎的直接组成部分。属于游戏引擎部分的方法是Initialize( ),调用它来初始化游戏引擎本身。

    WINAPI 数据类型

    该WinMain函数,返回的是WINAPI,即视窗操作系统应用程序接口,是微软对于Windows操作系统中可用的内核应用程序编程接口的称法。它设计为由C/C++程序调用,而且它也是应用软件与Windows系统最直接的交互方式。

    PSTR 数据类型

    PSTR的字面意思是指向字符串的指针,但是由于32位的普及,从Visual C++ 6.0开始它们完全相同,没有任何区别,只是由于习惯大家还分别在不同的地方使用它们。
    即:LPSTR=PSTR=char *(完全等同)

    对WinMain函数参数的分析

    HINSTANCE hInstance:应用程序当前实例的句柄

    HINSTANCE hPrevInstance:应用程序的先前实例的句柄。对于同一个程序打开两次,出现两个窗口第一次打开的窗口就是先前实例的窗口。对于一个32位程序,该参数总为NULL。

    PSTR szCmdLine:指向应用程序命令行的字符串的指针,不包括执行文件名。

    例如:在D盘下有一个sunxin.txt文件,当我们用鼠标双击这个文件时将启动记事本程序(notepad.exe),此时系统会将D:\sunxin.txt作为命令行参数传递给记事本程序的WinMain函数,记事本程序在得到这个文件的全路径名后,就在窗口中显示该文件的内容。

    int iCmdShow:指明窗口如何显示。

    该参数可以是下列值之一:

    SW_HIDE:隐藏窗口并且激活另外一个窗口。
    SW_MINIMIZE:最小化指定的窗口,并且激活在系统表中的顶层窗口。
    SW_RESTORE:激活并显示窗口。如果窗口已经最小化或最大化,系统将以恢复到原来的尺寸和位置显示窗口(与SW_SHOWNORMAL相同)。
    SW_SHOW:激活一个窗口并以原来的尺寸和位置显示窗口。
    SW_SHOWMAXIMIZED:激活窗口并且将其最大化。
    SW_SHOWMINIMIZED:激活窗口并将其最小化(以图标显示)。
    SW_SHOWMINNOACTIVE:将一个窗口显示为图标。激活窗口维持活动状态。
    SW_SHOWNA:以窗口的当前状态显示窗口。激活窗口保持活动状态。
    SW_SHOWNOACTIVATE:以窗口的最近一次的尺寸和位置显示窗口。不激活窗口。
    SW_SHOWNORMAL:激活并显示窗口。如果窗口最大化或最小化,系统将其恢复到原来的尺寸和位置(与SW_RESTORE相同)。

    如果函数成功,当它接收到一个WM_QUIT消息时就中止,函数应该返回在该消息的wParam参数的退出值(指定消息的附加值)。如果函数在进入消息循环前退出,应该返回零。

    MSG 数据类型

    MSG是Windows程序中的结构体

    在Windows程序中,消息是由MSG结构体来表示的。MSG结构体的定义如下

    typedef struct tagMSG {
        HWND hwnd;
        UINT message;
        WPARAM wParam;
        LPARAM lParam;
        DWORD time;
        POINT pt;
    } MSG;

    该结构体中各成员变量的含义如下:

    第一个成员变量hwnd是窗口句柄,表示消息所属的窗口。我们通常开发的程序都是窗口应用程序,一个消息一般都是与某个窗口相关联的。例如,在某个活动窗口中按下鼠标左键,产生的按键消息就是发给该窗口的。在Windows程序中,用HWND类型的变量来标识窗口。

    第二个成员变量message指定了消息的标识符(消息名称),UINT型为32位无符号整数类型在Windows中,消息是由一个数值来表示的,不同的消息对应不同的数值。但是由于数值不便于记忆,所以Windows将消息对应的数值定义为WM_XXX宏(WM是Window Message的缩写)的形式,XXX对应某种消息的英文拼写的大写形式。例如,鼠标左键按下消息是WM_LBUTTONDOWN,键盘按下消息是WM_KEYDOWN,字符消息是WM_CHAR,等等。在程序中我们通常都是以WM_XXX宏的形式来使用消息的。

    提示:如果想知道WM_XXX消息对应的具体数值,可以在Visual C++开发环境中选中WM_XXX,然后单击鼠标右键,在弹出菜单中选择goto definition,即可看到该宏的具体定义。跟踪或查看某个变量的定义,都可以使用这个方法。

    第三、第四个成员变量wParam和lParam,用于指定消息的附加信息。例如,当我们收到一个字符消息的时候,message成员变量的值就是WM_CHAR,但用户到底输入的是什么字符,那么就由wParam和lParam来说明。wParam、lParam表示的信息随消息的不同而不同。如果想知道这两个成员变量具体表示的信息,可以在MSDN中关于某个具体消息的说明文档查看到。读者可以在VC++的开发环境中通过goto definition查看一下WPARAM和LPARAM这两种类型的定义,可以发现这两种类型实际上就是unsigned int和long。

    最后两个变量分别表示消息投递到消息队列中的时间和鼠标的当前位置。

    PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)

    PeekMessage是一个Windows API函数。该函数为一个消息检查 线程消息队列,并将该消息(如果存在)放于指定的结构。

    函数原型为:

    BOOL PeekMessage(
        LPMSG IpMsg,
        HWND hWnd,
        UINT wMSGfilterMin,
        UINT wMsgFilterMax,
        UINT wRemoveMsg
    );

    lpMsg:接收消息信息的MSG结构指针。

    hWnd:其消息被检查的窗口句柄。

    wMsgFilterMin:指定被检查的消息范围里的第一个消息。

    wMsgFilterMax:指定被检查的消息范围里的最后一个消息。

    wRemoveMsg:确定消息如何被处理。

    此参数可取下列值之一:

    PM_NOREMOVE PeekMessage处理后,消息不从队列里除掉。

    PM_REMOVE PeekMessage处理后,消息从队列里除掉。

    PM_NOYIELD 此标志使系统不释放等待调用程序空闲的线程。可将PM_NOYIELD随意组合到PM_NOREMOVE或PM_REMOVE。

    TranslateMessage(&msg);

    TranslateMessage函数用于将虚拟键消息转换为字符消息。

    函数原型

    BOOL TranslateMessage( CONST MSG*lpMsg );

    IpMsg:指向含有消息的MSG结构的指针。

    返回值:如果消息被转换(即,字符消息被寄送到调用线程的消息队列里),返回非零值。

    如果消息是WM_KEYDOWN,WM_KEYUP WM_SYSKEYDOWN或WM_SYSKEYUP,返回非零值,不考虑转换。

    如果消息没被转换(即,字符消息没被寄送到调用线程的消息队列里),返回值是零。

    DispatchMessage(&msg);

    该函数分发一个消息给窗口程序。

    函数原型

    LONG DispatchMessage(CONST MSG*lpmsg);

    参数
    lpmsg:指向含有消息的MSG结构的指针。

    返回值:返回值是窗口程序返回的值。尽管返回值的含义依赖于被调度的消息,但返回值通常被忽略。

    GetTickCount( )

    GetTickCount返回从操作系统启动所经过的毫秒数,它的返回值是DWORD。

    WndProc( )

    LRESULT CALLBACK WndProc(HWND hWindow, UINT msg, WPARAM wParam, LPARAM lParam)
    {
      // 将所有Windows消息传递给游戏引擎 
      return GameEngine::GetEngine()->HandleEvent(hWindow, msg, wParam, lParam);
    }

    Windows是消息驱动的。所以消息将发往窗口中,而在窗口的过程(WNDPROC)中可以对消息进行分析,对自己感兴趣的消息进行处理。

    WndProc所做的事情实际上就是将所有消息都传递给HandleEvent。这乍看起来是浪费时间。不过,思路是允许GameEngine类的方法处理消息。这样就可以使用一种与游戏引擎一致的方法处理它们。

    GameEngine::GameEngine( )

    GameEngine::GameEngine(HINSTANCE hInstance, LPTSTR szWindowClass,
      LPTSTR szTitle, WORD wIcon, WORD wSmallIcon, int iWidth, int iHeight)
    {
      // 设置游戏引擎的成员变量 
      m_pGameEngine = this;
      m_hInstance = hInstance;
      m_hWindow = NULL;
      if (lstrlen(szWindowClass) > 0)
        lstrcpy(m_szWindowClass, szWindowClass);
      if (lstrlen(szTitle) > 0)
        lstrcpy(m_szTitle, szTitle);
      m_wIcon = wIcon;
      m_wSmallIcon = wSmallIcon;
      m_iWidth = iWidth;
      m_iHeight = iHeight;
      m_iFrameDelay = 50;   // 默认为20帧每秒(50ms/1000=20帧/秒) 
      m_bSleep = TRUE;
    }

    GameEngine::GameEngine( )构造函数负责初始化游戏引擎成员变量。

    GameEngine::~GameEngine( )

    GameEngine::~GameEngine()
    {
    }

    析构函数保持为空,以备将来使用。

    GameEngine::Initialize( )

    BOOL GameEngine::Initialize(int iCmdShow)
    {
      WNDCLASSEX    wndclass;
    
      // 创建主窗口的窗口类 
      wndclass.cbSize         = sizeof(wndclass);
      wndclass.style          = CS_HREDRAW | CS_VREDRAW;
      wndclass.lpfnWndProc    = WndProc;
      wndclass.cbClsExtra     = 0;
      wndclass.cbWndExtra     = 0;
      wndclass.hInstance      = m_hInstance;
      wndclass.hIcon          = LoadIcon(m_hInstance,
        MAKEINTRESOURCE(GetIcon()));
      wndclass.hIconSm        = LoadIcon(m_hInstance,
        MAKEINTRESOURCE(GetSmallIcon()));
      wndclass.hCursor        = LoadCursor(NULL, IDC_ARROW);
      wndclass.hbrBackground  = (HBRUSH)(COLOR_WINDOW + 1);
      wndclass.lpszMenuName   = NULL;
      wndclass.lpszClassName  = m_szWindowClass;
    
      // 注册窗口类 
      if (!RegisterClassEx(&wndclass))
        return FALSE;
    
      /* 根据游戏大小计算窗口大小和位置 (这段代码允许确定实际游戏屏幕的确切大小,
      这个大小与整个应用程序窗口的大小不同) */
      int iWindowWidth = m_iWidth + GetSystemMetrics(SM_CXFIXEDFRAME) * 2,
          iWindowHeight = m_iHeight + GetSystemMetrics(SM_CYFIXEDFRAME) * 2 +
            GetSystemMetrics(SM_CYCAPTION);
      if (wndclass.lpszMenuName != NULL)
        iWindowHeight += GetSystemMetrics(SM_CYMENU);
      int iXWindowPos = (GetSystemMetrics(SM_CXSCREEN) - iWindowWidth) / 2,
          iYWindowPos = (GetSystemMetrics(SM_CYSCREEN) - iWindowHeight) / 2;
    
      // 创建窗口 
      m_hWindow = CreateWindow(m_szWindowClass, m_szTitle, WS_POPUPWINDOW |
        WS_CAPTION | WS_MINIMIZEBOX, iXWindowPos, iYWindowPos, iWindowWidth,
        iWindowHeight, NULL, NULL, m_hInstance, NULL);
      if (!m_hWindow)
        return FALSE;
    
      // 显示和更新窗口 
      ShowWindow(m_hWindow, iCmdShow);
      UpdateWindow(m_hWindow);
    
      return TRUE;
    }

    GameEngine类中的Initialize( )方法用来初始化游戏引擎。更具体的说,Initialize( )方法现在执行大量杂乱的Windows设置任务,例如为主游戏窗口创建一个窗口类,然后从这个类中创建一个窗口。

    用来描述主窗口的窗口样式是WS_POPUPWINDOW、WS_CAPTION和WS_MINIMIZEBOX,这将生成一个大小不可调整、无法最大化的窗口。不过,它包含一个菜单,并且可以最小化。

    传入的参数是:int iCmdShow:指明窗口如何显示。

    该参数可以是下列值之一:
    SW_HIDE:隐藏窗口并且激活另外一个窗口。
    SW_MINIMIZE:最小化指定的窗口,并且激活在系统表中的顶层窗口。
    SW_RESTORE:激活并显示窗口。如果窗口已经最小化或最大化,系统将以恢复到原来的尺寸和位置显示窗口(与SW_SHOWNORMAL相同)。
    SW_SHOW:激活一个窗口并以原来的尺寸和位置显示窗口。
    SW_SHOWMAXIMIZED:激活窗口并且将其最大化。
    SW_SHOWMINIMIZED:激活窗口并将其最小化(以图标显示)。
    SW_SHOWMINNOACTIVE:将一个窗口显示为图标。激活窗口维持活动状态。
    SW_SHOWNA:以窗口的当前状态显示窗口。激活窗口保持活动状态。
    SW_SHOWNOACTIVATE:以窗口的最近一次的尺寸和位置显示窗口。不激活窗口。
    SW_SHOWNORMAL:激活并显示窗口。如果窗口最大化或最小化,系统将其恢复到原来的尺寸和位置(与SW_RESTORE相同)。

    WNDCLASSEX 数据类型

    WNDCLASSEX属于一个窗台类,WNDCLASSEX 结构用于注册窗口类。

    结构体原型

    typedef struct WNDCLASSEX {
        UINT cbSize;
        UINT style;
        WNDPROC lpfnWndProc;
        int cbClsExtra;
        int cbWndExtra;
        HINSTANCE hInstance;
        HICON hIcon;
        HCURSOR hCursor;
        HBRUSH hbrBackground;
        LPCTSTR lpszMenuName;
        LPCTSTR lpszClassName;
        HICON hIconSm;
    } WNDCLASSEX, *PWNDCLASSEX;

    参数解析

    cbSize
    WNDCLASSEX 的大小。我们可以用sizeof(WNDCLASSEX)来获得准确的值。

    style
    从这个窗口类派生的窗口具有的风格。您可以用“or”操作符来把几个风格或到一起。

    lpfnWndProc
    窗口处理函数的指针。

    cbClsExtra
    指定紧跟在窗口类结构后的附加字节数。

    cbWndExtra
    指定紧跟在窗口实例的附加字节数。如果一个应用程序在资源中用CLASS伪指令注册一个对话框类时,则必须把这个成员设成DLGWINDOWEXTRA。

    hInstance
    本模块的实例句柄。

    hIcon
    图标的句柄。

    hCursor
    光标的句柄。

    hbrBackground
    背景画刷的句柄。

    lpszMenuName
    指向菜单的指针。

    lpszClassName
    指向类名称的指针。

    hIconSm
    和窗口类关联的小图标。如果该值为NULL。则把hIcon中的图标转换成大小合适的小图标。

    GetSystemMetrics( )

    GetSystemMetrics( )用于得到被定义的系统数据或者系统配置信息。

    函数原型

    int WINAPI GetSystemMetrics( __in intnIndex);

    函数参数nIndex的定义

    SM_ARRANGE 标志用于说明系统如何安排最小化窗口。

    SM_CXFIXEDFRAME,SM_CYFIXEDFRAME:围绕具有标题但无法改变尺寸的窗口(通常是一些对话框)的边框的厚度

    SM_CYCAPTION:以像素计算的普通窗口标题的高度

    SM_CYMENU:以像素计算的单个菜单条的高度

    SM_CXSCREEN,SM_CYSCREEN: 以像素为单位计算的屏幕尺寸。

    CreateWindow( )

    Windows API函数,创建窗口。

    函数原型

    HWND CreateWindow(
        LPCTSTR lpClassName,
        LPCTSTR lpWindowName,
        DWORD dwStyle,
        int x,
        int y,
        int nWidth,
        int nHeight,
        HWND hWndParent,
        HMENU hMenu,
        HANDLE hlnstance,
        LPVOID lpParam);

    参数详情

    lpClassName
    指向一个空结束的字符串或整型数atom。

    如果该参数是一个整型量,它是由此前调用theGlobalAddAtom函数产生的全局量。这个小于0xC000的16位数必须是lpClassName参数字的低16位,该参数的高位必须是0。

    如果lpClassName是一个字符串,它指定了窗口的类名。这个类名可以是任何用函数RegisterClass注册的类名,或是任何预定义的控制类名。请看说明部分的列表。

    LPWindowName
    指向一个指定窗口名的空结束的字符串指针。

    如果窗口风格指定了标题条,由lpWindowName指向的窗口标题将显示在标题条上。当使用Createwindow函数来创建控制例如按钮,选择框和静态控制时,可使用lpWindowName来指定控制文本。

    dwStyle
    指定创建窗口的风格。该参数可以是下列窗口风格的组合再加上说明部分的控制风格。

    风格意义
    WS_BORDER:创建一个带边框的窗口。

    WS_CAPTION:创建一个有标题框的窗口(包括WS_BORDER风格)。

    WS_CHILD:创建一个子窗口。这个风格不能与WS_POPUP风格合用。

    WS_CHILDWINDOW:与WS_CHILD相同。

    WS_CLIPCHILDREN:当在父窗口内绘图时,排除子窗口区域。在创建父窗口时使用这个风格。

    WS_CLIPSIBLINGS:排除子窗口之间的相对区域,也就是,当一个特定的窗口接收到WM_PAINT消息时,WS_CLIPSIBLINGS 风格将所有层叠窗口排除在绘图之外,只重绘指定的子窗口。如果未指定

    WS_CLIPSIBLINGS风格,并且子窗口是层叠的,则在重绘子窗口的客户区时,就会重绘邻近的子窗口。

    WS_DISABLED:创建一个初始状态为禁止的子窗口。一个禁止状态的窗口不能接受来自用户的输入信息。

    WS_DLGFRAME:创建一个带对话框边框风格的窗口。这种风格的窗口不能带标题条。

    WS_GROUP:指定一组控制的第一个控制。这个控制组由第一个控制和随后定义的控制组成,自第二个控制开始每个控制,具有WS_GROUP风格,每个组的第一个控制带有WS_TABSTOP风格,从而使用户可以在组间移动。用户随后可以使用光标在组内的控制间改变键盘焦点。

    WS_HSCROLL:创建一个有水平滚动条的窗口。

    WS_ICONIC:创建一个初始状态为最小化状态的窗口。与

    WS_MINIMIZE风格相同。

    WS_MAXIMIZE:创建一个初始状态为最大化状态的窗口。

    WS_MAXIMIZEBOX:创建一个具有最大化按钮的窗口。该风格不能与

    WS_EX_CONTEXTHELP风格同时出现,同时必须指定WS_SYSMENU风格。

    WS_OVERLAPPED:产生一个层叠的窗口。一个层叠的窗口有一个标题条和一个边框。与WS_TILED风格相同。

    WS_OVERLAPPEDWINDOW:创建一个具有WS_OVERLAPPED,

    WS_CAPTION,WS_SYSMENU WS_THICKFRAME,

    WS_MINIMIZEBOX,WS_MAXIMIZEBOX风格的层叠窗口,与

    WS_TILEDWINDOW风格相同。

    WS_POPUP:创建一个弹出式窗口。该风格不能与WS_CHILD风格同时使用。

    WS_POPUPWINDOW:创建一个具有WS_BORDER,

    WS_POPUP,WS_SYSMENU风格的窗口,WS_CAPTION和

    WS_POPUPWINDOW必须同时设定才能使窗口某单可见。

    WS_SIZEBOX:创建一个可调边框的窗口,与WS_THICKFRAME风格相同。

    WS_SYSMENU:创建一个在标题条上带有窗口菜单的窗口,必须同时设定WS_CAPTION风格。

    WS_TABSTOP:创建一个控制,这个控制在用户按下Tab键时可以获得键盘焦点。按下Tab键后使键盘焦点转移到下一具有WS_TABSTOP风格的控制。

    WS_THICKFRAME:创建一个具有可调边框的窗口,与WS_SIZEBOX风格相同。

    WS_TILED:产生一个层叠的窗口。一个层叠的窗口有一个标题和一个边框。与WS_OVERLAPPED风格相同。

    WS_TILEDWINDOW:创建一个具有WS_OVERLAPPED,

    WS_CAPTION,WS_SYSMENU, WS_THICKFRAME,

    WS_MINIMIZEBOX,WS_MAXIMIZEBOX风格的层叠窗口。与

    WS_OVERLAPPEDWINDOW风格相同。

    WS_VISIBLE:创建一个初始状态为可见的窗口。

    WS_VSCROLL:创建一个有垂直滚动条的窗口。

    X
    指定窗口的初始水平位置。对一个层叠或弹出式窗口,X参数是屏幕坐标系的窗口的左上角的初始X坐标。

    对于子窗口,x是子窗口左上角相对父窗口客户区左上角的初始X坐标。如果该参数被设为CW_USEDEFAULT则系统为窗口选择缺省的左上角坐标并忽略Y参数。CW_USEDEFAULT只对层叠窗口有效,如果为弹出式窗口或子窗口设定,则X和y参数被设为零。

    Y
    指定窗口的初始垂直位置。对一个层叠或弹出式窗口,y参数是屏幕坐标系的窗口的左上角的初始y坐标。

    对于子窗口,y是子窗口左上角相对父窗口客户区左上角的初始y坐标。对于列表框,y是列表框客户区左上角相对父窗口客户区左上角的初始y坐标。如果层叠窗口是使用WS_VISIBLE风格位创建的并且X参数被设为CW_USEDEFAULT,则系统将忽略y参数。

    nWidth
    以设备单元指明窗口的宽度。对于层叠窗口,nWidth或是屏幕坐标的窗口宽度或是CW_USEDEFAULT。若nWidth是CW_USEDEFAULT,则系统为窗口选择一个缺省的高度和宽度:缺省宽度为从初始X坐标开始到屏幕的右边界,缺省高度为从初始Y坐标开始到目标区域的顶部。

    CW_USEDEFAULT只对层叠窗口有效;如果为弹出式窗口和子窗口设定CW_USEDEFAULT标志则nWidth和nHeight被设为零。

    nHeight
    以设备单元指明窗口的高度。对于层叠窗口,nHeight是屏幕坐标的窗口宽度。若nWidth被设为CW_USEDEFAULT,则系统忽略nHeight参数。

    hWndParent
    指向被创建窗口的父窗口或所有者窗口的句柄。若要创建一个子窗口或一个被属窗口,需提供一个有效的窗口句柄。这个参数对弹出式窗口是可选的。Windows NT 5.0;创建一个消息窗口,可以提供HWND_MESSAGE或提供一个己存在的消息窗口的句柄。

    hMenu
    菜单句柄,或依据窗口风格指明一个子窗口标识。对于层叠或弹出式窗口,hMenu指定窗口使用的菜单:如果使用了菜单类,则hMenu可以为NULL。对于子窗口,hMenu指定了该子窗口标识(一个整型量),一个对话框使用这个整型值将事件通知父类。应用程序确定子窗口标识,这个值对于相同父窗口的所有子窗口必须是唯一的。

    hlnstance:与窗口相关联的模块实例的句柄。

    lpParam
    指向一个值的指针,该值传递给窗口WM_CREATE消息。该值通过在IParam参数中的CREATESTRUCT结构传递。如果应用程序调用CreateWindow创建一个MDI客户窗口,则lpParam必须指向一个CLIENTCREATESTRUCT结构。

    返回值:如果函数成功,返回值为新窗口的句柄:如果函数失败,返回值为NULL。若想获得更多错误信息,请调用GetLastError函数。[1]

    ShowWindow( )

    该函数设置指定窗口的显示状态。

    函数原型

    BOOL ShowWindow(HWND hWnd, int nCmdShow);

    参数详解

    hWnd:指窗口句柄。

    nCmdShow:指定窗口如何显示。
    如果发送应用程序的程序提供了STARTUPINFO结构,则应用程序第一次调用ShowWindow时该参数被忽略。否则,在第一次调用ShowWindow函数时,该值应为在函数WinMain中nCmdShow参数。

    在随后的调用中,该参数可以为下列值之一:
    SW_FORCEMINIMIZE:在WindowNT5.0中最小化窗口,即使拥有窗口的线程被挂起也会最小化。在从其他线程最小化窗口时才使用这个参数。nCmdShow=11。

    SW_HIDE:隐藏窗口并激活其他窗口。nCmdShow=0。

    SW_MAXIMIZE:最大化指定的窗口。nCmdShow=3。

    SW_MINIMIZE:最小化指定的窗口并且激活在Z序中的下一个顶层窗口。nCmdShow=6。

    SW_RESTORE:激活并显示窗口。如果窗口最小化或最大化,则系统将窗口恢复到原来的尺寸和位置。在恢复最小化窗口时,应用程序应该指定这个标志。nCmdShow=9。

    SW_SHOW:在窗口原来的位置以原来的尺寸激活和显示窗口。nCmdShow=5。

    SW_SHOWDEFAULT:依据在STARTUPINFO结构中指定的SW_FLAG标志设定显示状态,STARTUPINFO 结构是由启动应用程序的程序传递给CreateProcess函数的。nCmdShow=10。

    SW_SHOWMAXIMIZED:激活窗口并将其最大化。nCmdShow=3。

    SW_SHOWMINIMIZED:激活窗口并将其最小化。nCmdShow=2。

    SW_SHOWMINNOACTIVE:窗口最小化,激活窗口仍然维持激活状态。nCmdShow=7。

    SW_SHOWNA:以窗口原来的状态显示窗口。激活窗口仍然维持激活状态。nCmdShow=8。

    SW_SHOWNOACTIVATE:以窗口最近一次的大小和状态显示窗口。激活窗口仍然维持激活状态。nCmdShow=4。

    SW_SHOWNORMAL:激活并显示一个窗口。如果窗口被最小化或最大化,系统将其恢复到原来的尺寸和大小。应用程序在第一次显示窗口的时候应该指定此标志。nCmdShow=1。

    UpdateWindow( )

    更新指定窗口的客户区。

    功能:如果窗口更新的区域不为空,UpdateWindow函数就发送一个WM_PAINT消息来更新指定窗口的客户区。函数绕过应用程序的消息队列,直接发送WM_PAINT消息给指定窗口的窗口过程,如果更新区域为空,则不发送消息。

    函数原型

    BOOL UpdateWindow(
        HWND hWnd // 窗口的句柄
    );

    参数详解:
    hWnd:要更新的窗口的句柄.

    GameEngine::HandleEvent( )

    LRESULT GameEngine::HandleEvent(HWND hWindow, UINT msg, WPARAM wParam, LPARAM lParam)
    {
      // 将Windows消息传递给游戏引擎成员函数 
      switch (msg)
      {
        case WM_CREATE:
          // 设置游戏窗口并开始游戏 
          SetWindow(hWindow);
          GameStart(hWindow);  //响应WM_CREATE消息,开始游戏 
          return 0;
    
        case WM_SETFOCUS:
          // 激活游戏并更新休眠状态 
          GameActivate(hWindow);
          SetSleep(FALSE);
          return 0;
    
        case WM_KILLFOCUS:
          // 停用游戏并更新休眠状态 
          GameDeactivate(hWindow);
          SetSleep(TRUE);
          return 0;
    
        case WM_PAINT:
          HDC         hDC;
          PAINTSTRUCT ps;
          hDC = BeginPaint(hWindow, &ps);
    
          // 绘制游戏 
          GamePaint(hDC);      //响应WM_PAINT消息,绘制游戏 
    
          EndPaint(hWindow, &ps);
          return 0;
    
        case WM_DESTROY:
          // 结束游戏并退出应用程序 
          GameEnd();
          PostQuitMessage(0);  //响应WM_DESTROY消息,结束游戏 
          return 0;
      }
      return DefWindowProc(hWindow, msg, wParam, lParam);
    }

    HandleEvent( )方法包含了一个switch语句,它获得Windows消息并单独响应他们。HandleEvent( )方法也调用游戏引擎函数。

    首先处理每次初次创建主游戏窗口时发送的WM_CREATE消息。这个消息的处理程序代码设置游戏引擎中的窗口句柄,然后调用GameStart( )游戏事件函数来初始化游戏。

    WM_SETFOCUSWM_KILLFOCUS消息分别通知游戏,它的游戏窗口接受(激活)或失去(停用)了输入焦点。如果游戏被激活(获得焦点),则调用GameActivate( )函数,唤醒游戏,如果游戏窗口被停用(失去焦点),则调用GameDeactivate( )函数,使游戏休眠。

    HandleEvent( )方法中其余的消息相当简单,它们主要调用游戏函数。WM_PAINT消息处理程序调用标准的Win32 BeginPaint( )函数,然后调用GamePaint( )函数,最后调用EndPaint( )函数来结束绘制过程。最后,WM_DESTROY处理程序调用GameEnd( )函数,然后终止整个程序。

    PAINTSTRUCT 数据类型

    用于绘制窗口客户区的信息的结构体。

    结构体定义:

    typedef struct tagPAINTSTRUCT {
    HDC hdc;
    BOOL fErase;
    RECT rcPaint;
    BOOL fRestore;
    BOOL fIncUpdate;
    BYTE rgbReserved[32];
    } PAINTSTRUCT, *PPAINTSTRUCT;

    参数解释

    BeginPaint可以得到客户区设备描述表的句柄,GetDC也可以得到,MFC里的CClientDC与之对应。

    hdc是用于绘制的句柄,

    fErase如果为非零值则擦除背景,否则不擦除背景,

    rcPaint 通过制定左上角和右下角的坐标确定一个要绘制的矩形范围,该矩形单位相对于客户区左上角,

    后面三个参数都是系统预留的,编程一般用不到。

    BeginPaint(hWindow, &ps)

    BeginPaint函数为指定窗口进行绘图工作的准备,并用将和绘图有关的信息填充到一个PAINTSTRUCT结构中。

    函数原型

    HDC BeginPaint(
        HWND hwnd, // 窗口的句柄
        LPPAINTSTRUCT lpPaint // 绘制信息
    );

    参数解释

    hwnd:[输入]被重绘的窗口句柄

    lpPaint:[输出]指向一个用来接收绘画信息的PAINTSTRUCT结构

    EndPaint(hWindow, &ps);

    EndPaint函数标记指定窗口的绘画过程结束;这个函数在每次调用BeginPaint函数之后被请求,但仅仅在绘画完成以后。

    函数原型

    BOOL EndPaint(
    HWND hWnd, // 窗口句柄
    CONST PAINTSTRUCT *lpPaint // 绘制窗口的数据
    );

    参数解释

    hWnd:[输入]已经被重画的窗口的HANDLE

    lpPaint:[输入]指向一个PAINTSTRUCT结构,该结构包含了绘画信息,是BeginPaint函数返回的返回值:

    PostQuitMessage(0);

    该函数向系统表明有个线程有终止请求。通常用来响应WM_DESTROY消息,指定应用程序退出代码。

    void PostQuitMessage(int nExitCode)

    参数:nExitCode:指定应用程序退出代码。此值被用作消息WM_QUIT的
    wParam参数。

    返回值:无。

    DefWindowProc(hWindow, msg, wParam, lParam);

    DefWindowProc函数调用缺省的窗口过程来为应用程序没有处理的任何窗口消息提供缺省的处理。该函数确保每一个消息得到处理。

    函数功能:该调用DefWindowProc函数时使用窗口过程接收的相同参数。

    函数原型

    LRESULT DefWindowProc(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM IParam);

    用引擎开发Blizzard雪花小游戏

    说一下VC 6++中新建文件的问题。其他的IDE,一般右键文件夹,即可选择添加不同的文件至文件中。

    而VC 6++要点击菜单栏的文件->新建,然后选添加至工程就行了。

    说下资源脚本的问题。

    新建 资源脚本Resource script .rs文件

    资源脚本,它是一个简单的文本文件,可以手工编辑,也可以让Visual C++自动编辑,或者你用其它的自动编辑器编辑。无论如何,资源脚本文件要有一个.rc的扩展名。

    点击菜单栏的文件->新建->选中资源脚本

    这里写图片描述

    成功创建,出现如下界面

    这里写图片描述

    右击Blizzard.rc文件夹。

    这里写图片描述

    点击插入即可新建新的位图文件进资源脚本中。因为该游戏中,我们已有自己的位图文件,所以我们点击引入。找到自己的位图文件后,选中,点击引入按钮。

    这里写图片描述

    引入成功后,即可看见位图文件被导入至资源脚本中。

    这里写图片描述

    接下来,我们要对位图文件,进行改名。右击位图文件,选择属性。

    这里写图片描述

    在ID处改名,改完右击回车即可。另一个位图文件也按照相同操作,ID名则改成IDI_BLIZZARD_SM。

    这里写图片描述

    至此,资源脚本设置好了。当创建资源脚本时,VC会自动帮我们创建一个resource.h头文件,并且Blizzard.rc资源脚本与resource.h头文件相关联,即Blizzard.rc中include

    Blizzard 目录结构和效果图

    给一张项目最后的目录。

    这里写图片描述

    效果图:(其实就是雪花不停的从窗口各个地方出现)

    这里写图片描述

    Blizzard 源代码

    该Blizzard雪花游戏除了使用游戏引擎文件GameEngine.cpp 和 GameEngine.h以外。

    还有它独有的Blizzard.cpp 和 Blizzard.h 和 资源脚本Blizzard.rc以及自动创建的resource.h。

    资源脚本Blizzard.rc的创建,上面已经介绍过了。接下来将贴其他几个代码,而代码解析则放在后面。

    resource.h 源代码

    resource.h 头文件可以算是一个帮助器文件,它定义了在程序中使用的所有资源的标识符。在这个例子中,唯一的资源是两个不同大小(16*16,32*32)的图标。

    resource.h头文件声明了Blizzard示例中使用的图标的标识符。

    资源通常使用某个特定范围内的数字,这样就更容易相互区分并有助于确保它们具有唯一的值。

    //-----------------------------------------------------------------
    // Icons                    Range : 1000 - 1999
    //-----------------------------------------------------------------
    #define IDI_BLIZZARD        1000
    #define IDI_BLIZZARD_SM     1001
    

    Blizzard.h 源代码

    Blizzard.h头文件只是导入几个头文件并声明重要的全局游戏引擎指针。

    #pragma once
    
    #include<windows.h>
    #include "Resource.h"
    #include "GameEngine.h"
    
    //全局变量
    GameEngine* g_pGame;   //每一个基于游戏引擎的游戏都需要一个全局游戏引擎指针

    Blizzard.cpp 源代码

    主要的Blizzard程序位于Blizzard.cpp源代码中,在Blizzard.cpp中我们定义了游戏事件函数。

    Blizzard.cpp源代码文件揭示了在使用游戏引擎时,一个小型Windows程序(游戏)的程序代码变得多么简单,只需要定义属于该游戏的游戏事件函数,而不必管与Windows有关的API。

    //-----------------------------------------------------------------
    // Blizzard 应用程序
    //-----------------------------------------------------------------
    
    //-----------------------------------------------------------------
    // 包含文件
    //-----------------------------------------------------------------
    #include "Blizzard.h"
    
    //-----------------------------------------------------------------
    // GameEngine.h 中的游戏事件函数
    //-----------------------------------------------------------------
    
    //初始化游戏
    BOOL GameInitialize(HINSTANCE hInstance)
    {
      // 创建游戏引擎
      g_pGame = new GameEngine(hInstance, TEXT("Blizzard"),TEXT("Blizzard"), IDI_BLIZZARD, IDI_BLIZZARD_SM);
      if (g_pGame == NULL)
      {
        return FALSE;
      }
    
      // 设置帧频
      g_pGame->SetFrameRate(15);  //15帧/秒
    
      return TRUE;
    }
    
    //开始游戏
    void GameStart(HWND hWindow)
    {
      // 生成随机数生成器种子
      srand(GetTickCount());
    }
    
    //结束游戏
    void GameEnd()
    {
      // 清理游戏引擎
      delete g_pGame;
    }
    
    //激活游戏
    void GameActivate(HWND hWindow)
    {
      HDC   hDC;
      RECT  rect;
    
      // 在游戏屏幕上绘制文本
      GetClientRect(hWindow, &rect);
      hDC = GetDC(hWindow);
      DrawText(hDC, TEXT("Here comes the blizzard!"), -1, &rect,
        DT_SINGLELINE | DT_CENTER | DT_VCENTER);
      ReleaseDC(hWindow, hDC);
    }
    
    //停用游戏
    void GameDeactivate(HWND hWindow)
    {
      HDC   hDC;
      RECT  rect;
    
      // 在游戏屏幕上绘制停用文本
      GetClientRect(hWindow, &rect);
      hDC = GetDC(hWindow);
      DrawText(hDC, TEXT("The blizzard has passed."), -1, &rect,
        DT_SINGLELINE | DT_CENTER | DT_VCENTER);
      ReleaseDC(hWindow, hDC);
    }
    
    //这个例子中的所有绘制工作都发生在GameCycle()函数中,因此不需要做任何事情,不过这种情况很少见
    void GamePaint(HDC hDC)
    {
    }
    
    //循环游戏
    void GameCycle()
    {
      HDC   hDC;
      HWND  hWindow = g_pGame->GetWindow();
    
      // 在游戏屏幕上的随机位置绘制雪花图标
        hDC = GetDC(hWindow);
        DrawIcon(hDC, rand() % g_pGame->GetWidth(), rand() % g_pGame->GetHeight(),
          (HICON)(WORD)GetClassLong(hWindow, GCL_HICON));
        ReleaseDC(hWindow, hDC);
    }

    GameCycle( )函数中的第一步是获得主游戏窗口的窗口句柄,它允许在游戏屏幕上绘制图形。

    绘制工作实际上发生在调用Win32 DrawIcon( )函数绘制Blizzard图标时。调用标准的rand( )函数来确定游戏屏幕上的一个随机位置,然后使用Win32 GetClassLong( )函数从游戏窗口类中提取图标。

    编译中可能出现的问题

    error LNK2001: unresolved external symbol _main 错误

    错误原因

    Windows项目要使用Windows子系统, 而不是Console

    解决方法

    选择菜单中的[Project工程] –> [Settings设置] –> 选择”Link连接”属性页,在Project Options 工程选项中将 /subsystem:console 改成 /subsystem:windows 。

    这里写图片描述

    A corresponding workspace 点击dsp文件,无法进入工程

    VC 6++的工程文件为dsp,当我们保存工程文件,再进入时,可能会报这个错误。

    这里写图片描述

    解决方法

    自己打开VC6++ ,用菜单栏里的打开文件(报错的话,用前面的工具,选O打开),选中该工程的dsp文件,即可打开这个工程。

    源代码 下载

    http://pan.baidu.com/s/1ge2Vzr1

    展开全文
  • 2D游戏引擎制作:前言

    千次阅读 2018-01-28 21:59:05
    前言 笔者年少时,包括现在,一直是一个喜欢玩游戏的人。父亲曾因此批评过笔者,因为他也是个程序员,就说你可以自己做一个出来之类的话,可到现在都没有教过笔者应该怎么做,可能是他对这方面不感兴趣。大学后选...

    前言

    这是笔者生平第一次写博客,水平较差,请多谅解。


    前言

      笔者年少时,包括现在,一直是一个喜欢玩游戏的人。父亲曾因此批评过笔者,因为他也是个程序员,就说你可以自己做一个出来之类的话,可到现在都没有教过笔者应该怎么做,可能是他对这方面不感兴趣。大学后选专业时选了软件工程(其实应该选数字媒体的orz),就是为了学怎么做游戏,可是课堂上并没有课程来讲这方面内容,所以就上网查。之后知道小型游戏可以直接用代码写,大型游戏需要使用游戏引擎,之后接触到了Unity,但使用起来不太顺手。之后用Unreal,感觉无论是画面还是使用上都非常好,直到用到布料系统,开始感到头疼了。当时布料需要先从3dsMax中使用一个插件导出(一台4G内存笔记本开Unreal和3dsMax,卡成幻灯片了),感觉比较麻烦,而且布料与其他物体的碰撞体也需要使用相同方法导出。百度了几天之后大脑一热,决定自己写一个比Unreal还优秀的3D游戏引擎。

      这个引擎笔者熬了一年半,保证学科成绩60的前提下剩余时间都用来写它了,最后发现,笔者真是个凡骨,仅仅完成了基础功能,读取fbx骨骼动画人物动作总是斜的,效果还比不上2万行的鬼火0.1,笔者曾经炽热的大脑,它们都说已经冰得咬不动了。

      时间又过了半年,以某件事为契机,笔者重新打开了工作用的电脑,不再好高骛远,从2D基础开始重新写一次。笔者知道一个人很难坚持到完成它,所以这次笔者将制作过程记录下来,一方面是为了其他有相同需求的朋友,帮他们提前探好路,笔者所用的方法不一定很好,但至少可以实现效果,另一方面也是抛砖引玉,希望有高手能够指教,笔者完全是个新手,这里先谢过。


    正文

      在笔者幻想中完整的游戏引擎分为三部分,包括UI编辑器(类似与CocosStudio的图形化工具),游戏运行时主体(游戏运行时真正执行的内容),服务器后台(网络游戏中进行数据处理的······控制器?笔者是做前端的,服务器真的不太懂)。

      在之后的一段时间里笔者将引擎从零开始,思路和架构全都没有(所以有可能在第一天添加的代码在第二天就全部删掉了),一点一点添加功能。文章将不定期更新,也有可能中途放弃。


    结束语

      笔者不知道该写什么,就讲个笑话吧!

    展开全文
  • 仿生储物柜 使用Phaser游戏引擎制作的2D平台游戏。 我暂时不在这个项目上工作。
  • Spindel引擎 用c ++和openGL制作游戏引擎
  • 移相器 第一次尝试用phaser 2.0 html5游戏引擎做一个简单的碰撞游戏 它使用 p2 物理引擎
  • 游戏引擎游戏引擎开发入门 早想写一点游戏设计的文章与大家交流 , 一是经 验的问题 , 二是公司正在紧张的游戏制作期 , 实 在抽不出多少时间 , 一直没有动手 , 今天忽然头 脑发热 , 写了一段 , 以后准备陆续写一些...
  • 移相器游戏 用Phaser为国际电联“游戏引擎”课程制作的游戏
  • 幻影游戏引擎

    2014-09-29 12:26:12
    幻影游戏引擎,方便制作横板,动作,RPG类游戏,只有你想不到没有你做不到
  • 游戏引擎0.7a 一个小游戏引擎,我已经全心投入了。 真是太糟糕了,是的
  • CLGE-JavaEdition 用Java内置的简单游戏引擎制作命令行游戏 Python 您可以通过访问查看此应用程序的Python3版本
  • 游戏引擎

    千次阅读 2012-03-04 18:05:31
    游戏引擎是指一些已编写好的可编辑电脑游戏系统或者一些交互式实时图像、声音、玩家控制应用程序的核心组件。(百度百科)  这些系统为游戏设计者提供各种编写游戏所需的各种工具,其目的 在于让游戏设计者能容易...

           游戏引擎是指一些已编写好的可编辑电脑游戏系统或者一些交互式实时图像、声音、玩家控制应用程序的核心组件。(百度百科)

           这些系统为游戏设计者提供各种编写游戏所需的各种工具,其目的 在于让游戏设计者能容易和快速地做出游戏程式而不用由零开始。对游戏设计者而言,这是引擎的优点,因为可以利用各种模块很快完成游戏的制作,节约了时间和成本(相对从零开始制作引擎而言,因为引擎对商业而言需要购买,也不乏那些偷着使用的公司);这也是缺点,因为单从技术角度而言,游戏引擎是核心技术,我们都知道运营一款游戏是吃游戏开发者的第二碗饭,但是谁又深究过,游戏开发如果没有自主知识产权的引擎,就不能被看作是真正的自主开发游戏,也就是吃引擎开发者的第二碗饭。没有自己的游戏引擎的公司,不可能对游戏引擎有深刻的了解。没有深刻的了解,又怎么谈创意?没有创意怎能超越,怎能取得真正的成功。

           大部分都支持多种操作平台,如Linux、Mac OS X、微软Windows。游戏引擎包含以下系统:渲染引擎(即“渲染器”,含二维图像引擎和三维图像引擎)、物理引擎、碰撞检测系统、音效、脚本引擎、电脑动画、人工智能、网络引擎以及场景管理。

    1,基本框架(渲染、逻辑、物理 等等各部分如何组装)
    2、资源管理
    3、渲染(粒子效果)
    4、基本逻辑(网游还要解决逻辑的同步问题)
    5、物理(碰撞,重力等)
    6、UI
    7、音乐音效
    8、网络
    9、脚本(有些类型的游戏引擎需要脚本和逻辑的关联性非常强,有些脚本则比较独立)

    一、十大游戏引擎排名
    来源:英国develop杂志
    排名结果
    1,Unreal Enigne 3
    2,GameBryo Lightspeed(2011年被韩国公司gamebase收购)
    3,CryEngine 3
    4,Unity 3D
    5,BlitzTech
    6,Infernal Engine
    7,Vision Engine
    8,Bigworld Technology Suite
    9,Vicious Engine
    10,Torque 3D

    1,Unreal Enigne3(虚幻引擎3 UE3)

    虚幻引擎3 是由全球顶级游戏EPIC公司(Epic Games是全球领先的数字游戏及图形交互技术开发商,1991年创立于美国)虚幻引擎的最新版本。NovodeX是虚幻引擎3中功能强大的新一代物理引擎,其性能决不输给Havok PhysiCS。NovodeX支持速度、加速度和弹性碰撞等物理概念,并且含有布娃娃系统[1]令人物动作更加逼真。日本的建筑公司把旗下开发的虚化引擎用于建筑业务上。因此,研究最佳方案的该公司发现,使用游戏引擎可以进行最尖端的画面设计,决定使用虚幻引擎。虚幻3引擎写实的表现是被该公司采用的最大原因。图像引擎细节制作和光影表现很不错,配上高品质的贴图,很轻松就能做出画面效果极佳的游戏。      

    虚幻引擎核心由C++写成,支持或曾经支持的平台包括Windows、Linux、Mac OS X、Dreamcast、Xbox、Xbox 360、PS2、PS3等

    代表作品:《战争机器2》《生化奇兵》《虚化竞技场》

    国产:2008 武林群侠传Online中华网龙

    2009 中华英雄 中华网龙

    2010 天子传奇 中华网龙

    Neowiz开发首款虚幻引擎3网游新作《祝福》

    据海外媒体报道,韩国正与当地开发商Neowiz联手打造一款幻想风格的网游新作《祝福》(Bless)。《祝福》的开发团队成员多达150名,项目早已从2009年就开始运作。本作将是一款东方风格的角色扮演类大型网游,提供多达10个种族,以及丰富多样的独特武器和装备,并会呈现出华丽的视觉效果和暴力场面。

    此前Neowiz的代表作包括《穿越火线》和《战地之王》,均为射击类网游。

      这也是Neowiz首款使用虚幻引擎3开发的作品,韩国将提供全面的技术支持。虚幻引擎3是英配最新推出的顶尖开发工具,处于全球业界的领先地位,性能极为强大。

    目前,除了用在建筑方面之外,虚幻3引擎还被其他不少非游戏行业使用。其中包括,美国职业橄榄球达拉斯小牛队的主场建设,动画制作工具的开发,儿童用3D TV系列的制作等。

    2,Gamebryo引擎是NetImmerse引擎的后继版本,是由Numerical Design Limited最初开发的游戏中间层,在与Emergent Game Technologies公司合并后,引擎改名为Gamebryo Element。不过已经被韩国Gamebase收购了,将改名字了哦。Gamebase公司介绍:2003年11月在韩国创办,到2010年为止是Gamebryo引擎的韩国独家供应商。2010年12月21 日,Gamebase从开发商从Emergent Game Technologies公司收购Gamebryo引擎的所有知识产权及全部资产。同时,在2011年1月在美国创办Gamebase USA,开始开发新版Gamebryo引擎。

     在Gamebryo中,物理系统使用的是NVidia公司的PhysX系统。

     GamebryoElement引擎是由C++编写的多平台游戏引擎,他支持的平台有:Windows、Wii、PlayStation 2、PlayStation3、Xbox和Xbox 360。

    代表作,知名的游戏有《上古卷轴4》、《辐射3》、《文明4》等。另外,《战锤OL》、《星辰变》、《境传说2》

    国内使用Gamebryo游戏引擎的公司及开发的游戏 (授权费用:27W美元

      御龙在天  腾讯

      轩辕传奇  腾讯

      QQ飞车 腾讯

      星辰变  盛大

      古剑奇谭  上海烛龙

      宠物森林 久游

      魔界2   金酷游戏

    侠义道III  成都梦工厂

    黄帝  西安鼎盛数码

    3,CryENGINE它最初是Crytek1999年由Yerli兄弟所成立。Crytek总部位在德国法兰克福)为NVIDIA开发的技术演示,后来该公司看到了它的潜力,将其用于FPS游戏孤岛惊魂》的开发。授权价:70W欧元,也有一说法为500WRMB。

     成功拿下Crytek MMO FPS《战争前线》之后,腾讯还出人意外的获得了Crytek最新游戏引擎CryENGINE3的开发授权,将借此引擎自主研发或于Crytek合作开发一款新网游。

    孤岛惊魂》(2004,MicrosoftWindows) - Crytek育碧软件

    《孤岛惊魂 本能》(2005, Xbox) - 蒙特利尔育碧,育碧软件

    《孤岛惊魂 本能:进化》(2006,Xbox) - 蒙特利尔育碧,育碧软件

    《孤岛惊魂 本能:掠食者》(2006,Xbox360) - 蒙特利尔育碧,育碧软件

    《孤岛惊魂 复仇》(2006,Wii) - 蒙特利尔育碧,育碧软件

    永恒之塔》(2008,MicrosoftWindows) -NCsoft,NCsoft

     

    4,Unity3D (U3D) 是丹麦Unity公司开发的游戏开发工具,具体的特性包含整合的编辑器、跨平台发布、地形编辑、着色器,脚本,网络,物理,版本控制等特性。Pro版(包含制作工具和版本控制器)的售价为1998美元,这个价格对于国内的中小游戏开发者无疑是个福音。除此之外Unity3D还在向WII和IPhone进军作为Unity的使用者。此引擎定位非常明确,就是针对中小型游戏,上手容易,易扩展性。以C#和javascript为主要的编码语言,貌似还有一个boo(*&##什么语言),为了实现简单代码间类的互相操作。然而对于一个商业化的游戏引擎来说,快速高效的完成类似的特效应该是分内之事。游戏引擎的初衷就是将游戏开发者筋力转移到游戏的可玩性上来。那么Unity3D为什么会吸引开发者的目光呢,重要的原因是廉价,并且能够发布为基于浏览器的网页格式。这个是目前的一大趋势,玩家无须下载庞大的客户端,打开浏览器即可进入游戏。
      Unity3D使用了PhysX的物理引擎,但是非常遗憾的是还不能支持流体和布料的效果。Unity公司在在脚本方面不可不谓之强悍,Unity3D支持JaveScript, C#, Boo脚本,如果开发非网页的独立版还可使用插件。

     

     

    上面的十大引擎都是商业引擎,也没有一个是国产的。当然也有开源的,比如我们比较熟悉的OGRE引擎;在国外发展如何,至少流行的3D网游是没有基于OGRE的,单机游戏有几款。在国内,基于OGRE的大作已经有几款了,其中包括搜狐的《天龙八部》、吉比特的《问鼎》、深圳网域的《华夏2》以及久游的《疯狂飙车》还有很多公司也正在开发基于OGRE的网络游戏,这也大大降低了的进入门槛,至少不用花上千万去买Unreal引擎了。

    《天骄3》是光宇游戏旗下重量级3D动作网游,游戏采用OverMax引擎(据说是纯自主研发)技术,营造出电影画质般的场景和栩栩如生的角色造型,优异的画面表现以及游戏本身的魅力。他们的命运在中国玩家的手上,只有玩家的觉醒,和游戏公司的自立,才能催生中华民族自己的游戏引擎。

     [1]布娃娃系统

    英文:ragdoll physics

      在早期电脑游戏中,开发者通过手工制作一组按动作顺序的角色图像,并接连显示出来来达到角色动画的目的。这种技术对处理器的要求很低。

      随着电子科技的不断发展,在游戏中实现实时动画逐渐变成现实。开发者用三维绘图工具制作一个角 色模型,并在合适的位置给角色安装骨骼,通过游戏引擎中的骨骼控制模板,控制这些骨骼的移动,而角色的表层随着骨骼的移动而发生相应的变化。这样的技术让游戏中的角色有更加多变丰富的动作可以变现。   但由于技术的限制,诸如骨骼的移动没有类似肌肉的物质来约束,以致游戏引擎在控制移动骨骼时,常常出现将骨骼移到一个在现实中不可能实现的位置,就像布娃娃,该系统由此得名。由于计算机的各种技术限制,游戏开发者不能够使用完全仿真的布娃娃设计,而采用一种相对简单的模式。

      一些末端骨骼如手指能做出种类繁多的动作。

      利用骨骼联合点代替真实的骨骼肌来约束骨骼的移动,能取得较好的表现效果。

      通过布娃娃的碰撞检测可以让角色在游戏中的表现更为真实。不同的先前的将整个角色模型用来进行碰撞检测。

    布娃娃系统最大的优势还是在于取代传统的角色动作系统。


    展开全文
  • 凯克 Kek,使用LWJGL3构建的Kotlin 2D游戏引擎 开源:只是想尝试使用LWJGL3制作游戏引擎制作游戏引擎不是一个好主意。
  • didot:使用Zig制作的多线程3D游戏引擎

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 39,407
精华内容 15,762
关键字:

如何制作游戏引擎