先说一下代码风格,大家都说看不懂,这就对了。整套代码约有3000行,并不都是针对这个游戏写的。我想把代码写成一个容易扩展、容易维护、功能全面的“框架”,需要什么功能,就从这个框架中取出相应功能,如果是一个新的功能,比如新的图像显示、新的运动控制,我也能方便地实现。所以,这个游戏的代码,是在前几个游戏的基础上扩充起来的。部分函数,部分变量在这款游戏中,根本不用,但要保留,要为下一款游戏作准备。只要理解了各个类,就理解了整个框架。
今天先讲最基础的图像类 MYBITMAP:
成员函数功能列表:
//功能 根据一个位图文件,初始化图像
//入参 应用程序实例句柄 资源ID 横向位图个数 纵向位图个数
void Init(HINSTANCE hInstance,int iResource,int row,int col);
//功能 设置环境信息
//入参 目的DC(要绘制图像的DC),临时DC,要绘制区域的宽 高
void SetDevice(HDC hdest,HDC hsrc,int wwin,int hwin);
//功能 设置图片位置
//入参 设置方法 横纵坐标
void SetPos(int istyle,int x,int y);
//功能 图片显示
//入参 图片显示方式
void Draw(DWORD dwRop);
//功能 图片缩放显示
//入参 横纵方向缩放比例
void Stretch(int x,int y);
//功能 图片缩放显示
//入参 横纵方向缩放比例 缩放图像ID(纵向第几个)
void Stretch(int x,int y,int id);
//功能 在指定位置显示图片
//入参 横纵坐标
void Show(int x,int y);
//功能 横向居中显示图片
//入参 纵坐标
void ShowCenter(int y);
//功能 将某个图片平铺在一个区域内
//入参 左上右下边界的坐标 图片ID(横向第几个)
void ShowLoop(int left,int top,int right,int bottom,int iframe);
//功能 不规则图片显示
//入参 横纵坐标 图片ID(横向第几个)
void ShowNoBack(int x,int y,int iFrame);
//功能 不规则图片横向平铺
//入参 横纵坐标 图片ID(横向第几个) 平铺个数
void ShowNoBackLoop(int x,int y,int iFrame,int iNum);
//动画播放
//功能 自动播放该图片的所有帧,函数没有实现,但以后肯定要用:)
//入参 无
void ShowAni();
//功能 设置动画坐标
//入参 横纵坐标
void SetAni(int x,int y);
成员数据
//跟踪打印类
// FILEREPORT f;
//图像句柄
HBITMAP hBm;
//按照行列平均分成几个
int inum;
int jnum;
//按行列分割后,每个图片的宽高(显然各个图片大小一致,派生后,这里的宽高已没有使用意义)
int width;
int height;
//屏幕宽高
int screenwidth;
int screenheight;
//要绘制图片的dc
HDC hdcdest;
//用来选择图片的临时dc
HDC hdcsrc;
//当前位置
int xpos;
int ypos;
//是否处于动画播放中(功能没有实现)
int iStartAni;
这个基类的部分函数和变量,在这个游戏中没有使用,是从前几个游戏中保留下来的,所以看起来有些零乱.这个游戏的主要图像功能,由它的派生类完成.由于基类封装了物理层信息(dc和句柄),派生类的编写就容易一些,可以让我专注于逻辑含义.
基类的函数实现上,很简单,主要是以下几点:
1.图片初始化:
//根据程序实例句柄,位图文件的资源ID,导入该位图,得到位图句柄
hBm=LoadBitmap(hInstance,MAKEINTRESOURCE(iResource));
//获取该位图文件的相关信息
GetObject(hBm,sizeof(BITMAP),&bm);
//根据横纵方向的图片个数,计算出每个图片的宽高(对于超级玛丽,宽高信息由派生类处理)
width=bm.bmWidth/inum;
height=bm.bmHeight/jnum;
2.图片显示
各个图片的显示函数,大同小异,都要先选入一个临时DC,再bitblt到要绘制的dc上.矩形图片,可以直接用SRCCOPY的方式绘制.不规则图片,需要先用黑白图与目的区域相"与"(SRCAND),再用"或"的方法显示图像(SRCPAINT),这是一种简单的"去背"方法.
例如下面这个函数:
void MYBITMAP::ShowNoBack(int x,int y,int iFrame)
{
xpos=x;
ypos=y;
SelectObject(hdcsrc,hBm);
BitBlt(hdcdest,xpos,ypos,width,height/2,hdcsrc,iFrame*width,height/2,SRCAND);
BitBlt(hdcdest,xpos,ypos,width,height/2,hdcsrc,iFrame*width,0,SRCPAINT);
}
3.图片缩放
用StretchBlt的方法实现
void MYBITMAP::Stretch(int x,int y,int id)
{
SelectObject(hdcsrc,hBm);
StretchBlt(hdcdest,xpos,ypos,width*x,height*y,
hdcsrc,0,id*height,
width,height,
SRCCOPY);
}
在超级玛丽中的使用
在这个游戏中,哪些图像的处理是通关这个基类呢?只有一个:
MYBITMAP bmPre;
由于这个基类只能处理几个大小均等的图片,只有这些图片大小一致,且都是矩形:游戏开始前的菜单背景,操作信息的背景,每一关开始前的背景(此时显示LIFE x WORLD x),通关或游戏结束时显示的图片.共5个,将这5个图片,放在一个位图文件中,于是,这些图片的操作就做完了,代码如下:
//初始设置,在InitInstance函数中
bmPre.Init(hInstance,IDB_BITMAP_PRE1,1,5);
bmPre.SetDevice(hscreen,hmem,GAMEW*32,GAMEH*32);
bmPre.SetPos(BM_USER,0,0);
//图片绘制,在WndProc中,前两个参数指横纵方向扩大2倍显示.
bmPre.Stretch(2,2,0);
bmPre.Stretch(2,2,4);
bmPre.Stretch(2,2,2);
bmPre.Stretch(2,2,1);
bmPre.Stretch(2,2,3);
图像控制部分,基类就讲到这里,欲知后事,下回分解.
附:
超级玛丽第一版源码链接:http://download.csdn.net/source/497676
超级玛丽增强版源码链接:http://download.csdn.net/source/584350