zoukankan      html  css  js  c++  java
  • 对象类[置顶] 游戏开发技术总结(经典之作)第六集 穿越丛林游戏角色的角色遮挡(前后关系)

    最近研究对象类,稍微总结一下,以后继续补充:

        

    6-1 任务

        
    1.学习C++“ 类”的创立和用使法方。
    2.在场景中入加风物。
    3.决解对象的互相遮挡关系。

        


    6-2 类文件

        


    6-2-1 建立类文件

        
            开打 VC 集成编程器。在菜单当选“file→new”进入建新文件。在Files 当选择“C++
    Source Files” 建立一个新的源文件(.cpp) ,注意输入文件名。按OK 键后,我们就到得
    了一个名为game.cpp 的一个空文件。

        对象和类

         

        
                                                             图6-1
    在game.cpp 中入加:

    #include "stdafx.h"
    #include "game.h"
    game::game() //构造函数
    {}
    game::~game() //析构函数
    {}

        

           样同开打VC 集成编程器。在菜单当选“file→new”进入建新文件。在Files 当选择
    “C/C++ Header Files”建立一个新的头文件(.h),注意输入文件名。按OK 键后,我们就
    到得了一个名为game.h 的一个空文件。

        对象和类

         

        
                                                      图6-2
    在game.h 中入加

    class game //类名
    {public:
    game(); //构造函数
    virtual~game();//析构函数
    public: //有公型类,外部可调用。
    ⋯⋯
    private: //私有型类,类部内用使。
    ⋯⋯
    protected: //掩护型类,派生类可调用。
    ⋯⋯
    };

        



    6-2-2 类文件的用使

        
           这样,一个类文件就建立好了,它当初可以正确地译编了。当然当初它是个空的
    类文件。
    面上我们以可就将后面做的能功函复制来过。这里作为例子,我们将后面的loadbmp
    (CString cc)调图片入加到这个类文件中。
    A.game.h 头文件
    在 game.h 头文件中入加函数的明说(见黑体字分部)。

    class game //类名
    {public:
    game(); //构造函数
    virtual~game();//析造函数
    public: //有公,外部可调用
    //定义类变量
    HBITMAP bitmap; //定义位图柄句
    int w,h; //对象图片宽、高
    //定义类函数
    loadbmp (CString cc); //调图片
    private: //私有,类部内用使
    };

        

     

        其中:
    public: 有公型类,引诱明说的变量、函数可以被类外的其它序程调用。
    private: 私有型类,引诱明说的变量、函数只能在类部内用使。
    protected:掩护型类,引诱明说的变量、函数可以在派生类中调用。
    B.game.cpp 类文件
    在 game.cpp 源文件中入加函数的主体(见黑体字分部)。

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

        

     

        照此法方,将后面其它几个能功函数入加到game 类中。
    C.类的用使
           类文件 game.cpp 中的能功函数在我们的序程的其它任何地方都可以方便地调用。
    法方如下:
    后面我们的序程主要是写在视图类 XXXXDlg.cpp 中的,当初我们在XXXXDlg.cpp 中
    调用game.cpp 中的能功函数。
    在 XXXXDlg.cpp 的头文件XXXXDlg.h 中定义类变量(见黑体字分部)。

    #include "game.h" // game 类的引用明说
    class CMyDlg : public CDialog
    { public:
    CMyDlg(CWnd* pParent = NULL); // standard constructor
    game m_game; // 定义对象变量( 调用名)
    ⋯⋯
    }

        

    在 XXXXDlg.cpp 的任何地方都可以用。
    m_game.loadbmp ("c:\0010.bmp"); //调用game.cpp 的能功函数。
    int Wie=m_game.w; //取game.cpp 中类变量的值。
    详细情况见本章例实“穿梭林丛”中的game.cpp 和game.h。

        


    6-2-3 初始化场景

        
           在这一章的第二个任务是要在场景中入加游戏角色之外的其它西东, 这里我们加
    入一棵树、一块石头。
    对象和类
                                    图6-3
    1.舆图文件*.dat
           在数据文件 game.dat 中布置了游戏角色、场景的初始数据。
    空中.BMP
    对象和类
    数据意思见下表。这些数据可所以直接在game.dat 中输入,也可所以游戏的舆图
    编辑器编辑的结果。
    背景名 空中.BMP
    对象数 3
    第0 个人 0, 0, 0, 1, 234, 260,
    第1 个树 1, 2, 0, 31, 269, 309,
    第2 个石 2, 2, 0, 8, 207, 255,
    结构量分名 jisu lb js p xix xiy
    中文明说 序号 类别 角色 形图号 坐标
    2.loadmap(⋯) 对象初始化
            我们在 game 类文件game.cpp 中建立一个loadmap(CString name) 对象初始化能功函数;读入dir 目录中game.data 数据,实现rs 个对象man[]的初始化。这是上一章已用过
    的读入外部文件的序程。

    loadmap(CString name) 对象初始化序程如下:
    //**************************************************
    // loadmap(CString name)// 对象初始化
    // 调入体例好的对象场景(.dat)
    // 场景文件(.dat)的式格:
    // 第1 行,为背景形图
    // 第2 行,对象数,面后一行是一个对象。
    // 序号,类别,角色,静物形图号,x,y 置位6 个数据
    //**************************************************
    void game::loadmap(CString name)//调舆图
    1{ FILE *f;
    2 f=fopen(name,"r");
    3 if(f==NULL){
    AfxMessageBox("没有舆图文件!!!");
    SetCurrentDirectory(appdir); //置前当目录
    return;}
    4 fscanf(f,"%s\n",mapbak); //读舆图块名
    5 fscanf(f,"%d\n",&rs); //读对象数
    6 if(rs>SU_LIANG){ //对象数大于设定值回返
    7 fclose(f);
    8 SetCurrentDirectory(appdir); //置前当目录
    9 return; }
    10 for (int i=0;i<rs;i++)
    11 {fscanf(f,"%d,",&man[i].jisu); //读序号
    12 fscanf(f,"%d,",&man[i].lb); //读类别: [0 人1 兽2 景]
    13 fscanf(f,"%d,",&man[i].js); //读角色:人[0 男1 女]
    // 兽[0 豹1 狼2 猪3 鹿4 马5 雀6 羊]
    14 fscanf(f,"%d,",&man[i].p); //读静物形图号
    15 fscanf(f,"%d,",&man[i].xix); //读前当置位x
    16 fscanf(f,"%d,",&man[i].xiy); //读前当置位y
    17 man[i].x0=man[i].xix; //设目标置位x
    18 man[i].y0=man[i].xiy; //设目标置位y
    19 man[i].fw=1; //设方位: [0 南1 西南⋯⋯]
    20 man[i].zs=0; //设作动:人[0 站1 走2 刺3 劈4 倒]
    // 兽[0 站1 走2 跑3 斗4 倒5 尸]
    21 man[i].pk =-1; //设径路长
    22 man[i].fid=-1; //设径路计数
    23 man[i].zd=0;
    24 if(man[i].lb!=2) setman(man[i].jisu); //置设活动对象值初
    25 getobjwh(i); //取对象的尺寸
    }
    26 fclose(f);
    27 SetCurrentDirectory(appdir); //置前当目录
    }

        

     

        第1~ 3 行,开打名为name 的舆图文件,犯错回返。
    第4 行,读舆图块名
    第 5 行,读对象数rs
    第 6~ 9 行,对象数大于设定值,闭关文件回返。
    第 10~25 行,读入rs 个对象的的特征值;其中第17~23 为行初始化数据,第25
    行取对象的尺寸。
    第 26 行,闭关文件
    第 27 行,置前当目录
    注意必须在 game.h 中入加函数loadmap(CString name)的定义。
    ⋯⋯
    public://有公,外部可调用
    void loadmap(CString name); //对象初始化
    ⋯⋯
    3.在主序程中入加对象初始化
          这样在 XXXXDlg.cpp 的BOOL CMyDlg::OnInitDialog()初始口入中入加以下语句就可对游戏的角色场景停止初始化了。
    //C.初始化类

    m_game.init();
    //D.对象初始化
    cc=m_game.appdir;
    if(cc.Right(8)=="运行序程")
    cc= "舆图/game0.dat";
    else cc="../运行序程/舆图/game0.dat"; //舆图(场景)文件径路
    m_game.loadmap(cc); //对象初始化
    //E.调入表现背景
    cc.Format("%s%s",m_game.dir,m_game.mapbak); // mapbak 在对象初始化中赋值
    m_game.loadbmp(cc); //调背景图片
    SelectObject(m_game.BkDC0,m_game.bitmap); //背景位图关联到背景备设场景

        




    6-2-4 多对象处置

        
             当初我们 游戏场景中已不只是一个对象了,树、石等也是对象,面后我们还要加
    入其它植物。所以当初在一个时钟期周里,表现的就是多个对象了( 在面后的例实中,
    我们将定义场景中可同时表现500 个对象)。为了简化OnTimer()中的代码复杂性,我们
    将一些能功整合在函数setobj(int q) 对象表现中,并将它也写在类文件game.cpp 里。
    1.setobj(int q) 对象表现

    //**************************************************
    // setobj(int q) 对象表现
    // 调入由man[q].lb 指出的不同的man[q].p 图片和偏移值。
    // 将对象q 在各自的前当置位(x,y)上以透明式方TransparentBlt2 表现。
    // 然后停止动移或方位换转的能功。
    // 为止防闪烁,全部对象先表当初暂存区BkDC1,一屏实现后再翻到转主屏上。
    //**************************************************
    void game::setobj(int q)//对象表现
    { CString cc;
    int x=man[q].xix-scrx-man[q].w/2; //x 前当置位
    int y=man[q].xiy-scry-man[q].h; //y 前当置位
    if(inscreer(q)) //对象q 在表现区才表现它
    {if(man[q].lb==0) {cc="人";}
    if(man[q].lb==1) {cc="兽";}
    if(man[q].lb==2) {cc="景";}
    if(getpic(cc,man[q].p)==FALSE) return; //调形图
    if(man[q].lb!=2) //角调色的偏移置位
    {int x0=0,y0=0;
    if(man[q].lb==0) {x0=rbufx[man[q].p];y0=rbufy[man[q].p];}
    if(man[q].lb==1) {x0=sbufx[man[q].p];y0=sbufy[man[q].p];}
    if(man[q].fw>4) x0=w-x0; //是西南、东、南东方位
    x=man[q].xix-scrx-x0;
    y=man[q].xiy-scry-y0;
    }
    TransparentBlt2(BkDC1,x,y,w,h,MemDC,0,0,w,h,RGB(255,255,255));
    mans++;
    }
    if(man[q].lb==2) return;
    else manmove(q); //活动对象的动移
    man[q].p++; //下一作动
    if(man[q].p>=man[q].m1) {bianfw(q);} //本作动实现,停止方位换转
    }

        

     

        2.修改主序程的对应处
    引入 setobj(int q) 对象表现后, 在OnTimer(⋯)中多对象(对象数为rs) 表现如下:

    void CMyDlg::OnTimer(UINT nIDEvent) //时钟函数,[类向导中定义生成]
    { CClientDC dc(this); //客户区备设环境
    BitBlt(m_game.BkDC1,0,0,rect.Width(),rect.Height(),
    m_game.BkDC0,0,0,SRCCOPY); //用舆图刷新Bk1
    for(int i=0;i<m_game.rs;i++)
    m_game.setobj(i); //对象表现
    BitBlt(dc.m_hDC,0,0,rect.Width(),rect.Height(),
    m_game.BkDC1,0,0,SRCCOPY); //将Bk1 的内容表当初前当窗口
    CDialog::OnTimer(nIDEvent);
    }

        

     

              由于是多对象表现,当初我们须要将按左键OnLButtonDown(… )略改一下;使按
    左键时只对游戏的配角起作用(这是我们这个游戏定义所要求的)。

    void CMyDlg::OnLButtonDown(UINT nFlags, CPoint point)
    { int x=point.x,y=point.y;
    for(int i=0;i<m_game.rs;i++)
    if(m_game.man[i].jisu==0) //只对配角
    {m_game.man[i].x0=x; //得获目标置位x
    m_game.man[i].y0=y; //得获目标置位y
    m_game.man[i].p=m_game.man[i].m1-1; //止中前当作动
    break;
    }
    CDialog::OnLButtonDown(nFlags, point);
    }

        



    6-3 对象遮挡

        
            决解对象 遮挡的法方有多种, 我们这里给出一种最单简但适用的法方。从面上程
    序看到, 我们是在一个循环中按对象的序号来表现对象的,必定就有先表现的内容要
    被面后的内容遮挡。人[0]先最表现,然后是树[1] , 石头[2]最后表现(见图6-4),结果
    是先表现的被后表现的遮住了。

        对象和类
                                      图6-4
           事实上,我们的游戏画面是上远、下近;Y 坐标是上小、下大。这里应该是人在树
    与石头之间,有人遮石,树遮人的景象现出。
    我们察观对象的表现置位:石头(207, 255)、树(269 , 309)、人(234, 260) 。
    从 Y 坐标看有:树(269, 309)>人(234, 260)>石(207, 255) 。
    这就给我们提示了一种决解问题的法方:我们在表现对象前,按对象前当表现位
    置的Y 坐标停止排序,使Y 坐标最小的对象,也就是远的对象先表现,这样以可就形
    成下遮上、近遮远的效果。好,面上我们来做一个按对象的表现置位Y 坐标排序的功
    能函数。

        



    6-3-1 冒泡法排序

        
            排序是序程中经常使用的法算。冒泡法是排序法算中最单简、最好懂得的一种。因为
    对游戏中几百个对象排序,排序法算的率效不很要重 (在我们这个游戏中也做到500 个
    对象,这是已不少的了) ,所以用冒泡法排序也就够了。
    面上是将 q 个对象序列对Y 置位停止排序的能功函数sort(int q),我们也把它写在
    game 类中。
    注:这是一个标准的冒泡法排序序程,在本例中的特殊点是比拟、交换的数据。

    //**********************************************************
    // sort() 排序(冒泡法)
    // 将rs 个对象序列对Y 置位停止排序,用于在表现时分出前后置位。
    //**********************************************************
    void game::sort()//排序(冒泡法)
    1{ MAN man0;
    2 for(int a=0;a<rs-1;a++)
    3 for(int b=a+1;b<rs;b++)
    4 if(man[a].xiy>man[b].xiy) //前数大于后数
    5 {man0=man[a]; //两数交换
    6 man[a]=man[b];
    7 man[b]=man0;
    8 } //排序结果,前当置位Y 小的在前。
    9 mans=0; //表现区对象数置0
    }

        

    样同在game.h 中要入加sort() 的定义。
    冒泡法排序的基本思想是:
    在第 2、3 行for 的双循环中停止排序。
    第 4 将行第一个数a=0 与面后的全部数停止比拟,如果大于某个数,就与它们的位
    置停止交换(5、6、7 行)。如果这个数是排序序列中的最大数,则交换的结果是它将沉
    到最底下(如果是小于比拟数,最小的数将冒到最面上,所以称冒泡法)。
    第一个数完后又将第二个数与面后的数样同处置,直到倒数第二个数q-1。我们这
    时交换的数不只是Y 坐标,而是对象的整个数据,好在VC++可以对结构停止单简的赋
    值运算(man[a]=man[b] 是 man[a] 的全部量分于等man[b]的对应量分)。
    排序结果是前当置位 Y 小的对象man[]在后面了。

        


    6-3-2 决解对象遮挡

        
           当初将 sort()排序入加到用于对象表现的时钟函数中。在表现前,先对对象置位的
    Y 坐标排序,让Y 坐标小的(远的、面上的)先表现。

    void CMyDlg::OnTimer(UINT nIDEvent) //时钟函数,[类向导中定义生成]
    { CClientDC dc(this); //客户区备设环境
    BitBlt(m_game.BkDC1,0,0,rect.Width(),rect.Height(),m_game.BkDC0,0,0,SRCCOPY);
    //用舆图刷新Bk1
    m_game.sort(); //对对象的Y 坐标排序
    for(int i=0;i<m_game.rs;i++)
    m_game.setobj(i); //对象表现
    BitBlt(dc.m_hDC,0,0,rect.Width(),rect.Height(),m_game.BkDC1,0,0,SRCCOPY);
    //将Bk1 的内容表当初前当窗口
    CDialog::OnTimer(nIDEvent);
    }

        

    结果为图6-5。所示画面上为人遮石、树遮人;但人只要再向下走, 就人遮树了。
    OK! 觉视上合符逻辑。
    对象和类
                                        图6-5

        


    6-4 游戏库类

        
            在这一章我们开始引入了 C++的库类,并将游戏的能功写在这个库类中。面后我们
    还要在库类中加增更多的能功。所以我们在这里列出这个库类的源序程game.cpp 和它
    的头文件game.h ,还有它引用的常数定义.h ,要注意它们的成组结构。

        


    6-4-1 game.cpp

        
           以下 game.cpp 是一个完全的序程,结构次序上是续连的。它包含了1 个常数定义
    和14 个能功函数。为了更清楚地示表这个序程,我们将它们开隔,加上了小标题(加
    灰的份部是本章未用的)。
    1.常数定义

    #include "stdafx.h"
    #include "game.h"
    JCDZ zjdz[6]={0,5,40,10,120,10,200,10,280,10,360,5};//人作动结构400 幅
    //0 站,1 走, 2 刺, 3 劈, 4 倒 5 尸
    JCDZ zjdw[6]={0,5,40,10,120,10,200,10,280,10,360,5};//兽作动结构400 幅
    //0 站,1 走, 2 跑, 3 斗, 4 倒, 5 尸
    unsigned short dw[7][6]={0,1,1,3,4,5, //0 豹,无跑
    0,1,2,3,4,5, //1 狼,
    0,1,1,3,4,5, //2 猪,无跑
    0,1,2,3,4,5, //3 鹿,
    0,2,2,2,4,5, //4 马,无走、斗
    0,1,1,1,4,5, //5 羊,无跑、斗
    0,1,1,3,4,5 //6 雀,无跑
    };
    game:: game(){} //构造函数
    game::~game(){} //析构函数

        

     

        2.init()初始化

    //****************************************************************
    // init() 初始化
    //1.建立形图处置环境
    // BkDC0-装载背景空中
    // BkDC1-在此生成即时场景,在1 个时钟期周后翻到转前当表现屏。
    // MemDC-调入的对象图片。
    //2.置设图片目录
    //3.初始一些变量
    //****************************************************************
    BOOL game::init()//初始化[6 章]
    {//1.建立形图处置环境
    hScrDC=CreateDC("DISPLAY", NULL, NULL, NULL); //创立幕屏备设场景
    BkDC0 =CreateCompatibleDC(hScrDC); //创立舆图备设场景
    BkDC1 =CreateCompatibleDC(hScrDC); //创立暂存备设场景
    bit0 =CreateCompatibleBitmap(hScrDC,WIDTH,HEIGHT);//创立暂存位图0
    bit1 =CreateCompatibleBitmap(hScrDC,WIDTH,HEIGHT);//创立暂存位图1
    SelectObject(BkDC1,bit1); //暂存位图1 与暂存备设关
    联
    OldMak=(HBITMAP)SelectObject(BkDC0,bit0); //暂存位图0 与舆图备设关
    联
    MemDC =CreateCompatibleDC(hScrDC); //创立对象备设场景
    //2.置设图片目录
    GetCurrentDirectory(256,appdir); //取前当目录
    dir=appdir;
    if(dir.Right(8)=="运行序程")
    dir="图片/";
    else dir="../运行序程/图片/"; //图片径路
    //3.初始一些变量
    sys=getsys(); //取前当系统,( Win2000 、
    Win98)
    scrx=0;scry=0; //
    rs=0; //对象数置0
    return TRUE;
    }

        


    3.exit()退出

    //**************************************************
    // exit() 退出, 删除形图处置环境
    //**************************************************
    void game::exit()//退出
    { DeleteObject(bit0); //删除暂存位图内存
    DeleteObject(bit1); //删除暂存位图内存
    DeleteDC(BkDC0); //删除舆图备设场景
    DeleteDC(BkDC1); //删除暂存备设场景
    DeleteDC(MemDC); //删除对象备设场景
    DeleteDC(hScrDC); //删除幕屏备设场景
    }
        每日一道理
    书籍好比一架梯子,它能引领人们登上文化的殿堂;书籍如同一把钥匙,它将帮助我们开启心灵的智慧之窗;书籍犹如一条小船,它会载着我们驶向知识的海洋。

        

    4.getsys()别识操作系统

    //****************************************************
    // getsys()//别识操作系统
    // 用使TransparentBlt()透明表现的须要;
    // 是WIN2000,直接调用TransparentBlt();
    // 否则调用自编的TransparentBlt2()。
    // 回返系统型类编号。
    //****************************************************
    int game::getsys()//别识操作系统
    { OSVERSIONINFO stOSVI ;
    ZeroMemory(&stOSVI , sizeof ( OSVERSIONINFO )) ;
    stOSVI.dwOSVersionInfoSize = sizeof ( OSVERSIONINFO ) ;
    GetVersionEx ( &stOSVI);
    int a=0;
    if (stOSVI.dwPlatformId==VER_PLATFORM_WIN32_WINDOWS
    &&(stOSVI.dwMajorVersion>4||(stOSVI.dwMajorVersion==4
    && stOSVI.dwMinorVersion>0)))
    a=1; // "Windows98";
    if (VER_PLATFORM_WIN32_NT==stOSVI.dwPlatformId&&stOSVI.dwMajorVersion>=5)
    a=2; // "Windows2000";
    if (VER_PLATFORM_WIN32_NT==stOSVI.dwPlatformId&&stOSVI.dwMajorVersion==4)
    a=3; // "WindowsNT4.0";
    if (VER_PLATFORM_WIN32_NT==stOSVI.dwPlatformId)
    a=4; // "WindowsNT";
    return a;
    }

        

    5.inscreer(int i)判断在表现区

    //**********************************************************
    // inscreer(int i)在表现区?
    // 判断对象是不是在表现区
    //**********************************************************
    BOOL game::inscreer(int i)//在表现区?
    { int xs=man[i].xix-scrx-man[i].w/2; //x 前当置位
    int ys=man[i].xiy-scry-man[i].h; //y 前当置位
    if(xs>(-man[i].w+2)&&xs<WIDTH&&ys>(-man[i].h+10)&&ys<HEIGHT)
    return TRUE;
    else return FALSE;
    }

        

    6.sort() 排序(冒泡法)

    //**********************************************************
    // sort() 排序(冒泡法)
    // 将rs 个对象序列对Y 置位停止排序;用于在表现时分出前后置位。
    //**********************************************************
    void game::sort()//排序(冒泡法)
    { MAN man0;
    for(int a=0;a<rs-1;a++)
    for(int b=a+1;b<rs;b++)
    if(man[a].xiy>man[b].xiy)//前数大于后数
    {man0=man[a]; //两数交换
    man[a]=man[b];
    man[b]=man0;
    } //排序结果,前当置位Y 小的在前。
    mans=0; //表现区对象数置0
    }

        

    7.getobjwh(int q) 取对象的尺寸

    //**************************************************
    // getobjwh(int q) 取对象的尺寸
    // 取序号q 对象的尺寸(宽man[q].w 高man[q].h)。
    //**************************************************
    void game::getobjwh(int q)//取对象的尺寸
    { CString cc;
    if(man[q].lb==0) {cc="人";}
    if(man[q].lb==1) {cc="兽";}
    if(man[q].lb==2) {cc="景";}
    if(getpic(cc,man[q].p)==FALSE) return;
    man[q].w=w; man[q].h=h; //对象的尺寸
    }

        

    8.TransparentBlt2 (......)透明表现

    //**************************************************
    // TransparentBlt2 (......)透明表现
    // 根据关键色,将hdc1 中的形图在hdc0 中自动生成掩模,并生成透明形图。
    //**************************************************
    void game::TransparentBlt2( HDC hdc0,// 目标DC
    int nX0,int nY0,// 目标偏移
    int nW0,int nH0,// 目标宽高度
    HDC hdc1, // 源DC
    int nX1,int nY1,// 源起点
    int nW1,int nH1,// 源宽高度
    UINT Tcol // 透明色,COLORREF 型类
    ) //透明表现 [4 章]
    {//A.建立形图资源。
    HBITMAP hBMP =CreateCompatibleBitmap(hdc0,nW0, nH0); //创立位图内存
    HBITMAP mBMP =CreateBitmap(nW0,nH0,1,1,NULL); //创立单色掩码位图
    HDC hDC =CreateCompatibleDC(hdc0); //创立备设场景
    HDC mDC =CreateCompatibleDC(hdc0); //创立备设场景
    HBITMAP oldBMP =(HBITMAP)SelectObject(hDC, hBMP);
    HBITMAP oldmBMP=(HBITMAP)SelectObject(mDC, mBMP);
    //B.拷贝或压缩拷贝源DC 中的位图到临时hDC 中。
    if (nW0==nW1&&nH0==nH1) //源DC 宽、高与目标DC 一致
    BitBlt(hDC,0,0,nW0,nH0,hdc1,nX1,nY1,SRCCOPY);
    //将源DC 的位图拷贝到临时hDC 中
    else //源DC 宽、高与目标DC 不一致
    StretchBlt(hDC,0,0,nW0,nH0,hdc1,nX1,nY1,nW1,nH1,SRCCOPY);
    // 将源DC 中的位图拷贝到临时hDC 中
    //C.生成掩码位图。
    SetBkColor(hDC, Tcol); // 置设透明色
    BitBlt(mDC,0,0,nW0,nH0,hDC,0,0,SRCCOPY);//生成白色透明区,其它区为黑色的掩码
    图
    SetBkColor(hDC, RGB(0,0,0)); //生成黑色透明区,其它区域保持不变的
    图
    SetTextColor(hDC, RGB(255,255,255)); // 白色
    BitBlt(hDC,0,0,nW0,nH0,mDC,0,0,SRCAND);
    SetBkColor(hdc0,RGB(255,255,255)); //透明分部保持幕屏不变,其它变成黑色
    SetTextColor(hdc0,RGB(0,0,0)); // 黑色
    //D.透明表现
    BitBlt(hdc0,nX0,nY0,nW0,nH0,mDC,0,0,SRCAND); //“与”运算,在hdc0 生成掩模洞
    BitBlt(hdc0,nX0,nY0,nW0,nH0,hDC,0,0,SRCPAINT);//“或”运算,生成最终透明效果
    //E.释放形图资源
    SelectObject(hDC, oldBMP);
    DeleteDC(hDC);
    SelectObject(mDC, oldmBMP);
    DeleteDC(mDC);
    DeleteObject(hBMP);
    DeleteObject(mBMP);
    }

        

    9. setman(int q) 置设活动对象值初

    //**************************************************
    // setman(int q) 置设活动对象值初
    // 由给定的对象、方位、作动计算出形图的置位和数量。
    //**************************************************
    void game::setman(int q)//置设活动对象值初
    { int a=400;
    if(man[q].lb==0) //是人
    {man[q].m0=man[q].js*a+zjdz[man[q].zs].qi
    +man[q].fw*zjdz[man[q].zs].bc; //置位值初
    man[q].m1=zjdz[man[q].zs].bc+man[q].m0; //置位终值
    man[q].p=man[q].m0; //数量计数
    }
    if(man[q].lb==1) //是兽
    {man[q].m0=man[q].js*a+zjdw[man[q].zs].qi
    +man[q].fw*zjdw[man[q].zs].bc; //置位值初
    man[q].m1=zjdw[man[q].zs].bc+man[q].m0; //置位终值
    man[q].p=man[q].m0; //数量计数
    }
    man[q].zd=0;
    }

        

    10.manmove(int i)活动对象的动移

    //**************************************************
    // manmove(int i) 活动对象的动移
    // 由前当、目标置位的差,计算前当置位向不同方位的改变。
    //**************************************************
    void game::manmove(int i)//活动对象的动移
    { if(man[i].lb==2) return; //是静物回返
    int stx,sty,qx,qy;
    switch(man[i].zs)
    {case 2: {stx=9;sty=6;break;} //跑步长
    case 1: {stx=4;sty=2;break;} //走步长
    default:{stx=2;sty=1;break;}
    }
    qx=man[i].x0-man[i].xix; //x 前当、目标置位差
    qy=man[i].y0-man[i].xiy; //y 前当、目标置位差
    if (qx==0&&qy==0) return ; //到达回返
    int qxa=abs(qx); //x 置位差绝对值
    int qya=abs(qy); //y 置位差绝对值
    if(qxa<stx) stx=qxa; //置位差不足步长,步长为差
    if(qya<sty) sty=qya; //
    if(qx!=0) man[i].xix+=qxa/qx*stx; //前当置位加步长
    if(qy!=0) man[i].xiy+=qya/qy*sty; //[qya/qy]单位绝对值
    }

        

    11.bianfw(int q)方位换转

    //**************************************************
    // bianfw(int q)//方位换转
    // 由前当、目标置位的差,计算活动形图的方向取向。
    //**************************************************
    void game::bianfw(int q)//方位换转
    { int qx=man[q].x0-man[q].xix; //x 前当目标置位差
    int qy=man[q].y0-man[q].xiy; //y 前当目标置位差
    if(qx==0&&qy==0)
    {if(man[q].zd==0) man[q].zs=0; //为0,作动为站,方位保留
    goto aa;
    }
    if(man[q].zd==0) //没打
    {int a=rand()%2+1; //随机产生走、跑
    if(man[q].lb==0) man[q].zs=1; //是人设为走
    if(man[q].lb==1) man[q].zs=dw[man[q].js][a];//是兽
    }
    if(qx<0&&qy>0) {man[q].fw=1;goto aa;} //取西南向
    if(qx<0&&qy<0) {man[q].fw=3;goto aa;} //取西北向
    if(qx>0&&qy<0) {man[q].fw=5;goto aa;} //取西南向
    if(qx>0&&qy>0) {man[q].fw=7;goto aa;} //取南东向
    if (qy>0) {man[q].fw=0;goto aa;} //取南向
    if(qx<0) {man[q].fw=2;goto aa;} //取西向
    if (qy<0) {man[q].fw=4;goto aa;} //取北向
    if(qx>0) {man[q].fw=6;goto aa;} //取东向
    aa: setman(q); //置设活动对象值初
    if(man[q].zs==0)
    man[q].p=man[q].p+rand()%3; //避免作动一致
    }

        

    12.loadmap(CString name) 对象初始化

    //**************************************************
    // loadmap(CString name)//对象初始化
    // 调入体例好的对象场景(.dat)
    // 场景文件(.dat)的式格:
    // 第1 行,为背景形图
    // 第2 行,对象数,面后一行是一个对象。
    // 序号、类别、角色、静物形图号x,y 置位6 个数据
    //**************************************************
    void game::loadmap(CString name)//调舆图
    { FILE *f;
    f=fopen(name,"r");
    if(f==NULL)
    {AfxMessageBox("没有舆图文件!!!");
    SetCurrentDirectory(appdir); //置前当目录
    return;
    }
    fscanf(f,"%s\n",mapbak); //读舆图块名
    fscanf(f,"%d\n",&rs); //读对象数
    if(rs>SU_LIANG) //对象数大于设定值回返
    {fclose(f);
    SetCurrentDirectory(appdir); //置前当目录
    return;
    }
    for (int i=0;i<rs;i++)
    {fscanf(f,"%d,",&man[i].jisu); //读序号
    fscanf(f,"%d,",&man[i].lb); //读类别:[0 人1 兽2 景]
    fscanf(f,"%d,",&man[i].js); //读角色:人[0 男1 女]
    // 兽[0 豹1 狼2 猪3 鹿4 马5 雀6 羊]
    fscanf(f,"%d,",&man[i].p); //读静物形图号
    fscanf(f,"%d,",&man[i].xix); //读前当置位x
    fscanf(f,"%d,",&man[i].xiy); //读前当置位y
    man[i].x0=man[i].xix; //设目标置位x
    man[i].y0=man[i].xiy; //设目标置位y
    man[i].fw=1; //设方位:[0 南1 西南2 西3 西北⋯]
    man[i].zs=0; //设作动:人[0 站1 走2 刺3 劈4 倒]
    // 兽[0 站1 走2 跑3 斗4 倒5 尸]
    man[i].pk =-1; //设径路长
    man[i].fid=-1; //设径路计数
    man[i].zd=0;
    if(man[i].lb!=2)
    setman(man[i].jisu); //置设活动对象值初
    getobjwh(i); //取对象的尺寸
    }
    fclose(f);
    SetCurrentDirectory(appdir); //置前当目录
    }

        

    13.getpic(CString cc,int p) 调图片到相干位图

    //**************************************************
    // getpic(CString cc,int p) 调图片到相干位图
    // 由p 到得将调的形图文件名。
    // 在指定目录中调入形图到相干位图bit
    //**************************************************
    BOOL game::getpic(CString cc,int p)//调图片到相干位图
    { char name[256];
    if(stmp==NULL) //没有压缩资源
    {SetCurrentDirectory(appdir); //置前当目录
    //A.调cc 指定的形图
    sprintf(name,"%s%s/c%05d.bmp",dir,cc,p); //生成将调的形图文件名
    if(!loadbmp(name)) return FALSE; //调BMP 图片
    SelectObject(MemDC,bitmap);
    //B.调cc 指定的形图的偏移值。
    sprintf(name,"%s%s/c%05d.txt",dir,cc,p);
    FILE *f;
    f=fopen(name,"r");
    if(f!=NULL)
    {if(cc=="人") fscanf(f,"%d,%d",&rbufx[p],&rbufy[p]); //人的偏移量
    if(cc=="兽") fscanf(f,"%d,%d",&sbufx[p],&sbufy[p]); //兽的偏移量
    fclose(f);
    return TRUE;
    }
    }
    else
    {if(getpic0(cc,p)) return TRUE; //调压缩图片。
    else return FALSE;
    }
    }

        

    14.loadbmp(CString cc) 调BMP 图片

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

        

    15.setobj(int q) 对象表现

    //**************************************************
    // setobj(int q) 对象表现
    // 调入由man[q].lb 指出的、不同的man[q].p 图片和偏移值。
    // 将对象q 在各自的前当置位(x,y)上以透明式方TransparentBlt2 表现。
    // 然后停止动移或方位换转的能功。
    // 为止防闪烁,全部对象先表当初暂存区BkDC1,一屏实现后再翻到转主屏上。
    //**************************************************
    void game::setobj(int q)//对象表现
    { CString cc;
    int x=man[q].xix-scrx-man[q].w/2; //x 前当置位
    int y=man[q].xiy-scry-man[q].h; //y 前当置位
    if(inscreer(q))//在表现区?
    {if(man[q].lb==0) {cc="人";}
    if(man[q].lb==1) {cc="兽";}
    if(man[q].lb==2) {cc="景";}
    if(getpic(cc,man[q].p)==FALSE) return;
    if(man[q].lb!=2)//角调色的偏移置位
    {int x0=0,y0=0;
    if(man[q].lb==0) {x0=rbufx[man[q].p];y0=rbufy[man[q].p];}
    if(man[q].lb==1) {x0=sbufx[man[q].p];y0=sbufy[man[q].p];}
    if(man[q].fw>4) x0=w-x0; //是西南、东、南东方位
    x=man[q].xix-scrx-x0;
    y=man[q].xiy-scry-y0;
    }
    TransparentBlt2(BkDC1,x,y,w,h,MemDC,0,0,w,h,RGB(255,255,255));
    mans++;
    }
    if(man[q].lb==2) return;
    else manmove(q); //活动对象的动移
    man[q].p++; //下一作动
    if(man[q].p>=man[q].m1) {bianfw(q);} //本作动实现,停止方位换转
    }

        



    6-4-2 game.h

        
           以下 game.h 结构在次序上是续连的。为了更清楚地示表,我们将它们隔断,并加
    上了小标题(加灰的份部是本章未用的)。
    1.定义结构

    #include "常数定义.h"
    //定义结构
    typedef struct
    { short int x;
    short int y;
    } PATHN;//搜索整理径路
    typedef struct
    { short int qi; //作动起点
    short int bc; //作动步数
    } JCDZ; //人或兽的作动结构
    typedef struct
    { short int jisu; //序号
    short int xix,xiy;//角色坐标
    short int x0,y0; //目标置位
    short int w,h; //对象尺寸
    short int lb; //类别: [0 人1 兽2 景]
    short int p; //计数
    //以下人、植物用使
    short int m0,m1; //置位值初、终值
    short int zs; //作动:人[0 站1 走2 刺3 劈4 倒]
    // 兽[0 站1 走2 跑3 斗4 倒5 尸]
    short int js; //角色:人[0 男1 女]
    // 兽[0 豹1 狼2 猪3 鹿4 马5 雀6 羊]
    short int fw; //方位:[0 南1 西南2 西3 西北4 北5 西南6 东7 南东]
    short int zd; //前当状态[0,1 打斗]
    //以下搜索用使
    PATHN ph[250];//搜索的径路
    short int pk; //径路长
    short int fid; //径路计数
    short int fx,fy; //保留目标点
    } MAN; //对象结构

        

    2.定义类
    //定义类

    class game
    {public: game(); //构造函数
    virtual~game(); //析构函数

        

    3.定义变量
    //变量定义

    public://有公,外部可调用
    MAN man[SU_LIANG]; //定义对象变量,数量为SU_LIANG
    HDC BkDC0; //舆图备设场景
    HDC BkDC1; //暂存备设场景
    HDC MemDC; //对象备设场景
    HBITMAP OldMak;
    HDC hScrDC; //幕屏备设场景
    HBITMAP bitmap; //舆图位图内存
    CString dir; //数据径路
    short int rs; //前当对象数
    short int scrx,scry; //舆图动移量
    CString mapbak; //舆图块名
    int w,h; //对象图片宽、高
    char appdir[256]; //前当目录
    short int mans; //表现区对象数
    short int sbufx [SBUF]; //兽的偏移量x
    short int sbufy [SBUF]; //兽的偏移量y
    short int rbufx [RBUF]; //人的偏移量x
    short int rbufy [RBUF]; //人的偏移量y
    private://私有,类部内用使
    HBITMAP bit0; //暂存位图内存
    HBITMAP bit1; //暂存位图内存
    short int sys; //前当运行系统

        

    4.定义函数
    //函数定义

    public://有公,外部可调用。
    BOOL init(); //初始化
    void exit(); //退出
    void loadmap(CString name); //对象初始化
    BOOL getpic(CString cc,int p); //调图片到相干位图
    BOOL loadbmp(CString cc); //调BMP 图片
    void setobj (int q); //对象表现
    void setman (int q); //置设活动对象值初
    void getobjwh(int q); //取对象的尺寸
    void sort(); //排序(冒泡法)
    void TransparentBlt2(HDC hdc0, //目标DC
    int nX0,int nY0,int nW0,int nH0,//目标左坐标,目标宽高宽
    HDC hdc1, //源DC
    int nX1,int nY1,int nW1,int nH1,//源起点坐标,源宽高宽
    UINT Tcol); //透明表现
    private://私有,类部内用使
    BOOL inscreer(int i); //在表现区?
    int getsys(); //别识系统
    void bianfw (int q); //方位换转
    void manmove(int i); //活动对象的动移

        
     

        


    6-4-3 常数定义.h

        
           在这里我们定义了游戏库类 game 要用到的常数,以及一些API 函数必需的头文件
    定义和LIB 连接库。

    #include <mmsystem.h>
    #pragma comment (lib,"winmm.lib") //时间函数库
    #include <wingdi.h>
    #pragma comment (lib,"gdi32.lib") //形图库
    #pragma comment (lib,"msimg32.lib")//透明表现库
    #include <vfw.h>
    #pragma comment (lib,"vfw32.lib") //
    //定义常数
    #define SU_LIANG 500 //定义对象数
    #define TIMER 150 //主时钟期周
    #define WIDTH 640 //游戏表现区宽
    #define HEIGHT 480 //游戏表现区高
    #define SCRWI 800 //序程界面宽
    #define SCRHE 600 //序程界面高
    #define GX 40 //舆图格宽
    #define GY 30 //舆图格高
    #define SCRP 12 //舆图最大为表现区的12 倍
    #define SBUF 2801 //兽最大数
    #define RBUF 801 //人最大数
    #define JBUF 100 //景最大数

        

    更详细的源序程请见本章例实:“穿梭林丛”。

        


    6-5 小结

        
    在这一章里,我们学了以下知识和法方:
    1.类文件和建立类文件的法方。
    2.类文件的用使法方。
    3.调入场景文件,初始化场景。
    4.冒泡法排序。
    5.用冒泡法排序决解对象遮挡。
    6.适用的无闪烁刷屏法方。
    7.入加了对象表现的校正值,使对象的表现不再跳动。

    文章结束给大家分享下程序员的一些笑话语录: Bphone之你们聊,我先走了!移动说:我在phone前加o,我叫o缝;苹果说:我在phone前i,我是i缝;微软说:我在phone前加w,我叫w缝;三星说:你们聊,我先走了!
    将来王建宙写回忆录的时候,一定要有一句“常小兵为中国移动的发展做出了不可磨灭的贡献”。

  • 相关阅读:
    VMware设置共享文件夹
    非奇异阵
    ICP算法使用遇到的问题
    osgEarth编译的一些问题
    [OpenCV](1)安装与测试
    [PCL]1 PCL点云库安装
    【转载】:【C++跨平台系列】解决STL的max()与numeric_limits::max()和VC6 min/max 宏冲突问题
    matlab将多条曲线绘制在一起
    C++问题
    SLAM学习笔记(3)相关概念
  • 原文地址:https://www.cnblogs.com/jiangu66/p/3063557.html
Copyright © 2011-2022 走看看