您的位置:首页 > 编程语言 > C语言/C++

基于MFC框架的C++游戏开发(四)键盘响应和鼠标响应

2017-12-20 17:54 441 查看
本系列文章由七十一雾央编写,转载请注明出处。

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

// ChildView.h : CChildView 类的接口  
//  
  
  
#pragma once  
  
  
// CChildView 窗口  
  
class CChildView : public CWnd  
{  
// 构造  
public:  
    CChildView();  
  
// 特性  
public:  
    CRect m_client;    //保存客户区大小  
    CRect m_heroPos;    //保存英雄的位置  
    CImage m_hero;   //英雄  
    CImage m_bg;      //背景图片  
// 操作  
public:  
  
// 重写  
    protected:  
    virtual BOOL PreCreateWindow(CREATESTRUCT& cs);  
  
// 实现  
public:  
    virtual ~CChildView();  
  
    // 生成的消息映射函数  
protected:  
    afx_msg void OnPaint();  
    DECLARE_MESSAGE_MAP()  
public:  
    afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);  
    afx_msg void OnLButtonDown(UINT nFlags, CPoint point);  
};  

    然后是CPP文件

[cpp]
view plain
copy

// ChildView.cpp : CChildView 类的实现  
//  
  
#include "stdafx.h"  
#include "GameMFC.h"  
#include "ChildView.h"  
  
#ifdef _DEBUG  
#define new DEBUG_NEW  
#endif  
  
  
// CChildView  
  
CChildView::CChildView()  
{  
}  
  
CChildView::~CChildView()  
{  
}  
  
  
BEGIN_MESSAGE_MAP(CChildView, CWnd)  
    ON_WM_PAINT()  
    ON_WM_KEYDOWN()  
    ON_WM_LBUTTONDOWN()  
END_MESSAGE_MAP()  
  
  
//将png贴图透明  
void TransparentPNG(CImage *png)  
{  
    for(int i = 0; i <png->GetWidth(); i++)  
    {  
        for(int j = 0; j <png->GetHeight(); j++)  
        {  
            unsigned char* pucColor = reinterpret_cast<unsigned char *>(png->GetPixelAddress(i , j));  
            pucColor[0] = pucColor[0] * pucColor[3] / 255;  
            pucColor[1] = pucColor[1] * pucColor[3] / 255;  
            pucColor[2] = pucColor[2] * pucColor[3] / 255;  
        }  
    }  
}  
  
// CChildView 消息处理程序  
  
BOOL CChildView::PreCreateWindow(CREATESTRUCT& cs)   
{  
    if (!CWnd::PreCreateWindow(cs))  
        return FALSE;  
  
    cs.dwExStyle |= WS_EX_CLIENTEDGE;  
    cs.style &= ~WS_BORDER;  
    cs.lpszClass = AfxRegisterWndClass(CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS,   
        ::LoadCursor(NULL, IDC_ARROW), reinterpret_cast<HBRUSH>(COLOR_WINDOW+1), NULL);  
  
    //加载背景  
    m_bg.Load("bg.png");  
  
    //加载英雄图片  
    m_hero.Load("hero.png");  
    TransparentPNG(&m_hero);  
  
    //设置英雄初始位置  
    m_heroPos.left=100;    //人物左边贴在100的位置  
    m_heroPos.right=100+60; //人物的右边等于左边加上人物的宽度  
    m_heroPos.top=400;  
    m_heroPos.bottom=400+60;  
  
    return TRUE;  
}  
  
void CChildView::OnPaint()   
{  
    //获取窗口DC指针  
    CDC *cDC=this->GetDC();  
    //获取窗口大小  
    GetClientRect(&m_client);  
    //贴背景  
    m_bg.Draw(*cDC,m_client);  
    //贴英雄  
    m_hero.Draw(*cDC,m_heroPos);  
  
    //释放DC  
    ReleaseDC(cDC);  
}  
  
//按键响应函数  
void CChildView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)  
{  
    //nChar表示按下的键值  
    switch(nChar)  
    {  
    case 'd':         //游戏中按下的键当然应该不区分大小写了  
    case 'D':  
        m_heroPos.left+=10;    //向右移动10个像素的单位  
        m_heroPos.right+=10;   //左边和右边都要移动哦  
        break;  
    case 'a':  
    case 'A':  
        m_heroPos.left-=10;  
        m_heroPos.right-=10;  
        break;  
    case 'w':  
    case 'W':  
        m_heroPos.top-=10;  
        m_heroPos.bottom-=10;  
        break;  
    case 's':  
    case 'S':  
        m_heroPos.top+=10;  
        m_heroPos.bottom+=10;  
        break;  
    }  
}  
  
//鼠标左键单击响应函数  
void CChildView::OnLButtonDown(UINT nFlags, CPoint point)  
{  
    m_heroPos.left=point.x;  
    m_heroPos.right=m_heroPos.left+60;  
    m_heroPos.top=point.y;  
    m_heroPos.bottom=m_heroPos.top+60;  
}  

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

        对于文章的疏漏或错误,欢迎大家的指出。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  MFC与C++ c语言