超级玛丽制作揭秘.docx
- 文档编号:15153182
- 上传时间:2023-07-01
- 格式:DOCX
- 页数:137
- 大小:373.10KB
超级玛丽制作揭秘.docx
《超级玛丽制作揭秘.docx》由会员分享,可在线阅读,更多相关《超级玛丽制作揭秘.docx(137页珍藏版)》请在冰点文库上搜索。
超级玛丽制作揭秘
MARIOCODEINSIDE
超级玛丽制作揭秘
目录
一、超级玛丽制作揭秘1工程开始2
二、超级玛丽制作揭秘2图片基类MYBITMAP4
三、超级玛丽制作揭秘3游戏背景类MYBKSKY7
四、超级玛丽制作揭秘4图片显示类MYANIOBJ9
五、超级玛丽制作揭秘5魔法攻击类MYANIMAGIC13
六、超级玛丽制作揭秘6时钟控制类MYCLOCK14
七、超级玛丽制作揭秘7字体管理类MYFONT19
八、超级玛丽制作揭秘8跟踪打印类FILEREPORT22
九、超级玛丽制作揭秘9精灵结构structROLE24
十、超级玛丽制作揭秘10子弹的显示和帧的刷新26
十一、超级玛丽制作揭秘11子弹运动和打怪27
十二、超级玛丽制作揭秘12旋风攻击,小怪运动,火圈29
十三、超级玛丽制作揭秘13小怪和火圈,模板34
十四、超级玛丽制作揭秘14爆炸效果,金币37
十五、超级玛丽制作揭秘15金币提示,攻击提示41
十六、超级玛丽制作揭秘16攻击方式切换43
十七、超级玛丽制作揭秘17地图物品44
十八、超级玛丽制作揭秘18背景物品47
十九、超级玛丽制作揭秘19视图48
二十、超级玛丽制作揭秘20地图切换50
二十一、超级玛丽制作揭秘21游戏数据管理53
二十二、超级玛丽制作揭秘22玩家角色类MYROLE58
二十三、超级玛丽制作揭秘23玩家动作控制63
二十四、超级玛丽制作揭秘24角色动画69
二十五、超级玛丽制作揭秘25类GAMEMAP全局变量72
二十六、超级玛丽制作揭秘26菜单控制窗口缩放76
二十七、超级玛丽制作揭秘27程序框架WinProc80
二十八、InitInstance函数说明85
二十九、后记87
类结构
图像层:
图像基类MYBITMAP
游戏背景MYBKSKYMYBITMAP
游戏图片MYANIOBJMYBITMAP
魔法攻击MYANIMAGICMYBITMAP
逻辑层:
游戏逻辑GAMEMAP
时钟处理MYCLOCK
字体处理MYFONT
跟踪打印FILEREPORT
玩家控制MYROLEMYBITMAP
结构和表:
精灵结构ROLE
物品结构MapObject
地图信息表MAPINFO
一、超级玛丽制作揭秘1工程开始
两个版本的超级玛丽下载量已超过5000次,谢谢大家支持。
谁无法下载,请告诉我邮箱,我直接发。
现在反映两个问题,一没有帮助文档,二代码注释太少。
今天起,我揭秘制作过程,保证讲解到每一行代码,每一个变量。
代码我已经发布,可见做这样一个游戏并不难。
今天讲准备工作,也就是所需要的开发工具。
代码编写调试:
VC6.0,美术工具:
Windows自带的画图(开始-程序-附件-画图)。
这是最简陋的开发工具,但已足够。
最好再有Photoshop,记事本或UltraEdit等等你喜欢的文本编辑工具。
游戏代码分两部分,图像部分,逻辑部分。
先说图像部分:
图像分两种,矩形图片和不规则图片。
工程中的PIC文件夹下,可以看到所有图像资源
矩形图片有:
地面、砖块、水管、血条、血条背景。
不规则图片有:
蘑菇(玩家,敌人1,敌人2),子弹、旋风、爆炸效果、金币、撞击金币后的得分、攻击武器(那个从魂斗罗里抠来的东东)、火圈1、火圈2、箭头(用于开始菜单选择)、树木、河流、WIN标志、背景图片(游戏背景和菜单背景)。
所有图片都分成几个位图BMP文件存储。
一个文件中,每种图片,都纵向排列。
每种图片可能有多帧。
比如,金币需要4帧图像,才能构成一个旋转的动画效果,那么,各帧图像横向排列。
图像层的结构就这样简单,逻辑层只需要确定“哪个图像,哪一帧”这两个参数,就能在屏幕上绘制出所有图片。
图像层的基类是:
classMYBITMAP
voidInit(HINSTANCEhInstance,intiResource,introw,intcol);
voidSetDevice(HDChdest,HDChsrc,intwwin,inthwin);
voidDraw(DWORDdwRop);
HBITMAPhBm;
//按照行列平均分成几个
intinum;
intjnum;
intwidth;
intheight;
HDChdcdest;
HDChdcsrc;
这只是一个基类,上面是几个重要的数据成员和函数。
它所描述的图片,是一个m行n列构成的m*n个图片,每个图片大小一致,都是矩形。
显然,这并不能满足上面的设计要求,怎么解决呢?
派生,提供更多的功能。
但是,这个基类封装了足够的物理层信息:
设备上下文HDC,和位图句柄HBITMAP。
矩形图片的显示、不规则图片的显示、图片组织排列信息,这些功能交给它的派生类MYANIOBJ。
还有,我们最关心的问题是图片坐标,比如,不同位置的砖块、精灵、金币,这些由逻辑层处理,以后再讲,先到这里吧。
二、超级玛丽制作揭秘2图片基类MYBITMAP
先说一下代码风格,大家都说看不懂,这就对了。
整套代码约有3000行,并不都是针对这个游戏写的。
我想把代码写成一个容易扩展、容易维护、功能全面的“框架”,需要什么功能,就从这个框架中取出相应功能,如果是一个新的功能,比如新的图像显示、新的运动控制,我也能方便地实现。
所以,这个游戏的代码,是在前几个游戏的基础上扩充起来的。
部分函数,部分变量在这款游戏中,根本不用,但要保留,要为下一款游戏作准备。
只要理解了各个类,就理解了整个框架。
今天先讲最基础的图像类MYBITMAP:
成员函数功能列表:
//功能根据一个位图文件,初始化图像
//入参应用程序实例句柄资源ID横向位图个数纵向位图个数
voidInit(HINSTANCEhInstance,intiResource,introw,intcol);
//功能设置环境信息
//入参目的DC(要绘制图像的DC),临时DC,要绘制区域的宽高
voidSetDevice(HDChdest,HDChsrc,intwwin,inthwin);
//功能设置图片位置
//入参设置方法横纵坐标
voidSetPos(intistyle,intx,inty);
//功能图片显示
//入参图片显示方式
voidDraw(DWORDdwRop);
//功能图片缩放显示
//入参横纵方向缩放比例
voidStretch(intx,inty);
//功能图片缩放显示
//入参横纵方向缩放比例缩放图像ID(纵向第几个)
voidStretch(intx,inty,intid);
//功能在指定位置显示图片
//入参横纵坐标
voidShow(intx,inty);
//功能横向居中显示图片
//入参纵坐标
voidShowCenter(inty);
//功能将某个图片平铺在一个区域内
//入参左上右下边界的坐标图片ID(横向第几个)
voidShowLoop(intleft,inttop,intright,intbottom,intiframe);
//功能不规则图片显示
//入参横纵坐标图片ID(横向第几个)
voidShowNoBack(intx,inty,intiFrame);
//功能不规则图片横向平铺
//入参横纵坐标图片ID(横向第几个)平铺个数
voidShowNoBackLoop(intx,inty,intiFrame,intiNum);
//动画播放
//功能自动播放该图片的所有帧,函数没有实现,但以后肯定要用:
)
//入参无
voidShowAni();
//功能设置动画坐标
//入参横纵坐标
voidSetAni(intx,inty);
成员数据
//跟踪打印类
//FILEREPORTf;
//图像句柄
HBITMAPhBm;
//按照行列平均分成几个
intinum;
intjnum;
//按行列分割后,每个图片的宽高(显然各个图片大小一致,派生后,这里的宽高已没有使用意义)
intwidth;
intheight;
//屏幕宽高
intscreenwidth;
intscreenheight;
//要绘制图片的dc
HDChdcdest;
//用来选择图片的临时dc
HDChdcsrc;
//当前位置
intxpos;
intypos;
//是否处于动画播放中(功能没有实现)
intiStartAni;
这个基类的部分函数和变量,在这个游戏中没有使用,是从前几个游戏中保留下来的,所以看起来有些零乱.这个游戏的主要图像功能,由它的派生类完成.由于基类封装了物理层信息(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),这是一种简单的"去背"方法.
例如下面这个函数:
voidMYBITMAP:
:
ShowNoBack(intx,inty,intiFrame)
{
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的方法实现
voidMYBITMAP:
:
Stretch(intx,inty,intid)
{
SelectObject(hdcsrc,hBm);
StretchBlt(hdcdest,xpos,ypos,width*x,height*y,
hdcsrc,0,id*height,
width,height,
SRCCOPY);
}
在超级玛丽中的使用
在这个游戏中,哪些图像的处理是通关这个基类呢?
只有一个:
MYBITMAPbmPre;
由于这个基类只能处理几个大小均等的图片,只有这些图片大小一致,且都是矩形:
游戏开始前的菜单背景,操作信息的背景,每一关开始前的背景(此时显示LIFExWORLDx),通关或游戏结束时显示的图片.共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);
图像控制部分,基类就讲到这里,欲知后事,下回分解.
附:
超级玛丽第一版源码链接:
超级玛丽增强版源码链接:
三、超级玛丽制作揭秘3游戏背景类MYBKSKY
类说明:
这是一个专门处理游戏背景的类。
在横版游戏或射击游戏中,都有一个背景画面,如山、天空、云、星空等等。
这些图片一般只有1到2倍屏幕宽度,然后像一个卷轴一样循环移动,连成一片,感觉上像一张很长的图片。
这个类就是专门处理这个背景的。
在超级玛丽增强版中,主要关卡是3关,各有一张背景图片;从水管进去,有两关,都用一张全黑图片。
共四张图。
这四张图大小一致,纵向排列在一个位图文件中。
MYBKSKY这个类,派生于MYBITMAP。
由于背景图片只需要完成循环移动的效果,只需要实现一个功能,而无需关心其他任何问题(例如句柄、dc)。
编码起来很简单,再次反映出面向对象的好处。
技术原理:
怎样让一张图片像卷轴一样不停移动呢?
很简单,假设有一条垂直分割线,把图片分成左右两部分。
先显示右边部分,再把左边部分接到图片末尾。
不停移动向右移动分割线,图片就会循环地显示。
成员函数功能列表:
classMYBKSKY:
publicMYBITMAP
{
public:
MYBKSKY();
~MYBKSKY();
//show
//功能显示一个背景.
//入参无
voidDrawRoll();//循环补空
//功能显示一个背景,并缩放图片
//入参横纵方向缩放比例
voidDrawRollStretch(intx,inty);
//功能指定显示某一个背景,并缩放图片,游戏中用的就是这个函数
//入参横纵方向缩放比例背景图片ID(纵向第几个)
voidDrawRollStretch(intx,inty,intid);
//功能设置图片位置
//入参新的横纵坐标
voidMoveTo(intx,inty);
//功能循环移动分割线
//入参分割线移动的距离
voidMoveRoll(intx);
//data
//分割线横坐标
intxseparate;
};
函数具体实现都很简单,例如:
voidMYBKSKY:
:
DrawRollStretch(intx,inty,intid)
{
//选入句柄
SelectObject(hdcsrc,hBm);
//将分割线右边部分显示在当前位置
StretchBlt(hdcdest,
xpos,ypos,//当前位置
(width-xseparate)*x,height*y,//缩放比例
hdcsrc,
xseparate,id*height,//右边部分的坐标
width-xseparate,height,//右边部分的宽高
SRCCOPY);
//将分割线左边部分接在图片末尾
StretchBlt(hdcdest,xpos+(width-xseparate)*x,ypos,
xseparate*x,height*y,
hdcsrc,0,id*height,
xseparate,height,
SRCCOPY);
}
使用举例:
定义MYBKSKYbmSky;
初始化
mario01\mario01.cpp(234):
bmSky.Init(hInstance,IDB_BITMAP_MAP_SKY,1,4);
mario01\mario01.cpp(235):
bmSky.SetDevice(hscreen,hmem,GAMEW*32*MAX_PAGE,GAMEH*32);
mario01\mario01.cpp(236):
bmSky.SetPos(BM_USER,0,0);
游戏过程中显示
mario01\mario01.cpp(366):
bmSky.DrawRollStretch(2,2,gamemap.mapinfo.iBackBmp);
每隔一定时间,移动分割线
mario01\mario01.cpp(428):
bmSky.MoveRoll(SKY_SPEED);//云彩移动
以下两处与玩家角色有关:
当玩家切换到一张新地图时,刷新背景图片的坐标
mario01\gamemap.cpp(314):
bmSky.SetPos(BM_USER,viewx,0);
当玩家向右移动时,刷新背景图片的坐标
mario01\gamemap.cpp(473):
bmSky.SetPos(BM_USER,viewx,0);
至此,游戏背景图片的功能就做完了。
附:
超级玛丽第一版源码链接:
超级玛丽增强版源码链接:
四、超级玛丽制作揭秘4图片显示类MYANIOBJ
类说明:
这个类负责游戏中的图片显示。
菜单背景、通关和游戏结束的提示图片,由MYBITMAP处理(大小一致的静态图片)。
游戏背景由MYBKSKY处理。
其余图片,也就是游戏过程中的所有图片,都是MYANIOBJ处理。
技术原理:
游戏中的图片大小不一致,具体在超级玛丽中,可以分成两类:
矩形图片和不规则图片。
在位图文件中,都是纵向排列各个图片,横向排列各帧。
用两个数组存储各个图片的宽和高。
为了方便显示某一个图片,用一个数组存储各个图片的纵坐标(即位图文件中左上角的位置)。
使用时,由逻辑层指定“哪个图片”的“哪一帧”,显示在“什么位置”。
这样图片的显示功能就实现了。
成员函数功能列表:
classMYANIOBJ:
publicMYBITMAP
{
public:
MYANIOBJ();
~MYANIOBJ();
//initlist
//功能初始化宽度数组高度数组纵坐标数组是否有黑白图
//入参宽度数组地址高度数组地址图片数量是否有黑白图(0没有,1有)
//(图片纵坐标信息由函数计算得出)
voidInitAniList(int*pw,int*ph,intinum,intismask);
//功能初始化一些特殊的位图,例如各图片大小一致,或者有其他规律
//入参初始化方式参数1参数2
//(留作以后扩展,目的是为了省去宽高数组的麻烦)
voidInitAniList(intstyle,inta,intb);
//show
//功能显示图片(不规则图片)
//入参横纵坐标(要显示的位置)图片id(纵向第几个),图片帧(横向第几个)
voidDrawItem(intx,inty,intid,intiframe);
//功能显示图片(矩形图片)
//入参横纵坐标(要显示的位置)图片id(纵向第几个),图片帧(横向第几个)
voidDrawItemNoMask(intx,inty,intid,intiframe);
//功能指定宽度,显示图片的一部分(矩形图片)
//入参横纵坐标(要显示的位置)图片id(纵向第几个),显示宽度图片帧(横向第几个)
voidDrawItemNoMaskWidth(intx,inty,intid,intw,intiframe);
//功能播放一个动画即循环显示各帧
//入参横纵坐标(要显示的位置)图片id(纵向第几个)
voidPlayItem(intx,inty,intid);
//宽度数组最多支持20个图片
intwlist[20];
//高度数组最多支持20个图片
inthlist[20];
//纵坐标数组最多支持20个图片
intylist[20];
//动画播放时的当前帧
intiframeplay;
};
函数实现上也很简单。
构造函数中,所有成员数据清零;初始化时,将各图片的高度累加,即得到各图片的纵坐标。
显示图片的方法如前所述。
使用举例:
游戏图片分成三类:
地图物品、地图背景物体、精灵(即所有不规则图片)
MYANIOBJbmMap;
MYANIOBJbmMapBkObj;
MYANIOBJbmAniObj;
初始化宽高信息
程序中定义一个二维数组,例如:
intmapani[2][10]={
{32,32,64,32,32,52,64,32,64,32},
{32,32,64,32,32,25,64,32,64,32},
};
第一维mapani[0]存储10个图片的宽度,第二维mapani[1]存储10个图片的高度,初始化时,将mapani[0],mapani[1]传给初始化函数即可。
1.地图物品的显示:
定义
mario01\mario01.cpp(82):
MYANIOBJbmMap;
初始化
这一步加载位图
mario01\mario01.cpp(238):
bmMap.Init(hInstance,IDB_BITMAP_MAP,1,1);
这一步初始化DC
mario01\mario01.cpp(239):
bmMap.SetDevice(hscreen,hmem,GAMEW*32*MAX_PAGE,GAMEH*32);
这一步设置宽高信息,图片为矩形
mario01\mario01.cpp(240):
bmMap.InitAniList(mapsolid[0],mapsolid[1],sizeof(mapsolid[0])/sizeof(int),0);
对象作为参数传给逻辑层,显示地图物品
mario01\mario01.cpp(368):
gamemap.Show(bmMap);
2.血条的显示:
打怪时,屏幕上方要显示血条。
由于同样是矩形图片,也一并放在了地图物品的位图中。
变量声明
mario01\gamemap.cpp(11):
externMYANIOBJbmMap;
显示血条背景,指定图片宽度:
最大生命值*单位生命值对应血条宽度
mario01\gamemap.cpp(522):
bmMap.DrawItemNoMaskWidth(xstart-1,ATTACK_TO_Y-1,ID_MAP_HEALTH_BK,
显示怪物血条,指定图片宽度:
当前生命值*单位生命值对应血条宽度
mario01\gamemap.cpp(525):
bmMap.DrawItemNoMaskWidth(xstart,ATTACK_TO_Y,ID_MAP_HEALTH,
3.地图背景物体的显示
背景物体包括草、河流、树
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 超级 玛丽 制作 揭秘
![提示](https://static.bingdoc.com/images/bang_tan.gif)