用mfc实现人物动画效果失败了

我想在MFC中创建一个动画人物,实现简单的行走,但是失败了。想问一下大家究竟是哪里出了问题。
这是人物类的头文件

#pragma once
class CMyRole
{
public:
    HBITMAP m_hBmp;//创建位图句柄,保存移动的位图
    //每帧位图的宽高
    int m_iPerFrameWidth;//每帧位图的宽高
    int m_iPerFrameHeight; 
    int m_iPosX, m_iPosY;//坐标
    int m_iSpeedX, m_iSpeedY;//水平竖直方向的速度
    int m_iFrameNum;//帧数
    int m_iCurFrame;//当前帧号
    int m_iDirection;//移动方向
    //上up为,0,下down为1,Left-2,right-3
public:
    int GetPosX() { return m_iPosX; }
    int GetPosY() { return m_iPosY; }
    void SetSpeedX(int iSpeedX) { m_iSpeedX = iSpeedX; }
    void SetSpeedY(int iSpeedY) { m_iSpeedY = iSpeedY; }
    void SetDirection(int iDirection) {
        m_iDirection = iDirection;
    }
    void Draw(HDC hDC, int x, int y);//位图绘图
    void Update();//位图更新 人物移动过程中位图要进行更新
    void Init(  UINT uiID, int iPerFrameWidth, int  iPerFrameHeight,
        int iFrameNum, int  iPosX =0,int iPosY =0);//位图初始化
public:
    CMyRole();
    ~CMyRole();
    
};

人物类的源文件


```c++
#include "pch.h"
#include "CMyRole.h"
CMyRole::CMyRole()
{

}
CMyRole::~CMyRole()
{

}
//位图初始化
void CMyRole:: Init(UINT uiID, int iPerFrameWidth, int  iPerFrameHeight,
    int iFrameNum, int  iPosX , int iPosY )
{
    m_hBmp = (HBITMAP)::LoadImage(::GetModuleHandle(NULL), (LPCSTR)uiID,
        IMAGE_BITMAP, 0, 0, NULL);
    m_iPerFrameWidth = iPerFrameWidth;
    m_iPerFrameHeight = iPerFrameHeight;
    m_iPosX = iPosX;
    m_iPosY = iPosY;
    m_iSpeedX = 0;
    m_iSpeedY = 0;
    m_iCurFrame = 0;
    //开始运动时方向向下
    m_iDirection = 1;

}
//更新人物位置信息
void CMyRole::Update()
{
    m_iPosX = m_iPosX + m_iSpeedX;
    m_iPosY = m_iPosY + m_iSpeedY;

}
void CMyRole::Draw(HDC hDC, int x, int y)
{   //创建兼容DC
    HDC hBufDC = ::CreateCompatibleDC(hDC);
    ::SelectObject(hBufDC, m_hBmp);
    ::TransparentBlt(hDC, x, y, m_iPerFrameWidth, m_iPerFrameWidth, hBufDC,
        m_iDirection * m_iPerFrameWidth, m_iCurFrame * m_iPerFrameHeight, m_iPerFrameWidth,
        m_iPerFrameWidth, RGB(225, 225, 225));

    m_iCurFrame = (m_iCurFrame + 1) % m_iFrameNum;
    ::DeleteDC(hBufDC);
        
}

这是在对话框类中的部分代码

```c++

