《MFC游戏开发》笔记四 键盘响应和鼠标响应:让人物动起来

本系列文章由七十一雾央编写,转载请注明出处。

http://blog.csdn.net/u011371356/article/details/9327377

作者:七十一雾央 新浪微博:http://weibo.com/1689160943/profile?rightmod=1&wvr=5&mod=personinfo



        这篇文章里有一个问题,可能会使一些同学感到困惑:在大家进行键盘操作后,改变了人物的位置,但是并没有刷新画面,按道理来说应该是看到不到人物的位置改变的(大家看到的还是之前的画面),但是由于雾央在绘图OnPaint中漏掉了一句代码ValidateRect(&m_client);缺少它会导致系统一直产生WM_PAINT消息,也就是会一直调用OnPaint函数,所以大家操作后立马就看到了人物的移动,详细的解释我写在了笔记五 定时器和简单动画。 雾央感到很抱歉,但是这里并不影响大家学习键盘响应和鼠标响应,这部分的知识是没有问题的。

                                                                                                                                     by雾央 2013.7.15 



        在上一节笔记里,我们讲解了贴图的透明效果的实现,使得画面变得美观起来,但是大家也知道,游戏还有一个非常重要的部分:交互性。大家在玩游戏的时候,按下键盘,点击鼠标,游戏中的人物都会根据自己的操作而做出不同的行为,或者走动,或者攻击,或者释放技能,这些都是通过键盘响应和鼠标响应来实现的,通过学习今天的内容,大家就可以让自己的程序中人物接收指令,动起来了。

       好了,就让我们开始今天的学习吧。

 

一、键盘响应

       

        1.键盘消息

        当我们在键盘上进行了操作后,那么系统便会接收到对应的键盘消息,下面我们列出最常用的2种键盘消息:

         WM_KEYDOWN 按下按键的消息

         WM_KEYUP 松开按键消息

        当某一按键被按下时,伴随着这个操作所产生的是WM_KEYDOWN,当松开时产生WM_KEYUP消息。当程序接收到这些消息时。便可由虚拟键码的信息来得知是哪个按键被按下。

       2.添加键盘响应函数

       MFC不仅仅只是一个封装好WIN32 API的框架,它还提供了很多工具,来实现可视化的开发,减少程序员的工作量,比如添加键盘响应程序我们就可以通过“类向导“来进行。

      大家点击VS2010菜单栏上的 项目->类向导 即可打开类向导。

      大家需要注意的是“类型“这一栏里要选择CChildView,其他的默认就好。我们需要添加键盘处理消息,所以要选择”消息“,雾央已经用红色框出来了。在消息中大家搜索到WM_KEYDOWN后,双击它就可以添加进消息了,然后点确就可以了。


      完成上述步骤后,大家会发现在CChildView.cpp中已经多出了一段函数名为

void  CChildView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)的代码

      大家把函数里面的内容可以都删掉,我们会自己写处理程序。

      我先解释一下这两个函数的参数意义:

      UINT nChar 指定特定键的虚键控代码。大家是不是很疑惑,我们收到按键消息后,怎么知道是哪个键被按下了呢?答案就是nChar这个参数了。大家如果按下了某个字母键,那么nChar存储的就是这个字母键的ASCII码,如果是上下左右键呢,那么就分别是VK_LEFT,VK_RIGHT,VK_UP,VK_DOWN这几个宏了。其他的键游戏中使用不多,我就不多说了,若有需要,大家百度“按键的虚拟值“即可查到。

     UINT nRepCnt,保存了键被重击的次数。

     UINT nFlags ,定扫描代码,键转换代码,前一个关键状态。

     后两个大家可以先不用关心,很少用到。

 

      我们现在想要实现的是按下WSAD键,人物就会分别往上下左右移动,这个要怎么实现呢?大家思考一下就会清楚,我们只要在要移动到的位置重新把人物贴出来,他不就移动过去了吗?

      要达到这样的效果,我们就不能再把贴图函数的坐标写成数值形式了,我们可以用变量保存人物的位置,在按下WSAD键后,改变人物的位置就可以了,具体代码请见最后,雾央对每一句都加上了注释,这里先给大家看一下效果图,呵呵。


      向右上移动n步后

 

二、鼠标响应

       

        在游戏中,鼠标的作用可以使控制人物的行走,与NPC对话,购买东西等,鼠标增加了游戏操作的很多灵活性,是很多游戏都不可缺少的部分,接下来我们就讲解一下鼠标响应。

        其实大家如果弄懂了键盘响应后,鼠标响应非常简单。鼠标的消息有下面这些种

