您的位置:首页 > 其它

从零开始学AS3游戏开发【七】永无终结,不断完善的游戏

2011-12-28 16:15 197 查看
注:本系列教程每周一篇,旨在引导刚刚接触FLASH的新手通过实例进行游戏开发的学习。在过程中逐步说明涉及到的类及对应的使用方法。从一个光秃秃的方块开始,根据不同的控制方式、玩法产生不同的分支,最终完善成一个个可玩的游戏。希望对各位入门的朋友有所帮助!在教程涉及的各种处理方法,可能不够完善,也希望各位高手指正:)

转载请注名来源于天地会。

第七篇 永无终结,不断完善的游戏

经过前面的六篇教程,我们写出来的东西基本上可以称之为一个游戏了:我们可以控制主角在场景内移动,射击敌人,并可能遭到敌人的反击。但是,它还是不够丰满,子弹没有打击效果,没有声音来进行气氛的烘托,另外,我们的坦克永远都是同样的速度同样的攻击力在地图中移动。当然,还有更多的想法可以加进去。不过,我们现在只来解决上面提到的问题。各位兄弟也可以开动脑筋,加入自己的想法到游戏里。

首先。我们来实现子弹的爆炸效果。由于我们以介绍程序写法为主,因此,对于爆炸素材的制作和寻找,我们不过多描述。我通过FLASH绘制了一个很简单的效果。



当然,导出GIF后图像品质下降了很多。。。呵呵。我们来想一下一个子弹的爆炸效果应该是怎样的实现顺序:爆炸效果应该在子弹飞出屏幕,或者击中敌人后出现。同时,爆炸效果的动画播放完成后,应该从主场景中自动删除掉。那么,我们应该想办法知道,爆炸效果的动画是否播放完成。



在FLASH CS3中,我们选择爆炸动画的最后一帧,按下F9打开动作面板。输入以下代码:

dispatchEvent(new Event(Event.COMPLETE));

stop();

复制代码
在这里,我们让动画停止播放,并且释放一个COMPLETE事件,告诉它的调用者,它已经播放完成,可以进行后续处理(删除等操作)。不过,还是要提醒大家。把代码写在时间轴上并不是一个好的习惯。对于一些简单的代码,可以通过时间轴来编写。如果长篇大论的在时间轴上写代码。后期维护起来是非常困难的。



动画做好了,我们把他为ActionScript导出(如上图),接下来我们来实现爆炸对象,按照我们的想法来写就可以了。直接贴出代码:

package D5Power.Objects

{

import flash.display.MovieClip;

import flash.events.Event;

/**

* 爆炸效果

* @author ...

*/

public class BoomEffect extends gameObject

{

protected var _face:MovieClip;

/**

*

* @param face 效果MC

*/

public function BoomEffect(face:MovieClip)

{

_face = face;

addChild(_face);

_face.addEventListener(Event.COMPLETE, onComplate);

}

/**

* 侦听到动画的播放结束事件

* @param e

*/

private function onComplate(e:Event):void

{

Global.scene.removeObject(this);

}

override public function die():void

{

removeChild(_face);

_face = null;

}

}

}

复制代码
爆炸对象当然也是游戏对象的一种,因此,它集成自gameObject类。_face变量用于保存对爆炸动画的引用。而在这里,我们侦听了爆炸动画的播放结束事件,当它产生这个事件的时候,onComplate将运行。把对象自身从游戏场景中删除掉。

接下来,就是在必要的地方把爆炸对象添加到场景中去。我们希望在子弹飞出地图边界,和击中目标的时候播放爆炸动画,因此,我们改动了子弹类的Do方法:

override public function Do():void

{

...

for each(var obj:gameObject in Global.scene.AllObject)

{

if (obj.hitTest && obj.part!=_shooter.part && obj!=this && obj.hitTestPoint(x, y, true))

{

// 击中目标

if (!obj.hitTest) continue;

showBoom();

if(obj.hasOwnProperty('Hurt')) (obj as FaceObject).Hurt(20);

Global.scene.removeObject(this);

break;

}

}

if (x<0 || x>Global.stage.stageWidth || y<0 || y>Global.stage.stageHeight)

{

showBoom();

Global.scene.removeObject(this);

}

}

/**

* 实现爆炸效果

*/

protected function showBoom():void

{

var boom:BoomEffect = new BoomEffect(new boom01());

boom.x = x;

boom.y = y;

Global.scene.addObject(boom);

}

复制代码
由于有2个位置都需要实现爆炸效果,因此我们写了一个showBoom方法,来实现爆炸效果,并把爆炸效果的位置设置在当前子弹的位置。而在击中目标,和飞出地图的判断中,只需要调用showBoom方法就可以了。

好了。现在测试一下吧,比原来效果好一些了吧:)



在附件中的源码里,我对敌人的爆炸也增加了效果。当然,实现的原理是一样的。

我们希望在游戏中出现各种各样的道具,来加强自己。下面,我们就通过一个加速道具,来看一下如何在游戏中实现道具

首先,道具肯定也是gameObject的子类,它有自己的皮肤(每个不同的道具当然有不同的外观),另外,它还需要检测是否与其他对象发生了碰撞,并对与其发生碰撞的目标产生属性的影响。

我们直接来看一下道具类的代码:

package D5Power.Objects