//添加人物
void CFamousPersonDlg::OnAdd()
{
    // TODO: 在此添加命令处理程序代码
    // TODO: 在此添加命令处理程序代码
    
    
    ::SetTimer(this->m_hWnd,10, 40, NULL);//10为定时器的ID,定时器要响应
    //WM_TIMER消息响应 
    Init();
    
}
//WM_TIMER消息响应 
void CFamousPersonDlg::OnTimer(UINT_PTR nIDEvent)//传入的参数为定时器ID
{
    switch (nIDEvent)
    {
        
    case 10: {
        //更新调用 
        update();
        Paint(); }
    default: {break; }
    }
    CDialogEx::OnTimer(nIDEvent);
}
//鼠标一直按下处理函数,重新绘制背景和角色
void CFamousPersonDlg::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
    // TODO: 在此添加消息处理程序代码和/或调用默认值
    //初始速度设为0
    m_MyRole.SetSpeedX(0);
    m_MyRole.SetSpeedY(0);
    if ('W' == nChar)
    {
        m_MyRole.SetSpeedY(-5);
        m_MyRole.SetDirection(0);
    }
    else if ('S' == nChar)
    {
        m_MyRole.SetSpeedY(5);
        m_MyRole.SetDirection(1);
    }
    else if ('A' == nChar)
    {
        m_MyRole.SetSpeedX(-5);
        m_MyRole.SetDirection(2);

    }
    else if ('D' == nChar)
    {
        m_MyRole.SetSpeedX(5);
        m_MyRole.SetDirection(3);

    }
    

    CDialogEx::OnKeyDown(nChar, nRepCnt, nFlags);
}

//鼠标左键函数
void CFamousPersonDlg::OnLButtonDown(UINT nFlags, CPoint point)
{
    // TODO: 在此添加消息处理程序代码和/或调用默认值
    //开始键,打开提示
    if (point.x >= 28 && point.x <= 202 && point.y >= 483 && point.y <= 643) {
        
            HDC hDC = ::GetDC(this->m_hWnd);
            HBITMAP hBmp = (HBITMAP)::LoadImage(::GetModuleHandle(NULL), (LPCSTR)IDB_BITMAP6, IMAGE_BITMAP, 0, 0, NULL);
            HDC hMDC = ::CreateCompatibleDC(hDC);
            ::SelectObject(hMDC, hBmp);
            ::BitBlt(hDC, 0, 0, 1044, 800, hMDC, 0, 0, SRCCOPY);
            ::DeleteDC(hMDC);
            ::ReleaseDC(this->m_hWnd, hDC);
        
        
    }
    //音乐键
    if (point.x >= 671 && point.x <= 842 && point.y >= 485 && point.y <= 656) {
        
        PlaySound(TEXT("C:\\背景音乐.wav"), NULL, SND_FILENAME | SND_ASYNC);
    }
    //游戏开始
    if (point.x >= 290 && point.x <= 544 && point.y >= 538 && point.y <= 652) {
        PaintBG(0, 0);
    }

    CDialogEx::OnLButtonDown(nFlags, point);
}
//画背景
void CFamousPersonDlg::PaintBG(int x, int y)
{

    HDC hDC = ::GetDC(this->m_hWnd);
    HBITMAP hBmp = (HBITMAP)::LoadImage(::GetModuleHandle(NULL), (LPCSTR)IDB_BITMAP2, IMAGE_BITMAP, 0, 0, NULL);
    HDC hMDC = ::CreateCompatibleDC(hDC);
    ::SelectObject(hMDC, hBmp);
    ::BitBlt(hDC, x, y,1044,800,hMDC,0,0,SRCCOPY);
    ::DeleteDC(hMDC);
    ::ReleaseDC(this->m_hWnd, hDC);
    
}
//画静态人物
void CFamousPersonDlg::PaintRole(int x, int y)
{
    
    HDC hDC = ::GetDC(this->m_hWnd);
    HBITMAP hBmp = (HBITMAP)::LoadImage(::GetModuleHandle(NULL), (LPCSTR)IDB_BITMAP3, IMAGE_BITMAP, 0, 0, NULL);
    HDC hMDC = ::CreateCompatibleDC(hDC);
    ::SelectObject(hMDC, hBmp);
     ::TransparentBlt(hDC,x,y, 80, 106, hMDC, 0, 0, 80, 110, RGB(0, 0, 0));
    //::BitBlt(hDC, x, y, 794, 551, hMDC, 0, 0, SRCCOPY);
    ::DeleteDC(hMDC);
    ::ReleaseDC(this->m_hWnd, hDC);
}
//人物开始运动
void CFamousPersonDlg::OnLookfor()
{
    // TODO: 在此添加命令处理程序代码
    //设置定时器
    CFamousPersonDlg::Init();
    ::SetTimer(this->m_hWnd, 10, 40, NULL);
}
//数据更新函数
void CFamousPersonDlg::update()
{
    m_MyRole.Update();
}