WM_LBUTTONDBLCLK 双击鼠标左键消息

WM_LBUTTONDOWN 单击鼠标左键消息

WM_LBUTTONUP 松开鼠标左键消息

WM_MBUTTONDBLCLK 双击鼠标中键(滚轮)消息

WM_MBUTTONDOWN 单击鼠标中键(滚轮)消息

WM_MBUTTONUP 松开鼠标中键(滚轮)消息

WM_RBUTTONDBLCLK 双击鼠标右键消息

WM_RBUTTONDOWN 单击鼠标右键消息

WM_RBUTTONUP 松开鼠标右键消息

WM_MOUSEMOVE 鼠标移动消息

WM_MOUSEWHEEL 鼠标滚轮转动消息

       大家需要处理什么样的消息,在类向导中添加它就可以了。


        我们以鼠标左键单击消息处理为例,它添加的函数有两个参数

        参数一:nFlags

        指示是否各种虚拟键是否被按下。这个参数可以是任何以下值的组合:

MK_CONTROL 如果Ctrl键按下时设置这个标志。

MK_LBUTTON 如果鼠标左键按下时设置这个标志。

MK_MBUTTON 如果鼠标中键按下时设置这个标志。

MK_RBUTTON 如果鼠标右键按下时设置这个标志。

MK_SHIFT 如果Shift键按下时设置这个标志。


        这个大家也可以不用管,在我们的教程中几乎用不到。


       参数二:CPoint point

      大家查看CPoint类型就可以发现,它包含两个成员变量x和y,就分别是鼠标的位置了,注意是相对于窗口左上角的,我想大家都知道程序中窗口的左上角是(0,0)点,向右为x正方向,向下为y正方向吧。

       我们的程序就设定为点击鼠标左键后,将人物的左上角移动到鼠标的位置。  

 

三、源代码

 

       大家如果有什么不清楚的地方可以看源代码,我尽量详细的添加了注释,大家如果有什么疑问可以留言。大家如果需要运行的直接复制进大家建的工程中就可以运行了,注意在工程下要放入图片,要不然会出错的哦。我使用的是相对路径,所以大家应该把图片放在工程文件夹下。

       首先是头文件

[cpp]  view plain copy
  1. // ChildView.h : CChildView 类的接口  
  2. //  
  3.   
  4.   
  5. #pragma once  
  6.   
  7.   
  8. // CChildView 窗口  
  9.   
  10. class CChildView : public CWnd  
  11. {  
  12. // 构造  
  13. public:  
  14.     CChildView();  
  15.   
  16. // 特性  
  17. public:  
  18.     CRect m_client;    //保存客户区大小  
  19.     CRect m_heroPos;    //保存英雄的位置  
  20.     CImage m_hero;   //英雄  
  21.     CImage m_bg;      //背景图片  
  22. // 操作  
  23. public:  
  24.   
  25. // 重写  
  26.     protected:  
  27.     virtual BOOL PreCreateWindow(CREATESTRUCT& cs);  
  28.   
  29. // 实现  
  30. public:  
  31.     virtual ~CChildView();  
  32.   
  33.     // 生成的消息映射函数  
  34. protected:  
  35.     afx_msg void OnPaint();  
  36.     DECLARE_MESSAGE_MAP()  
  37. public:  
  38.     afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);  
  39.     afx_msg void OnLButtonDown(UINT nFlags, CPoint point);  
  40. };  
    然后是CPP文件

