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.程序运行时的目录定位方法。

  • 相关阅读:
    用 ArcMap 发布 ArcGIS Server FeatureServer Feature Access 服务 PostgreSQL 版本
    ArcMap 发布 ArcGIS Server OGC(WMSServer,MapServer)服务
    ArcScene 创建三维模型数据
    ArcMap 导入自定义样式Symbols
    ArcMap 导入 CGCS2000 线段数据
    ArcMap 导入 CGCS2000 点坐标数据
    ArcGis Server manager 忘记用户名和密码
    The view or its master was not found or no view engine supports the searched locations
    python小记(3)操作文件
    pytest(2) pytest与unittest的区别
  • 原文地址:https://www.cnblogs.com/javawebsoa/p/3049862.html
Copyright © 2011-2022 走看看