//人物初始化
void  CFamousPersonDlg::Init()
{
    m_MyRole.Init(IDB_BITMAP8, 80,106, 3, 430, 260);//最后两个参数为初始位置 ,倒数第三个参数是帧数
}
//绘制人物
void CFamousPersonDlg::Paint() {
    //每次调用都绘制背景和人物
    HDC hDC = ::GetDC(this->m_hWnd);
    PaintBG(0, 0);
    //绘制人物 
    m_MyRole.Draw(hDC, m_MyRole.GetPosX(), m_MyRole.GetPosY());
    ::ReleaseDC(this->m_hWnd,hDC);
}


这是人物图,即代码中的位图8.

img

感谢大家。

重绘时候有调用Invalidate()或者UpdateWindow()吗,而且绘图要放在OnPaint()里吧

  • 这有个类似的问题, 你可以参考下: https://ask.csdn.net/questions/168211
  • 这篇博客你也可以参考下:MFC 使窗口最大化,不能改变大小,只能移动和最小化
  • 除此之外, 这篇博客: MFC笔记(一):一个对话框类调用(访问)另一个对话框类的成员变量中的 MFC笔记(一):一个对话框类调用(访问)另一个对话框类的成员变量 部分也许能够解决你的问题, 你可以仔细阅读以下内容或跳转源博客中阅读:
  • MFC中一个对话框类CDailog1要访问另外一个对话框类CDailog2对象的成员变量,这就需要获得对话框类CDailog2的对象的指针,有好几种方法可以实现,如维护一个单例模式、设置静态变量等。

    本文设置以静态变量的方法为例,实现对两个对话框之间数据访问。

    一、创建MFC对话框程序

    1.首先创建一个MFC对话框应用程序,命名为Test工程.
    2.对话框本身有一个主界面(CTestDlg对话框),那我们再添加一个新界面CXXXDlg.
    3.在主对话框(CTestDlg)上添加一个picture控件 ,对应变量名为ImageShowRect。

    二、在CTestDlg.h文件中,添加对话框指针变量的声明

    static CTestDlg *pTestdlg;

    三、在CTestDlg .cpp文件中,写上一行初始化代码,直接初始化为空

    CTestDlg *CTestDlg::pTestdlg = NULL;  //注意要写在类外,不要写在类实现函数里面。
    

    注意:
    由于这个指针是静态的,我们需要在类外初始化。

    四、然后要在CTestDlg.cpp文件的OnInitDialog()函数里面写上如下一句代码

    pTestdlg = this;  //为这个之前定义的指针变量赋值为主对话框指针

    *说明:
    现在我们只要在其他的类里面获得这个静态指针,就可以访问这个类里面的所有数据了~~~~*

    五、获得静态指针

    假设,我们想在CXXXDlg类中访问CTestDlg类的m_ImageShowRect变量,只需要在CXXXDlg.cpp文件的具体某个功能的实现函数中添加如下代码

    void  CXXXDlg::showimage()
    {
    CTestDlg *pdlg = CTestDlg::pTestdlg ;
    pdlg->m_ImageShowRect.GetClientRect(&clRect);
    ...
    ...
    }

    说明:
    m_ImageShowRect为主对话框TestDlg中picture控件的捆绑变量。

    End!

  • 您还可以看一下 胡兵老师的MFC开发简单聊天程序课程中的 解决接收字符串不完整小节, 巩固相关知识点