精华内容
下载资源
问答
  • 你唯一要做的就是在完成编译之后,点一下左下角的铃铛。 「信息保护」 这款来自国外开发者开发的应用彰显着国外对于信息保护的态度。哪怕「Scrittor」去掉了多余的功能。还是将密码锁保留了下来,当打开应用时需要...

    0aa756e396a02a85fd68cd2c8da150b6.png

    本文转至微信公众号HelpToMe

    背景

    我们常常会因为忘掉一个思路,想法,灵感懊恼不已。常常会因为忘掉一些事情,而重复的去做一些没有意义的事情。俗话说:“好记性不如烂笔头”。养成一个良好的记事习惯,绝对会大大提高自身的工作效率。把想法、事件等等用文字记录下来似乎更加符合普通人的习惯。

    智能手机普及的今天,我们不需要再用最原始的方法,拿本子记录,写下一条条的内容。繁琐的记录方式,和凌乱的顺序,会使我们很难坚持下来,这不利于我们培养习惯。科技的进步就是为了让人类更懒惰。没错,现在我们只需要一款app就可以做到。

    市面上大量的记事本应用,数不胜数。手机厂商在你手机里也必备了一些记事本。然而,我们可能不太想去使用它们。为什么?是因为软件做得不够好吗?功能不够全吗?都不是,是因为没有习惯。这是我思考很久的答案。

    当然一款高质量,UI设计精美的记事本,是我们坚持下来的首要原因。

    所有的记事工具中,我最喜欢的莫过于锤子科技的「闪念胶囊」。个人觉得这是记事工具里最方便,人性化的设计。但是这不是记事本,很多平台用不了。那么就说说我们可以使用一些记事本。

    锤子便签

    同样是锤子出品的便签应用「锤子便签」。在安卓平台,可能是最流行的记事工具。图文排版的记录方式,可能会让你重新爱上记录。你还可以随时随地将便签内容生成精美的长微博或图片并分享。雅致的信纸、精心调整的排版,令内容更加赏心悦目。

    447302bf5d5dcc771522ae623b5f1743.png
    锤子便签

    拟物并且极其精致的UI风格,是锤子科技一贯的行事作风。用在这款app上,显得很有情调。木纹的拟物背景,给你一种在书房创作的感觉,能让人激发起写作的乐趣。里面记事本风格的内容输入区域,给人一种在使用实体笔记本记录的感觉。

    「分享」

    锤子便签之所以被用户喜欢的一大部分原因,可能是这个功能。分享至长微博,生成的微博状态并不单单仅附加「生成网页」链接,而是会同样生成微博长图,这样在保证阅读便利性的同时,又使得用户创造的内容不被局限在无法搜索的图片中。

    c042f90a9686cc7bde2abc49f41d438f.png
    分享

    「Markdown模式」

    Markdown 是一种使用纯文本编写的标记语言,它可以使便签生成图片或网页时,产生格式丰富的页面排版效果,比如突出标题、居中、加粗、引用和生成列表。

    Markdown模式的加入绝对是便签的吸引用户的一大步,简单,便捷的操作。帮助用户省去了,对内容排版的时间。获取很多人没有使用过Markdown,简单来说。就是帮你生成一篇规范的,简约的排版格式。这对于很多自媒体用户来说,不可多得。

    「同步」

    锤子科技欢喜云功能的实现,使得锤子便签,也具有了同步的功能。就像一个云笔记,不仅可以在移动端记录,在云端同样可以继续自己的创作。结合Markdown的排版,在移动端和网页版的体验没有任何偏差。

    681d5aa53e18c38ae98899dfe2a4209a.png

    Scrittor

    相比于锤子科技的简单,功能强大之外。那么这块应用只能用,简陋来形容了。但是为什么要推荐给大家呢?因为其颜值相当的高,而且快速。可以说,打开即可记录。

    9ee8bf95886fc09a5eb91247ef7483b0.png

    「Scrittor」的用户界面简洁实用,它去掉了多余的功能,留下了简单的操作;添加便签,选择分类,大功告成。或者连选择分类都没有必要。

    「界面主题」

    「Scrittor」支持三种不同的主题,但是严格来说只有两种,非黑即白。正是因为这种模式才显得它那么的干净。多余繁杂的选项,往往给人一种累赘的体验。反而色彩分明的黑白显得高雅和简约。白,夜,黑。随便一种都显得好看。

    d9302b1ea9940e7d501dec11baa61598.png

    「内容编辑与功能」

    「Scrittor」的内容编译可以说是我最非常喜欢的一种字体格式。Space Mono的字体,给人一种在实用19世纪老实打字机一样的感觉,一个个字符落在白纸上,有一种莫名的质感,会让你多敲几个字。

    65bdb942762507a6af7d8dec3c500389.png

    当你加入链接时,它会自动识别并且标红。你会觉得以切都是这么自然。没有一丝的做作。就好像自己写在信纸上一样。

    「Scrittor」 在文本输入的功能上做得可谓是简单至极,没有像锤子便签一样的Markdown 格式,只支持标题、文本、列表,但可以标签和收藏来管理笔记。标签可以用颜色进行区别,不仅如此还能给每一个分类的标签添加说明。笔记分类整理后,能够方便查找;还可以用星标收藏重要的记录。

    「快速记录与提醒」

    打开「Scrittor」后会在下拉菜单存在一个快捷启动的按钮。当你又事情需要记录时,可以快速打开,不至于我们忘掉自己需要记录的内容。除此之外「Scrittor」人性化的地方在于,它可以提醒你刚才记录的内容。它会将你刚才输入的内容展示在下拉菜单。时刻提醒你。你唯一要做的就是在完成编译之后,点一下左下角的小铃铛。

    「信息保护」

    这款来自国外开发者开发的应用彰显着国外对于信息保护的态度。哪怕「Scrittor」去掉了多余的功能。还是将密码锁保留了下来,当打开应用时需要输入密码。你也可以使用指纹进行解锁。

    b406b90aa1ba6ca40751dfd2697d8f39.png

    信息保护,确实是我们应该加强的地方,相对于国外,我们还差太多。

    「总结」

    「Scrittor」虽然简化了很多功能,但是最实用记录。它将之的体验提高到了最高。这无疑是它的加分项。用一句话评价它“优雅的外表,稳重的气质,朴实的功能“

    结语

    一款实用的记事本提高你多少办公效率。这问题,没法用量来衡量。但至少它可以解决前文提高的,重复问题。有时候生活的效率,就是在这一点一滴的小事中体现的。希望大家可以养成记录的习惯。尝试改变一下自己的生活效率。

    展开全文
  • 后续将根据这个游戏引擎开发小游戏,逐渐完善该引擎并介绍游戏编程相关的知识。 假设你起码拥有C++的知识。以《游戏编程入门》 Micheal Morrison为基本教材,PDF书籍下载,光盘内容下载。开发环境为Win7,VC 6++ ...

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

    假设你起码拥有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

    展开全文
  • 记事本编写的贪吃蛇

    2013-03-28 15:13:12
    记事本编写的小游戏,用记事本打开可以看源代码
  • 单机版记事本

    2018-03-08 22:55:48
    由于之前公司没有网络,所以云笔记无法使用,工作中遇到的各种问题记录起来很不方便,所以开发了一个简单的本地记事本。修复了之前上传的记事本中的一个bug。
  • 小游戏代码开发

    2018-09-08 11:44:34
    这是用c语言编写的小游戏,可以硬键盘上的wasd来控制游戏中的上下左右
  • 一个简单的记事本小程序源码

    千次阅读 2010-05-16 17:09:00
     this.Text = filename + "-简单的记事本";  return currentFilePath;  }  private void tsmExit_Click(object sender, EventArgs e)  {  Application.Exit();  }  //复制  private void ...

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    using System.IO;

    namespace txtWrite
    {
        public partial class Form1 : Form
        {
            private string currentFilePath;//存储打开文件的字段
           
            public Form1()
            {
                InitializeComponent();
            }
            //打开文件
            private void tspOpen_Click(object sender, EventArgs e)
            {
                if (ofdFile.ShowDialog() == DialogResult.OK)
                {
                    getFileName(ofdFile.FileName);
                    txtFile.Text = File.ReadAllText(currentFilePath);
                }
            }

            //保存
            private void tsmSave_Click(object sender, EventArgs e)
            {
                File.WriteAllText(currentFilePath, txtFile.Text);
            }


            //另存为
            private void tsmSaveas_Click(object sender, EventArgs e)
            {
                if (sfdSave.ShowDialog() == DialogResult.OK)
                {
                    File.WriteAllText(sfdSave.FileName, txtFile.Text);

                    getFileName(sfdSave.FileName);
                }
            }

            private string getFileName(string filePath)
            {
                currentFilePath = filePath;
                string filename = Path.GetFileName(currentFilePath);//从一个完整路径中取出文件名
                this.Text = filename + "-简单的记事本";
                return currentFilePath;
            }

            private void tsmExit_Click(object sender, EventArgs e)
            {
                Application.Exit();
            }

            //复制
            private void cOPYToolStripMenuItem_Click(object sender, EventArgs e)
            {
                txtFile.Copy();
            }
            //粘贴
            private void tsmPaste_Click(object sender, EventArgs e)
            {
                txtFile.Paste();
            }
            //剪切
            private void tsmCut_Click(object sender, EventArgs e)
            {
                txtFile.Cut();
            }
        }
    }

     

     

     

    本人相当的菜鸟,高手见了本文莫笑!

     

    刚刚学c#不久

    展开全文
  • 本讲介绍用Python开发小游戏的方法,从中学习使用Python编写图形界面的程序,图形图像的基础知识,以及在图形界面程序中与用户交互。最后部分还将学习使用版本管理工具下载他人的代码。14.1 图形化应用程序之前学习...

    无论哪一种编程语言,实现图形界面程序的方法都大同小异。本讲介绍用Python开发小游戏的方法,从中学习使用Python编写图形界面的程序,图形图像的基础知识,以及在图形界面程序中与用户交互。最后部分还将学习使用版本管理工具下载他人的代码。

    14.1 图形化应用程序

    之前学习过的程序都相对简单:程序顺序执行,如图14.1左侧流程图所示,程序用字符显示输出信息。而带窗口界面的程序,无论是工具界面(如记事本),还是图像界面(如游戏),程序都包括三部分:

    • 初始化 初始化界面绘制模块,设置窗口属性(如:长、宽)、做装载图片和声音文件等准备工作。
    • 主循环 主循环等待接收用户输入的信息(鼠标或键盘输入),并对用户输入做出反馈(在界面上显示)。同时不断执行程序(如推进游戏过程)。
    • 退出 退出程序关闭已打开的窗口、释放申请的资源等等。

    带界面的程序启动后一直运行,直到用户关闭窗口或者在界面上选择退出时程序结束,如图14.1右侧流程图所示。

    7af83276641a01c924ad82e377c9481d.png
    图14.1 程序流程图

    14.2 绘图区域

    在电脑或者手机设备上显示的图片是由MxN个点组成的,其中的每一个点也叫做像素。每个像素大小一致,颜色不同。描述颜色的方法也有很多,在计算机中最常用红(RED)、绿(GREEN)、蓝(BLUE)描述一个像素点的颜色,它们分别代表每种颜色的亮度,也称为RGB。

    Python编程时,颜色常写成含有三个元素的元组,如(0,0,0)的RGB三个值都为0不发光,即黑色,而(255,255,255)三个值都为其最大值255最强光,即白色。255是用8位二进制数所能描述的最大值,也就是说每一位颜色用一个字节(8位)表示,一般3个字节描述一个像素点,有时也用四个值描述,如(255,255,255,255),前三位是颜色,最后一位是透明度,透明度的范围也是0-255,255为不透明,0为完全透明。

    Python编程时,一般将窗口作为画布绘图,窗口左上角位置为 (0,0),横坐标在前,纵坐标在后,越向右侧横坐标值越大,越向下纵坐标值越大。横向常用x表示,纵向常用y表示,即(x,y),如图14.2所示。

    注意:起始坐标从0开始,而不是1。

    b32be51c0d9b78b06bd0b405141f1f37.png
    图14.2 绘图区域图示

    图中的颜色区域被描述为 (4,2,3,2),依次是起始横坐标4,起始纵坐标2,宽度3,高度2。

    14.3 Pygame

    在Python环境下编写游戏比较简单,三方库pygame是常用的Python游戏编程工具,提供了图像、声音的支持。

    使用前需要先安装pygame模块,在Windows下打开:开始->所有程序->Anaconda3的Anaconda Prompt命令行,使用以下命令安装模块:

    01 $ pip install pygame

    本讲也通过编写pygame游戏了解图形图像程序的编写过程。下例将在窗口中绘制矩形,并根据用户输入的上下左右按键移动矩形的位置。

    01 

    第01-02行引入模块。
    第04行初始化pygame模块。
    第05行设置窗口大小。
    第07-08行创建变量用于设置和存储矩形位置。
    第09行为主循环,确保窗口一直显示,直到程序退出。
    第10-22行响应用户操作。
    第11行响应退出事件,当用户关闭游戏窗口时,此事件被触发。
    第12行释放游戏资源。
    第13行退出程序。
    第14行响应键盘按下事件。
    第15-22行对键盘的上下右左右四个按钮分别处理,改变x,y值。
    第23行将窗口背景绘制为黑色。
    第24行设置一个矩形区域,四个参数分别指定矩形起点的x坐标、y坐标、宽度和高度分别为100。
    第25行在窗口上绘制该矩形,函数的第一个参数指向绘制窗口,第二个参数指定颜色为红色,第三个参数指定绘制位置,第四个参数指定区域内部填充颜色。
    第26行用flip方法更新显示区域,此时绘制出来的图像被显示在窗口之中。
    第27行y值增加,使得在用户不按键的情况下,红色矩形也向下移动。

    本例中的程序类似于游戏“俄罗斯方块”,下一讲将从网络下载真正的“俄罗斯方块”游戏代码,进一步学习编写此类小游戏的技能。

    课后练习:(练习答案见本讲最后的小结部分)

    练习一:请在窗口中绘制背景为白色,前景为绿色的米老鼠头像,如图14.3所示,按任意键退出程序。
    提示:画圆的方法是:
    pygame.draw.circle(画布, 颜色, 圆心点, 半径, 填充方式)
    例如: pygame.draw.circle(screen, (0,255,0), (100,100), 50, 0)。
    与绘制矩形不同,绘制矩形需要指定矩形左上角坐标(横坐标、纵坐标)、宽和高,绘制圆形指定的是圆心点坐标(横坐标100、纵坐标100),圆的半径50。

    a74949bdc02836d1cf831c0c138a027c.png
    图14.3 绘制米老鼠效果图

    14.4 Git软件管理

    Git是分布式版本控制系统。当编写软件时,在不同的开发阶段可能需要保存多个版本的代码和数据。使用Git可以管理数据和代码的不同版本。

    GitHub是一个面向开源及私有软件项目的托管平台,它是远程的服务器,开发者可以将自己的代码上传到GitHub服务器,供他人下载,或者仅供自己和有限的几个人可见。可供所有人下载的软件和数据叫做“开源软件”;仅自己可见的叫作“私有软件”。目前Github拥有超过900万开发者用户,大量可以下载的高质量代码。

    本讲将介绍从GitHub下载他人公开的游戏代码,从中学习游戏的编写方法。

    14.4.1 安装Git软件

    Git早期只支持Linux和Unix,现在也可以在Windows上运行,但需要安装软件。先下载软件,打开https://git-scm.com/downloads,选择Windows版本,稍等片刻之后自动开始下载;下载后按提示选择Next和Install默认选项安装软件即可。

    软件安装成功之后可从Windows开始菜单中打开,开始->所有程序->Git->Git Bash,此时Git命令行被打开。

    14.4.2 下载游戏代码

    使用以下命令下载程序源代码,如图14.1所示:

    01 $ git clone https://github.com/lovetianya/pygame-development.git

    dfb4b984d1e87b2a5486c187592eafb5.png
    图14.4 下载项目的代码

    pygame-development是GitHub上的开源游戏代码,其中实现了俄罗斯方块、贪吃蛇等小游戏。

    用pwd命令可以看到当前目录,程序代码下载到了当前目录之中,其中的els目录中是实现俄罗斯方块的代码和相关的资源,如图14.5所示。font目录下是游戏中用到的字体,pictures目录下存储的是图片,run-this.py是用Python编写的程序源码,用Spyder打开它,或者复制到Jupyter Notebook中即可运行。此处建议用Spyder打开程序并运行(开始->所有程序->Anaconda3->Spyder)。

    b5f09001ec5596e19fc90e42f9cf4d4f.png
    图14.5 俄罗斯方块相关资源

    课后练习:

    练习二:运行游戏“俄罗斯方块”、“贪吃蛇”、“五子棋”,并阅读其源代码,找到其中的主循环、按键响应、以及绘图的相关代码。

    14.5 思维训练

    14.5.1 举一返三

    上一讲提到了通用人工智能AGI,即建立拥有广泛且适应性强的智能,其中包括将学习到的有限知识应用到更多的领域之中。本部分来探讨人类如何实现了举一返三。

    1.常识系统

    机器不能像人一样思考或者我们认为机器缺乏创造力,很大程度上是因为没有常识系统,目前的机器学习模型,一般都针对具体单一的功能,写文章的只懂写文章,识别图像也只关注图像本身,比如GPT-2模型通过学习所有金庸先生的小说,撰写了如下的文字。

    b1df4380d287993648e080dc7b95c7aa.png
    图14.6 模型生成文本

    如果读过《天龙八部》这部小说就不难发现,虽然在语言风格上问题不大,但人物关系不太正常。这是因为模型只模仿了文章的语言风格,模型通过学习阅读大量文字,根据前文计算下一个字最可能是什么,但它不知道“段誉”究竟是什么意思;以及段誉和王语嫣之间是什么关系。

    写作的人将脑中的思维框架转换成文字,并试图在读者脑中构建起类似的结构,其中包含大量的常识和背景知识,比如通过故事发生的时间、地点、氛围、故事风格,激活读者脑中的某种场景,这些都是文字之外的信息。思维中故事的框架是多层次的网络,而机器所识别的文字只是相对扁平的结构。

    人在成长中构建起丰富的常识系统。知识面越宽广,经验越丰富,就越具有优势。

    2.生成框架

    解决问题的框架,或者叫作流程、套路,就像是程序中的函数。把某种功能封装在函数之中,在之后遇到同样问题时,就可以直接使用。

    写程序处理问题的过程可细分成:获取、整理、使用。如果要实现某一功能,首先,要找到需要的数据比如Excel表;以及处理数据用到的方法如安装第三方库;有了这些基本元素之后,开始编写成程序,然后运行程序实现功能。

    除了这些基本步骤以外,有经验的程序员在程序正常运行之后,还会对程序做进一步优化:

    • 让程序变得可重用:比如把其中的各部分功能拆分成函数,以便之后在其它场合继续使用。函数除了能满足当前需要的功能,还要考虑满足未来的扩展功能。
    • 优化程序运行速度和程序结构:比如功能类似的函数是否可以合二为一。
    • 加强程序的健壮性,在遇到小问题时也能正常使用。
    • 规范化格式以及命名,加入注释,使程序更加清晰易懂。

    同样道理,在学习和实践之后,我们也需要反思:是不是可以做得更好?还需要做出哪些调整,或者加强训练;能否从复杂的过程中提取出几个重要经验模块?这些经验还可以用到什么场合?

    在编写函数、整理代码的过程中,就可以很好地训练这方面的能力。

    3.拆分

    处理复杂问题时,几乎不会遇到两次完全相同的情况,但可能遇到过程中的某一部分与之前的经验重合。就像本讲的练习中画出米老鼠头像可能让人觉得毫无头绪,但是拆开看,米老鼠头由三个相互重叠的圆形组成。

    解决复杂问题通常需要:拆分成单个问题、解决单个问题、处理各个问题之间的关系。调试程序也是同样道理,如果不能确定整体程序在什么位置出错,分块调试也是有效的方法。

    4. 相似性

    对比和类比也曾被认为是人类特有的灵性。二者有一个共同的特点,就是被比较的两者之间一定存在共性。类比很容易理解,比如把一片落叶比做蝴蝶,因为它们在风中具有相似的姿态。而对比也需要共性,虽然高和矮完全不同,但它们描述的都是长度。

    从总结规律的角度看,只要一种规则反复出现,就可以被提取;从使用的角度看,由于具有相似性,可以使用已有的经验处理未知的情况。

    5.代入框架和迁移学习

    很多人死读书,虽然记住了,但是场景稍有变化就不会使用。下面来看看机器是如何实现迁移学习,在不同的场景之中使用旧有的技能。

    迁移学习是人工智能领域近几年的热门方法,比如它先使用大量图片训练模型,训练出了模型对于图片的常识,包括对明暗、边角、形状等等,如果最终需要识别图中的水果,在使用之前,再用少量的水果图片进一步训练模型即可使用。

    可以说迁移学习的本质是使用大量数据训练常识,再加入微调。将已有的常识和当前的场景结合起来,解决当下的问题。通过对比相似性,使用旧框架,如果无效,也可以使用少量新数据训练调整旧有框架。

    当头脑中存储了大量框架,并且整理成清晰的结构,就更容易和当前场景结合。

    好方法事半功倍,但再好的方法也需要练习。

    14.5.2 创新

    人们常常认为机器在创新和想象方面无法超越人类?是否真是这样?让我们先来看看机器在棋类比赛中的表现。早在20年前,IBM的深蓝就打败了国际象棋大师,这已不再是什么新闻。在2017年10月在《科学》杂志上发表了一遍关于AlphaZero的论文,它的惊人之处在于,AlphaZero无需人类指导,仅仅通过自己与自己对弈,就快速地理解了国际象棋的规则,成为了目前为止最好的棋手。

    比胜利更重要的是,AlphaZero是自学成材,它具有自己的洞察力,而非被人教会,而且它还自创了一些出乎人们意料的策略,以致于,在后来的人类比赛中,如果有人出现非常精妙的走法,都可能被怀疑是使用计算机作弊。

    再来看看什么是创新,申请专利时把创新分为三种:

    第一种是发明专利,它是针对产品和方法产生新技术方案。就像爱迪生发明电灯,他通过1000多次不同材料的实验;而现今,科学家利用虚拟现实和分子技术,极大地优化了实验过程。比如在荷兰代尔夫特理工大学,正尝试使用贝叶斯模型寻找一种聚合物排列方法,使材料变得坚固、轻量和可折叠。

    第二种是实用新型专利,它是对产品的构造、结构、形状提出更加实用的新方案。就像瓦特发明蒸汽机的故事,实际上瓦特并非蒸汽机的发明者,而是蒸汽机的改造者,应该说他发明了第一台有实用价值的蒸汽机。这种创新以优化和改造为主。

    第三种是外观设计专利,这种专业偏重设计,与艺术相关,目前人工智能已经可以画慢画、谱曲、写作、创造各种艺术作品,也有人说,机器主要偏重模仿,没有艺术家的灵魂。而从上面武侠小说的例子可以看到,目前机器学习的模仿效果已经非常强大。BERT模型也可被用于生成故事的简介。如果模型学到了人物的关系,以及创建故事的规则,理论上也能编写故事。

    无论是修改旧方法还是创造新方法,都用到猜谜原则(试错),不断试错,其具体方法是随机修改重要特征,看是否解决了问题,或者效果是否变得更好。进而拆成小块不断式错,向目标靠近。在穷举方面,机器胜过人类。而相比之下,人类在常识和解决复杂问题方面更占优势。

    这些方法能让机器学会,不论天赋,更何况是正常人类。真实世界比棋盘上的可能性多得多,无法通过单纯的试错学习。在当前阶段,人机结合往往能达到最好的效果。人负责定义问题,构建和管理整体结构,而机器负责具体的工作。比如:某人想到了一个很好的故事,但文笔不够好,通过与机器结合,就能达到更加完美的写作效果。

    14.6 小结

    14.6.1 单词

    本讲需要掌握的英文单词如表14.1所示。

    7c9c4aa099bb881e999730d5d9f25c34.png
    表14.1本讲需要掌握的英文单词

    14.6.2 习题答案

    1.练习一:请在窗口中绘制背景为白色,前景为绿色的米老鼠头像,如图14.3所示,按任意键退出程序。

    01 

    2.练习二:运行游戏“俄罗斯方块”、“贪吃蛇”、“五子棋”,并阅读其源代码,找到其中的主循环、按键响应、以及绘图的相关代码。

    以贪吃蛇为例,“while running”中的是主循环,“event.key”相关的是按键处理,“draw_”相关的是绘图。

    展开全文
  • 会从计算机的使用开始讲解,中间搭配一些经典的针对知识点的练习,最终大家都可以用Python开发出一个小游戏,快来跟我一起往下看!第一课:学习准备(上):计算机是什么【本节目标】理解DOS命令行。听说大神用...
  • 习惯就收藏转发加关注哦!!! 想学编程的原因有很多,你也许是想要做一个程序,又或者你只是想投身于这个行业,所以,在选择你的第一门编程语言之前...桌面应用是运行在台式机或者笔记本电脑上的传统软件程序。这样你...
  • 一个可以发给爸妈使用的实用的图形化程序,一刻钟完成系列~
  • C# DX 编程

    千次阅读 2010-06-11 22:54:00
    要:C#进行游戏编程一直受到一些C++程序员的怀疑和猜忌,是不是真的C#就不能进行游戏编程呢? 回答当然是否定的,因为,微软已经发布了DirectX9.0SDK开发包,使得C#进行游戏编程简单易行,本篇在.NET环境下,用...
  • C C++编程子资料库(程序)

    千次阅读 2006-11-29 19:31:00
    ◆六籽弹小游戏 http://post.baidu.com/f?kz=17637684 ◆黑白棋:http://post.baidu.com/f?kz=19624178 ◆十个学生的成绩统计:http://post.baidu.com/f?kz=14787745 ◆某一天是这一年的第几天:...
  • C C++编程子资料库(程序)

    千次阅读 2006-11-26 17:24:00
    ◆六籽弹小游戏 http://post.baidu.com/f?kz=17637684 ◆黑白棋:http://post.baidu.com/f?kz=19624178 ◆十个学生的成绩统计:http://post.baidu.com/f?kz=14787745 ◆某一天是这一年的第几天:...
  • 用jar包运行带GUI的java游戏方法:http://www.cnblogs.com/gongsunaokong/p/8724718.html cmd进入到项目地址,使用 jar -cvf ***(压缩...打开META-INF文件夹,用记事本打开一个叫MANIFEST.MF的配置文件, 并在下...
  • java面向对象编程基础

    2021-03-20 11:33:25
    java面向对象编程基础 前言:什么是java 是咖啡飘香的清晨 是斯坦福校园意浓情深 是James的思想睿智 是剁手党双十一挥舞的利刃 是大数据云计算驰骋的平台 是春运时节那期盼回家的眼神 ...
  • 会从计算机的使用开始讲解,中间搭配一些经典的针对知识点的练习,最终大家都可以用Python开发出一个小游戏,快来跟我一起往下看!第一课:学习准备(上):计算机是什么【本节目标】理解DOS命令行。听说大神用...
  • 菜看到大鸟的电脑上开着记事本。 “哦,我打算写篇博客,名字就叫《设计模式不能戏说?》”大鸟解释道。 “嘻嘻,废话,这又不是电视剧《戏说XX》,可以乱讲不负责任,设计模式戏说了如何讲得清楚。怎么突然会...
  • 首先写这个小游戏你要先导入库,并且先设置好黑白棋子的起始位置。 import sys import random import pygame from pygame.locals import * import pygame.gfxdraw from collections import namedtuple Chessman = ...
  • 24、C语言编程项目实训(高级)(全日制一个半月,夜班三个月,学费1390元)理论与实操一体化课程:一、C语言基础:1、应用C语言的各种特点;2、应用算法的含义、特点、表示方法二、C的基本数据类型及运算:1、应用C语言...
  • 自己做的一个超级简单的小游戏

    万次阅读 2017-04-14 10:14:53
    自己做了一个简单的uniy3d小游戏方向键控制一个小球躲避别的小球,撞到指定的墙胜利,被别的球撞到失败。初学者练手 Playermove Enemymove Islose_Trigger Spawn Camera follow_player UI WallIsWin游戏图片 代码...
  • 编程新手导论

    万次阅读 2012-06-07 20:00:31
    第二部分 导论,这一部分主要是关于编程的导论, (要懂得一点思想具备一点常识)《设计,编码,,与软工》(编程与思想)这一章解释了三种思想,原语,抽象,组合,,和软件开发的二个重要过程,,软件工程的相关...
  • 现在手中掌握的很多淫荡的技巧正是因为学习了很多编程语言的缘故,不过这并不妨碍我正常地使用C++来在合理的时间内完成我的目标。 学习C++是一个艰难的过程。如果从我第一次看C++的书算起,现在已经过了11年了。一...
  • 编程语言

    千次阅读 2008-01-27 12:52:00
    飞扬)电脑每做的一次动作,一个步骤,都是按照以经用计算机语言编好的程序来执行的,程序是计算机要执行的指令的集合,而程序全部都是用我们所掌握的语言来编写的。所以人们要控制计算机一定要通过计算机语言向...
  • J2ME编程之Nokia 7210配置篇 J2ME编程之Nokia 7210配置篇 作者: 不详 一、引言 最近有朋友推荐能否写一些有关J2ME编程方面的文章。心想最近正好有心把自己工作所...
  • 常用编程语言简介大全

    千次阅读 2020-05-19 15:42:55
    一、计算机编程语言分类;二、高级语言分类;三、常用语言的用途
  • ... ... ...代码是一门语言,这门语言...通过编写代码,人类可以“命令”计算机开发网页、开发软件、搭建游戏... ... 这门语言并不是上帝的发明,它是前辈们发挥聪明才智创造出来的,前辈们的创造过程虽然充满了有趣...
  • 3.4 学编程不拘于语言,学语言不限于平台 编程语言 软件和硬件——计算机要作为一个整体看待 语言的江湖 语言不是回事 多平台上的精彩 3.4 学编程不拘于语言,学语言不限于平台 学习程序设计,我们总是从一门...
  • 大家第一次接触编程的时候我想很多人都会在那些Q群啊之类的地方不断的问,怎么学习编程,要看些那些书。甚至在百度,谷歌里搜索如何学习编程。 这篇文章,我会从我自己学习编程的角度去描述,如何学习,可能不是最好...
  • 游戏主体循环以及帧率设置 让子弹飞 刷出敌机 打怪 把飞机敌机子弹都画出来 处理键盘事件 分数显示 和 GameOver 最终代码 01 前言 这次还是用python的pygame库来做的游戏。关于这个库的内容,...
  • 编程新手导论(转载)

    万次阅读 2012-01-22 10:26:54
    第二部分 导论,这一部分主要是关于编程的导论, (要懂得一点思想具备一点常识)《设计,编码,,与软工》(编程与思想)这一章解释了三种思想,原语,抽象,组合,,和软件开发的二个重要过程,,软件工程的相关...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,089
精华内容 835
热门标签
关键字:

电脑记事本编程小游戏