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

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

 

    

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缝;三星说:你们聊,我先走了!
将来王建宙写回忆录的时候,一定要有一句“常小兵为中国移动的发展做出了不可磨灭的贡献”。

posted @ 2013-05-06 20:19  坚固66  阅读(309)  评论(0编辑  收藏  举报