[cpp]  view plain copy
  1. // ChildView.cpp : CChildView 类的实现  
  2. //  
  3.   
  4. #include "stdafx.h"  
  5. #include "GameMFC.h"  
  6. #include "ChildView.h"  
  7.   
  8. #ifdef _DEBUG  
  9. #define new DEBUG_NEW  
  10. #endif  
  11.   
  12.   
  13. // CChildView  
  14.   
  15. CChildView::CChildView()  
  16. {  
  17. }  
  18.   
  19. CChildView::~CChildView()  
  20. {  
  21. }  
  22.   
  23.   
  24. BEGIN_MESSAGE_MAP(CChildView, CWnd)  
  25.     ON_WM_PAINT()  
  26.     ON_WM_KEYDOWN()  
  27.     ON_WM_LBUTTONDOWN()  
  28. END_MESSAGE_MAP()  
  29.   
  30.   
  31. //将png贴图透明  
  32. void TransparentPNG(CImage *png)  
  33. {  
  34.     for(int i = 0; i <png->GetWidth(); i++)  
  35.     {  
  36.         for(int j = 0; j <png->GetHeight(); j++)  
  37.         {  
  38.             unsigned char* pucColor = reinterpret_cast<unsigned char *>(png->GetPixelAddress(i , j));  
  39.             pucColor[0] = pucColor[0] * pucColor[3] / 255;  
  40.             pucColor[1] = pucColor[1] * pucColor[3] / 255;  
  41.             pucColor[2] = pucColor[2] * pucColor[3] / 255;  
  42.         }  
  43.     }  
  44. }  
  45.   
  46. // CChildView 消息处理程序  
  47.   
  48. BOOL CChildView::PreCreateWindow(CREATESTRUCT& cs)   
  49. {  
  50.     if (!CWnd::PreCreateWindow(cs))  
  51.         return FALSE;  
  52.   
  53.     cs.dwExStyle |= WS_EX_CLIENTEDGE;  
  54.     cs.style &= ~WS_BORDER;  
  55.     cs.lpszClass = AfxRegisterWndClass(CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS,   
  56.         ::LoadCursor(NULL, IDC_ARROW), reinterpret_cast<HBRUSH>(COLOR_WINDOW+1), NULL);  
  57.   
  58.     //加载背景  
  59.     m_bg.Load("bg.png");  
  60.   
  61.     //加载英雄图片  
  62.     m_hero.Load("hero.png");  
  63.     TransparentPNG(&m_hero);  
  64.   
  65.     //设置英雄初始位置  
  66.     m_heroPos.left=100;    //人物左边贴在100的位置  
  67.     m_heroPos.right=100+60; //人物的右边等于左边加上人物的宽度  
  68.     m_heroPos.top=400;  
  69.     m_heroPos.bottom=400+60;  
  70.   
  71.     return TRUE;  
  72. }  
  73.   
  74. void CChildView::OnPaint()   
  75. {  
  76.     //获取窗口DC指针  
  77.     CDC *cDC=this->GetDC();  
  78.     //获取窗口大小  
  79.     GetClientRect(&m_client);  
  80.     //贴背景  
  81.     m_bg.Draw(*cDC,m_client);  
  82.     //贴英雄  
  83.     m_hero.Draw(*cDC,m_heroPos);  
  84.   
  85.     //释放DC  
  86.     ReleaseDC(cDC);  
  87. }  
  88.   
  89. //按键响应函数  
  90. void CChildView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)  
  91. {  
  92.     //nChar表示按下的键值  
  93.     switch(nChar)  
  94.     {  
  95.     case 'd':         //游戏中按下的键当然应该不区分大小写了  
  96.     case 'D':  
  97.         m_heroPos.left+=10;    //向右移动10个像素的单位  
  98.         m_heroPos.right+=10;   //左边和右边都要移动哦  
  99.         break;  
  100.     case 'a':  
  101.     case 'A':  
  102.         m_heroPos.left-=10;  
  103.         m_heroPos.right-=10;  
  104.         break;  
  105.     case 'w':  
  106.     case 'W':  
  107.         m_heroPos.top-=10;  
  108.         m_heroPos.bottom-=10;  
  109.         break;  
  110.     case 's':  
  111.     case 'S':  
  112.         m_heroPos.top+=10;  
  113.         m_heroPos.bottom+=10;  
  114.         break;  
  115.     }  
  116. }  
  117.   
  118. //鼠标左键单击响应函数  
  119. void CChildView::OnLButtonDown(UINT nFlags, CPoint point)  
  120. {  
  121.     m_heroPos.left=point.x;  
  122.     m_heroPos.right=m_heroPos.left+60;  
  123.     m_heroPos.top=point.y;  
  124.     m_heroPos.bottom=m_heroPos.top+60;  
  125. }  


       《MFC游戏开发》笔记四到这里就结束了,更多精彩请关注下一篇。如果您觉得文章对您有帮助的话,请留下您的评论,点个赞,能看到你们的留言是我最高兴的事情,因为这让我知道我正在帮助曾和我一样迷茫的少年,你们的支持就是我继续写下去的动力,愿我们一起学习,共同努力,复兴国产游戏。

        对于文章的疏漏或错误,欢迎大家的指出。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值