GameMaker8.0 新手教程 Part 14 -制作游戏(二)-

分类栏目:gamemaker教程

522

GameMaker8.0 新手教程 Part 14 -制作游戏(二)-

7、砖块与贴图

现在,我们要让我们的地图变得花哨一点,比如下面这样:
GameMaker8.0 新手教程 Part 14 -制作游戏(二)-
如果你想给每一种不同图像的砖块都创建一个object的话,那你可不得累死。(当然实际是可以的,只要全部勾选固体属性就行。)

所以,我推荐各位使用贴图。怎么使用呢?
首先,先给砖块一个半透明的精灵,比如下面这个:
GameMaker8.0 新手教程 Part 14 -制作游戏(二)-
然后给砖块勾上不可见。
GameMaker8.0 新手教程 Part 14 -制作游戏(二)-
我们很久以前说过,不可见仅仅只是代表不画出它的图像,但是依然会进行碰撞检测。
然后把砖块会用到的图像存进背景图片中。如果是个大张的记得勾选作为贴图使用。
GameMaker8.0 新手教程 Part 14 -制作游戏(二)-
在房间内,用objBlock摆好关卡:
GameMaker8.0 新手教程 Part 14 -制作游戏(二)-
把贴图贴上去。现在它看起来应该是这样的:
GameMaker8.0 新手教程 Part 14 -制作游戏(二)-
运行游戏,由于objBlock勾选不可见,所以它的半透明精灵不会被看到。
这样做的好处不仅是方便你不用创建大量对象,而且在复杂的游戏中易于维护。比如有什么地方必须要判定if(xxxx(objBlock))的话,如果大量创建不同的砖块对象,就得不停地加入if(xxxx(objBlock01) || xxxx(objBlock02) || xxxx(objBlock03)....)。

8、记录死亡数,杀死玩家,及父对

首先,我们要有一个能稳定记录死亡数的办法,所以要么保存存在global里,要么保存在world里。这里讲解保存在world里的方法,毕竟world本来就是全局控制的实例嘛。
所以我们先在world的create事件里初始化一个死亡数变量:
GameMaker8.0 新手教程 Part 14 -制作游戏(二)-
然后,新建一个对象叫做killerParent。至于为什么叫"Parent",这就是这一节的重头戏。
随便给它一个精灵。是的,随便给,给什么精灵都无所谓,不影响的。
GameMaker8.0 新手教程 Part 14 -制作游戏(二)-
打开objPlayer。给它的step事件添加新的代码。
由于我们这次添加的代码和之前写在step里的代码作用不同,所以建议用一个新的代码框来写。但凡是写在同一个事件但是作用不相同的代码,都建议分开不同的代码框来写。
GameMaker8.0 新手教程 Part 14 -制作游戏(二)-
在新的代码框里,我们写这样一段代码:
if(place_meeting(x, y, killerParent))
{
//播放死亡音效,如果没有,请删除这句。
sound_play(sndDeath);
//用来控制死亡效果的对象。
//view_xview + view_wview / 2和view_yview + view_hview / 2是确保在游戏窗口的正中间创建对象,如果不需要可以改成别的坐标。
instance_create(view_xview + view_wview / 2, view_yview + view_hview / 2, objGameOver);
//确保如果屏幕里有多个objPlayer,也都会被销毁。如果不需要这个效果,直接改成instance_destroy();即可。
with(objPlayer)instance_destroy();
//增加死亡数。
world.death += 1;
//保存死亡数及时间。
saveDeathTime();
}
在这里用到了未定义的脚本saveDeathTime,所以GM会报错。不过不要急,我们很快就会讲存读档。
然后新建一个对象objGameOver,深度调到-9999999。如果不叫这个名字,上面的代码中第七行也要修改掉。
这个objGameOver是用来实现死亡效果的。当然,现在咱还没讲到那些高级的特效函数,所以基本上也做不了什么高端特效,最普通的效果就是给objGameOver配一张好看的精灵了:
GameMaker8.0 新手教程 Part 14 -制作游戏(二)-
接着回到world,创建一个按下R键事件(随便什么键都行)用来replay:
//停止播放死亡音效。如果没有请删除。
sound_stop(sndDeath);
//读取存档
loadGame();
这里同样用到了未定义的脚本loadGame,GM也会在这里报错。
房间中,能杀死角色的实例可能是多种多样的,但是它们的形状也可能是各种各样的,所以并不能效仿objBlock一样使用贴图来解决这一问题。
这次我们只能给每一种能杀死角色的东西都新建一个对象了。
但是问题又来了。我们判断角色死亡,用的是if(place_meeting(x, y, killerParent)),如果创建多个对象的话,又要面临if(place_meeting(x, y, objBullet) || place_meeting(x, y, objSpike) || place_meeting(x, y, objThunder)...)的窘境了。要知道,GM只有固体和非固体两种实例,固体属性已经被我们拿去做地面和墙壁了,我们总不能把所有非固体都作为killer吧?

这时候,另一个在第三章被我们跳过的属性站了出来,他就是父对(Parent)。
GameMaker8.0 新手教程 Part 14 -制作游戏(二)-
我们随便新建一个对象(比如上图中的objSpike),然后给他的父对选上killerParent
GameMaker8.0 新手教程 Part 14 -制作游戏(二)-
把它放到房间里面,运行游戏,你会惊奇的发现——
GameMaker8.0 新手教程 Part 14 -制作游戏(二)-
报错了。这不是显然的嘛,还记得我们之前使用了未声明的脚本saveDeathTime和loadGame么?
所以我们先姑且暂时新建这两个脚本,不过里面什么都不写,空着。
GameMaker8.0 新手教程 Part 14 -制作游戏(二)-
再次运行游戏,控制角色去触碰objSpike,你会惊奇的发现,角色死亡被触发了。
GameMaker8.0 新手教程 Part 14 -制作游戏(二)-
这就是设置父对的意义之一:继承父对的被碰撞检测。无论是place_meeting,instance_place还是collision_系列函数,都会继承。
至此,这个问题也被完美的解决了。只要所有能杀死角色的对象,都设置killParent作为父对即可。这就是为什么killParent设置什么精灵都无所谓的原因,因为我们不会真的用到它。
当然,父对的意义不止于此,还有别的作用,比如子对继承父对的事件,子对响应父对的with等。正因如此,作为父对的对象,本身不应该有额外的代码(并不是说不能有代码),并且不应当作为实例出现在房间中。

9、记录游戏时间

有了记录死亡数的经验,记录游戏时间就简单了很多,所以我就不配图了。
首先先在world的create事件里初始化一个变量time = 0;
然后在world的step变量里写入如下代码:
//你需要把一切不应该记录游戏时间的房间写在这里。
if(room != rTitle && room != rStageSelect)
{
//当角色死亡时不记录游戏时间,你也可以删除这句。
if(instance_exists(objPlayer))
time += 1 / fps;
}
复制代码
time一次增加1 / fps,刚好每一秒增加1。