{

import flash.display.MovieClip;

/**

* 道具物品

* @author ...

*/

public class Item extends gameObject

{

protected var _face:MovieClip

/**

*

* @param face 皮肤MC

*/

public function Item(face:MovieClip)

{

_face = face;

_hitTest = false; // 不参与子弹碰撞

addChild(_face);

}

/**

*

*/

override public function Do():void

{

// 检查是否发生碰撞

for each(var obj:gameObject in Global.scene.AllObject)

{

if (obj is Player || obj is Monster)

{

if (hitTestObject(obj))

{

(obj as ActionObject).Speed = 2.4;

Global.scene.removeObject(this);

break;

}

}

}

}

override public function die():void

{

removeChild(_face);

_face = null;

}

}

}

复制代码

在构造函数中,我们把_hitTest属性设置为FALSE,也就是说,道具是不参与子弹的碰撞检测的。主要的功能,在覆盖的Do方法里实现。每次运行Do方法,将循环遍历游戏场景中的全部对象,并检查是否与自身发生了碰撞,如果是的话,把碰撞对象的速度设置为2.4。

这部分功能的实现过于简单,同时也存在一些问题:

1.每次都要检测场景中的全部对象,甚至是砖墙。这显然很浪费资源。道具应该只可能由敌人或者主角来碰撞使用,因此,有什么方法跳过对其他游戏对象的检测呢?
2.速度的影响是直接写在程序中的,这显然非常不利于扩展。有什么办法能够解决呢?

对于第一个问题,可以通过建立角色列表来解决。除了AllObject方法,还可以在游戏场景中专门建立一个特殊的数组,用来保存所有的敌人和主角的引用。这样就可以只在这些游戏对象中进行检查。第二个问题,有很多的解决方法。例如可以建立一个道具配置文件,把不同道具的属性影响写在这个配置文件中(类似GLOBAL类),而在使用的时候,想办法获取属性就可以了。大家可以试着自己来实现。

道具实现了,我们需要定期的让它出现在游戏场景中,因此,我们修改了Main.as。在Main方法中增加了以下语句

var timer:Timer = new Timer(30000);

timer.addEventListener(TimerEvent.TIMER, createItem);

timer.start();

复制代码

我们定义了一个时间间隔是30秒的定时器,每次都会运行createItem方法来创建道具。来看一下createItem的代码:

private function createItem(e:TimerEvent):void

{

for each(var obj:gameObject in Global.scene.AllObject)

{

if (obj is Item) Global.scene.removeObject(obj);

}

var p:Point = getRandomPlace();

var item:Item = new Item(new item_upspeed());

item.x = item.width * p.x;

item.y = item.height * p.y;

Global.scene.addObject(item);

}

复制代码

首先,遍历了所有的游戏对象,把所有没有被吃掉的道具删除,然后,通过一个getRandomPlace方法获取了一个坐标点,并通过计算,把道具对象的位置设置好,然后放入游戏场景。

为什么要通过getRandomPlace来获取一个坐标点呢?来看一下它的代码:

/**

* 查找一个空的位置

* @return

*/

private function getRandomPlace():Point

{

var ry:uint = int(Math.random() * mapconfig.length);

var rx:uint = int(Math.random() * mapconfig[0].length);

if (mapconfig[ry][rx] == 0) return new Point(rx, ry);

return getRandomPlace();

}

复制代码

我们在第六篇教程中,已经把地图设置为数组配置了。如果物品的位置随机,那么应该在空的位置生成(你可以想象如果道具生成在墙上,你的坦克怎么开过去吃掉它呢)。因此,我们通过递归的方法,从地图配置文件中选出一个为0的元素,并把这个元素的坐标返回。而在createItem中,则根据这个坐标来控制道具类的位置。

现在,游戏场景中会不停的随机出现道具了:



当然,道具并不是只有你可以吃,如果敌人吃掉了,也是会跑的飞快的。

什么?我没讲道具的贴图是怎么制作的?
经过前面六篇半的学习,相信这个已经不用再介绍了。

我曾经在上一次的预告中,说到我们会在这篇教程来介绍如何加入声音。在这里,我将不会再去详细的介绍。我只告诉大家,可以通过Sound类来实现声音的播放。至于具体的方法,请大家自己翻阅Adobe提供的API文档。以及毫不客气的询问GOOGLE。相信他们会给你满意的答案。

写在最后

“从零开始学AS3游戏开发”系列教程,到这一篇就结束了。在过来的2个月里,我们从一个黑色方块开始,逐步讨论了一个“简单”的FLASH小游戏所需要使用的一些“简单”的技巧和知识。要完成一款好的游戏,要投入的时间会比2月多出更多。

有兄弟回帖问过我,应该详细的解释一下,为什么要搞这么多的类,这么多的继承。其实这样简单的功能,直接在时间轴上写就可以实现了。在教程的结尾,我只是说下我自己的看法。我们不要仅仅为了一个项目而去写代码。如果真的喜欢这个行业,就应该尽早建立起自己的类库。如果每次都在针对一个项目来写代码,那么这个项目结束后,如果没有总结和沉淀,我们通过实战所获得的提升,将慢慢被时间冲淡。如果可以的话,从一个项目中提取一部分通用的类,哪怕只有几个,经过这样的沉淀和积累,在以后的项目中我们可能会更加的得心应手,开发的速度也会更快。

技术学习起来很快,但是经验是很难学的到的,只能靠时间去不断积累。

嗯,说了很多题外话,总之,希望大家在游戏开发的路上,找到属于自己的乐趣。“玩”的开心

D5Power

PS.对认真挑出教程中的各种BUG的兄弟表示诚挚的感谢!

本篇最终源码:


teach.rar (414.56 KB)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: