zoukankan      html  css  js  c++  java
  • [置顶] 游戏开发技术总结(经典之作)第三集 让图片动起来快速切换图形实现动画

    游戏开发技术总结(经典之作)第三集 让图片动起来----快速切换图形实现动画

    转载请注明出处

     作者:孙广东 个人主页:http://blog.csdn.net/u010019717

    更多精彩内容见:http://passport.baidu.com/business&un=a1224708372&fr=prin#7

    3-1 任务


           我们这里将利用VC 的时钟消息函数,在屏幕上显示变换的图形,由此形成动画的
    效果。


    3-2 建立时钟消息


           在 VC 编程环境中选择菜单View 下的“ ClassWizard”项,进入MFC 的类向导(MFC
    ClassWizard) 。


                                                            图3-1
           在类向导中选择WM_TIMER, 双击后,在成员功能栏(Member functions)可以看到已生
    成的时钟消息函数ON_WM_TIMER。再按编辑代码(Edit Code), 就进入到时钟消息函数
    OnTimer()中了。


    void CMyDlg::OnTimer(UINT nIDEvent) //时钟函数,[类向导中定义生成]
    {
    CDialog::OnTimer(nIDEvent);
    }



    在程序中我们只要执行命令SetTimer(1,150,NULL),在程序运行期间每隔150 毫秒,
    时钟消息函数OnTimer()中的程序就会被执行一次。
    SetTimer 参数说明:
    SetTimer(1, 150, NULL);
    设定时器(第1 个定时器, 间隔时间(毫秒), 空值);


    3-3 让角色动起来


           我们在时钟消息里面写上图形显示的程序,图形就可以快速地变化了。当然你要
    调入的图形是变化的,而要调入的图形变化,只要调入的图形文件名变化就行了。


    3-3-1 变化的文件名


            如果图形文件在 C 盘的game 目录下,并且文件名为“b0p.bmp”,我们要给出的文
    件名格式就应该为“c:/game/b0p.bmp”。其中p 是顺序变化的。

                                                      图 3-2
            在C++语言中我们可以用sprintf(cc,"c:/game/b%02d.bmp", p); 来设置图形文件名。cc
    是字符串型变量,springf 是字符格式化函数,它可以将其它数据类型的值转换为字符串。
    注意,引号内的写法 %02d,“%”的意义是转换的数p 是整形数,其中“2”的意义
    是转换后的字串是两位,“0”的意义是数字不足两位时前面用“ 0”补位。
    如 p=2, 执行sprintf(cc,"c:/game/b%02d.bmp", p);后。
    cc 的值就是“c:/game/b02.bmp”。
    如 p=12, 执行sprintf(cc,"c:/game/b%02d.bmp", p);后。
    cc 的值就是“c:/game/b12.bmp”。
    为了使用方便,这里我们把动态获取将调用的图形文件名也写成一个功能函数
    getpic(⋯)。


    3-3-2 getpic(⋯)调图片到相关位图


     

    //**************************************************
    // getpic(CString cc,int p) 调图片到相关位图
    // 由p 得到将调的图形文件名。
    // 在指定目录中调入图形到相关位图bit
    //**************************************************
    BOOL getpic(CString cc,int p)//调图片到相关位图[2 章]
    { char name[256];
    SetCurrentDirectory(appdir); //置当前目录
    sprintf(name,"%s%s/c%05d.bmp",dir,cc,p);//生成将调的图形文件名
    loadbmp(name); //调BMP 图片
    return TRUE;
    }



    这个函数的功能是:根据输入的目录名cc 和图形编号p,生成将调用的图形文
    件名。
    例如:dir = “图形/”,cc =“人” ,p =15;
    则:name=“图形/人/00015.bmp” ;
    接着就将调入 loadbmp(“图形/人/00015.bmp”) 图片到bit 中。
    好了,我们可以将前面的调入图形文件和显示图形的代码写入时钟消息OnTimer()
    中(程序中的行号是为了便于注释加的)。


    3-3-3 可以动了


    设定:p=0;m0=0; m1=400;dir="c:/game/";
    现在,程序每隔150 毫秒, 时钟消息函数OnTimer()中的程序就会被执行一次。

    void CMyDlg::OnTimer(UINT nIDEvent) //时钟函数,[类向导中定义生成]
    1{ CClientDC dc(this); //客户区设备环境
    2 if(getpic("人",p)==FALSE) //调角色图片
    3 {AfxMessageBox(cc+"没找到!");return;}
    4 SelectObject(MemDC,bit); //设备相关位图关联到暂存设备场景
    5 BitBlt(dc.m_hDC,200,160,w,h,MemDC,0,0,SRCCOPY);//显示游戏角色
    6 p++; //下一动作
    7 if(p>m1) p=m0; //若动作完成,重复。
    CDialog::OnTimer(nIDEvent);
    }



    当第一次执行时,p=0;
    第 2 行,调入"c:/game/人/c00000.bmp"到bit。
    第 4 行,将目录bit 内容调入并关联到MemDC 中。
    第 5 行,将MemDC 中的图形拷贝到当前显示区在屏幕上显示。
    第 6 行,p 加1,变成了1。
    第二次执行时,p=1;
    程序将目录 c:/game/人/下名为"c00001.bmp"图片内容在屏幕上显示。
    第 n 次执行时, p=n-1;
    程序将目录 c:/game/人/下名为"c0000p.bmp"图片内容在屏幕上显示。
    每次在第 7 行判断p 是否达到m1(=400)的值,若达到,p=m0(=0); 从头开始。
    如此400 幅动作不同的图片在屏幕上循环显示,一个活生生的人物就出现了。


    3-3-4 OnOK()启动时钟


             现在我们还有一个事,在OnOK()中写入时钟消息函数的启动程序。

    void CMyDlg::OnOK() //确定键,[类向导中定义生成]
    { GetDlgItem(IDC_EDIT1)→ShowWindow(SW_HIDE);//隐藏文本框
    CClientDC dc(this); //客户区设备环境
    GetWindowRect(rect); //取当前窗口尺寸
    BitBlt(dc.m_hDC,0,0,rect.Width(),rect.Height(),MemDC,0,0,SRCCOPY);
    //将背景拷贝到当前屏幕
    //启动时钟
    SetTimer(1,150,NULL); //设定时器150 毫秒
    }



            现在程序运行后,只要一按“确定键”,程序首先将背景拷贝到当前屏幕,然后启
    动时钟,活动的人就在屏幕上出现了。


    3-4 窗口、控件的基本操作


           在程序的界面设计中,我们常需要对窗口和各种控件的大小、位置进行控制。
    VC++对窗口、各种控件的一些基本操作命令如下:
    GetDlgItem(IDC_EDIT1)→EnableWindow(FALSE); //控件失效、有效TRUE
    GetDlgItem(IDC_LIST1)→ShowWindow(SW_HIDE); //控件隐藏、显示SW_SHOW
    GetDlgItem(IDC_EDIT1)→SetWindowText(“cc”); //控件上显示cc 字串
    GetDlgItem(IDCANCEL)→MoveWindow( x,y,w,h,TRUE); //控件大小、定位
    SetDlgItemText(IDC_STATIC0, "cc"); //控件上显示cc 字串
    GetDlgItemText(IDC_STATIC0, "cc"); //取控件上文字到字串cc
    MoveWindow(x,y,w,h); //当前窗口定位
    CenterWindow(); //当前窗口居中
    例如:SetDlgItemText(IDC_EDIT1,cc) 将字符串cc 显示在编辑框“ IDC_EDIT1”上。
    例如:MoveWindow(0,0,640,480); 当前窗口大小、定位。
    例如:CenterWindow(); 当前窗口居中。
    例如:GetDlgItem(IDOK)→MoveWindow(580,0,55,18,TRUE)
    确定按钮控件“IDOK”的大小(w=55,h=18)、定位(x=580,y=0)。
    为了给读者一个对程序的完整的认识 ,下面我们给出这一章的全部程序和注释。
    在这一章我们编的程序只在“让我动吧Dlg.cpp”这一个文件中。


    3-5 “让我动吧 Dlg.cpp”完整的程序和注释


    3-5-1 全局定义


    注,灰色部份为MFC 自动产生的。

    #include "stdafx.h"
    #include "让我动吧.h"
    #include "让我动吧Dlg.h"
    #ifdef _DEBUG
    #define new DEBUG_NEW
    #undef THIS_FILE
    static char THIS_FILE[] = __FILE__;
    #endif
    /////////////////////////////////////////////
    // 全局变量定义
    /////////////////////////////////////////////
    HBITMAP bit; //设备相关位图
    HDC MemDC; //角色设备场景
    int w,h; //图形尺寸
    CString dir; //定义路径变量
    CString cc; //公用变量
    char appdir[256]; //当前目录
    CRect rect; //定义窗口尺寸变量
    int js; //角色[0 男,1 女]
    int fw; //方位[0 南1 西南2 西3 西北4 北5 东北6 东7 东南]
    int m0; //动画初值
    int m1; //动画终值
    int p; //当前图形序号
    ////////////////////////////////////////////
    // 函数定义
    ////////////////////////////////////////////
    BOOL getpic(CString cc,int p); //调图片到相关位图
    BOOL loadbmp(CString cc); //调BMP 图片
    


    3-5-2 程序的初始入口


     

    CMyDlg::CMyDlg(CWnd* pParent /*=NULL*/)//[MFC 自动生成]
    : CDialog(CMyDlg::IDD, pParent)
    {⋯⋯}
    void CMyDlg::DoDataExchange(CDataExchange* pDX)//[MFC 自动生成]
    {⋯⋯}
    BEGIN_MESSAGE_MAP(CMyDlg, CDialog)//[MFC 自动生成]
    ⋯⋯
    END_MESSAGE_MAP()
    BOOL CMyDlg::OnInitDialog()//对话框程序的初始入口,[MFC 自动产生]
    {CDialog::OnInitDialog();
    SetIcon(m_hIcon, TRUE); // Set big icon
    SetIcon(m_hIcon, FALSE); // Set small icon
    // TODO: Add extra initialization here
    //A.显示说明信息
    CString cc;
    cc="\r\n 这是《学VC 编游戏》的第二个示例:\r\n\r\n";
    cc+=" 在这一章我们使用了以下知识、技术\r\n";
    cc+="1.介绍计算机动画的基本知识和实现方法\r\n";
    cc+="2.在VC++中建立时钟消息,使用时钟消息产生动画。\r\n";
    cc+="3. 介绍格式化函数springf()的用法。由此动态地获取图形文件名。\r\n";
    cc+="4.介绍在VC++中窗口、控件大小控制和定位的方法。\r\n";
    SetDlgItemText(IDC_EDIT1,cc);
    //B.窗口定位
    MoveWindow(0,0,640,480); //窗口定位
    CenterWindow(); //居中窗口
    GetDlgItem(IDOK)→MoveWindow(640-60,0,55,18,TRUE);//确定按钮控件位置
    //C.建立图形环境
    MemDC =CreateCompatibleDC(0); //创建设备场景
    //D.设主角数据
    js=0; //角色,0 号人物
    fw=0; //方位,0 南
    m0=js*400+fw*4; //初值,0 号人物首位置
    m1=(js+1)*400-1; //终值,1 号人物首位置
    p=m0; //当前图形序号
    //E.设置路径
    GetCurrentDirectory(256,appdir); //取当前目录
    dir=appdir;
    if(dir.Right(8)=="运行程序")
    dir="图片/";
    else dir="../运行程序/图片/"; //图片路径
    //F.调入显示背景
    loadbmp(dir+"地面.BMP"); //调背景图片
    SelectObject(MemDC,bit); //调入位图关联到地图设备场景
    //G.在背景上显示文字
    SetTextColor(MemDC,RGB(255,255,255)); //设置地图设备场景字色
    SetBkMode(MemDC,TRANSPARENT); //字为透明方式
    cc="嘿嘿!我可以动了!!走走、跑跑,世间真美好!!!"; //设文字内容
    TextOut(MemDC,150,100,cc,lstrlen(cc)); //在MemDC 显示文字
    SetTextColor(MemDC,RGB(255,255,255)); //设置地图设备场景字色
    cc="不对呀,弄个框框把我笼起? 放开我 !!!"; //
    TextOut(MemDC,150,220,cc,lstrlen(cc)); //在MemDC 显示文字
    cc="BMP 图片本身就是矩形的,图片的底色是白色。";
    TextOut(MemDC,151,250,cc,lstrlen(cc)); //在MemDC 显示文字
    return TRUE;
    }
    

    3-5-3 OnOK()确定键


     

    void CMyDlg::OnPaint() //[MFC 自动生成]
    {⋯⋯
    }
    HCURSOR CMyDlg::OnQueryDragIcon()//[MFC 自动生成]
    {⋯⋯
    }
    void CMyDlg::OnOK() //确定键,[类向导中定义生成]
    {GetDlgItem(IDC_EDIT1)→ShowWindow(SW_HIDE);//隐藏文本框
    CClientDC dc(this); //客户区设备环境
    GetWindowRect(rect); //取当前窗口尺寸
    BitBlt(dc.m_hDC,0,0,rect.Width(),rect.Height(),MemDC,0,0,SRCCOPY);
    //启动时钟
    SetTimer(1,150,NULL); //设定时器150 毫秒
    }


     

    3-5-4 OnCancel()退出程序


     

    void CMyDlg::OnCancel() //退出,[类向导中定义生成] 
    
    { 
    
    DeleteDC(MemDC); //删除暂存设备场景 
    
    DeleteObject(bit); //删除暂存设备相关位图
    
    CDialog::OnCancel(); 
    
    }
    


     

    3-5-5 时钟函数


     

    void CMyDlg::OnTimer(UINT nIDEvent) //时钟函数,[类向导中定义生成]
    { CClientDC dc(this); //客户区设备环境
    if(getpic("人",p)==FALSE) //调角色图片
    {AfxMessageBox(cc+"没找到!");return;}
    SelectObject(MemDC,bit); //设备相关位图关联到暂存设备场景
    BitBlt(dc.m_hDC,200,160,w,h,MemDC,0,0,SRCCOPY); //显示游戏角色
    p++; //下一动作
    if(p>m1) p=m0; //若动作完成,重复。
    CDialog::OnTimer(nIDEvent);
    }


     


    3-5-6 调图片到相关位图


     

    //**************************************************
    // getpic(CString cc,int p) 调图片到相关位图
    // 由p 得到将调的图形文件名。
    // 在指定目录中调入图形到相关位图bit
    //**************************************************
    BOOL getpic(CString cc,int p)//调图片到相关位图
    { char name[256];
    SetCurrentDirectory(appdir); //置当前目录
    sprintf(name,"%s%s/c%05d.bmp",dir,cc,p); //生成将调的图形文件名
    loadbmp(name); //调BMP 图片
    return TRUE;
    }


     


    3-5-7 调BMP 图片


     

    //**************************************************
    // loadbmp(CString cc)//调BMP 图片
    // 调cc 指定的图形;取得的图形在设备相关位图bit 中
    // 图形的宽、高存于全局变量w,h 中
    //**************************************************
    BOOL loadbmp(CString cc)//调BMP 图片
    { DeleteObject(bit); //删除上次的位图内存。
    bit=(HBITMAP)LoadImage //调入cc 指定的图形
    (AfxGetInstanceHandle(),//
    cc, //文件名
    IMAGE_BITMAP, //位图方式
    0, //图形宽
    0, //图形高
    LR_LOADFROMFILE|LR_CREATEDIBSECTION//方式
    );
    if(bit==NULL) return FALSE; //调图失败
    DIBSECTION ds; //
    BITMAPINFOHEADER &bm = ds.dsBmih; //
    GetObject(bit,sizeof(ds),&ds); //取位图的信息→bminfo
    w = bm.biWidth; //得到位图宽度值
    h = bm.biHeight; //得到位图高度值
    return TRUE;
    }
    


     

    3-6 有关程序运行时的目录


    注意,在OnInitDialog()中设置路径一段程序的作用(行号是为了说明加上的)。

    //E.设置路径
    1 GetCurrentDirectory(256,appdir); //取当前目录
    2 dir=appdir;
    3 if(dir.Right(8)=="运行程序")
    4 dir="图片/"; //图片路径
    5 else dir="../运行程序/图片/"; //图片路径



    第 1 行,是一个Windows 的API 函数调用,是将当前程序运行的目录取到字符数组
    变量appdir 中。
    第 2 行,将当前目录赋于字符串变量dir。因为字符串变量支持我们下面要用到的
    一些灵活的操作。
    第 3 行,如果dir 后边8 个字符(4 个汉字)是“运行程序”,
    则第4 行dir="图片/";
    否则第5 行dir="../运行程序/图片/";
    第3~5 行算法的意义是:我们整个教学范例的运行程序,都集中放在与各个范例
    源程序同等的目录“ 运行程序”下的,而所有动画图片都在目录“运行程序”的下级
    目录“图片”下;即在与源程序同级目录“运行程序/图片/”下的。(见图3-3)


                                                           图3-3
           当程序直接在VC 中编译运行时,当前目录为范例源程序目录( 如本例是“ 02.让我
    动吧”这个目录)。按第3 行判断不是“运行程序”目录,所以取图片的目录就应该是
    dir="../运行程序/图片/",即上一级目录下的“运行程序/图片/”。
    如果在“ 运行程序”下执行程序“02.让我动吧.exe”;当前目录就是"运行程序",所
    以取图片的目录就应该是dir="图片/"。即本级目录下的"图片/"。
    这样做的作用是,无论是在VC 中直接编译运行程序,还是在目录“运行程序”下
    运行程序,都可以准确地取图片所在的目录。
    好了,现在可以编译运行这个程序了。


    3-7 流程图


           程序流程主要分三块:程序开始执行时的初始化, 按键后设置参数和启动时钟函
    数,由时钟函数和调图形函数构成的程序主循环。注意,我们下面对游戏的进一步编
    程主要是在这个主循环中进行的。


                                                        图3-4 主流程图
    具体的程序请看本章实例程序:“让我动吧”。


    3-8 小结


    在这一章里我们学了以下知识和方法。
    1.介绍计算机动画的基本知识和实现方法
    2.在VC++中建立时钟消息,使用时钟消息产生动画。
    3.介绍格式化函数sprintf()的用法。由此动态地获取图形文件名。
    4.介绍在VC++中窗口、控件大小控制和定位的方法。
    5.程序运行时的目录定位方法。

  • 相关阅读:
    Does Spring Framework support Reactive @Transaction?
    How to explain the 'WebFlux' by analogy with 'Sports' ?
    Atom 插件推荐
    PC端页面适应不同的分辨率的方法 (转载)
    JS
    JS
    apicloud
    PHP
    CSS
    屏幕适配
  • 原文地址:https://www.cnblogs.com/javawebsoa/p/3049862.html
Copyright © 2011-2022 走看看