本来有很多想说的,可一旦真的写了,突然发现无从下手,不过这个感觉就和我第一次开发游戏一样,因此,我就从新手最容易碰到的问题上来说吧。
很多游戏开发新手在这个问题上都会很迷茫,究竟如何去控制整个FLASH游戏?
比如,我们要做一个横版飞行游戏,那么我们会设想敌机在空中飞,那么这个飞行肯定是有速度的,新手一般会想到使用Timer类来实现每隔几秒就让某个元件按照一个数学函数来移动一下位置。这的确是最直观的方法。
不过这么做有两个坏处:
1 每个Timer如果都是独立的,那么则无法从全局上控制流程,比如让所有飞机都停止。如果是使用一个Timer来处理,那么对很多速度不相同的飞机就无法很好的控制。
2 我们不能保证每次Timer过后,显示出来的结果都是我们预期的,因为FLASH有相对固定的帧数,比如帧数是每秒1帧,如果你Timer设定10毫秒就移动一个像素,那么你看到的仍然是1秒移动了100像素,但是系统却运算了100游戏xml文件修改次。
因此我们使用在Flash中更为实用的控制流方式,ENTER_FRAME事件作为控制流的入口。这样做的好处如下:
1 只有在进入下一帧的时候才会做出相应运算,也就是说,所有内容的运算次数是最为优化的,因为你的眼睛只能看到每一帧的内容,因此我们只要在每帧的时候进行相应的改变就可以了
2 使用恰当的方式,我们可以由上而下的让所有的类都相对独立,但又可以受到上一级的控制,可以随时暂停任何一个你想暂停的内容。
那么接下来我们就举一个例子看一下实际的代码:
在文档类的构造函数中书写如下代码:
stage.addEventListener(Event.ENTER_FRAME, tick);
lastTickTime = getTimer();
lastTickTime 是个私有属性。
新增加一个私有函数tick
private function tick(e:Event) : void
{
var timer:int = getTimer();
var timespan:int = timer - lastTickTime;
lastTickTime = timer;
tickBase(lastTickTime);
}
这个tickBase函数的作用是,对需要被控制的对象执行相应的控制代码,具体内容大家可以根据需要自己写。
我们需要知道的就是,tickBase可以传2帧的时间间隔给你所需要控制的对象。因为虽然FLASH中我们设定了固定的帧数,但实际帧数会根据运算情况而有所改变,所以我们要使用这样的方式计算两帧的间隔时间。
好了,大家可以尝试一下,或者休息一会,之后我会写如何去更好的实现这个tickBase中的内容,以达到对你想要控制的内容进行控制
上一次讲了如何使用Enterframe做基础控制流的入口,我们使用了Timer配合,使得我们可以在每次进入下一帧的时候获得两帧之间的时间。
现在我们讲讲如何通过tickBase方法进而去控制程序中需要控制的每一个类。
这次我们用《梦想花园》中的花的成长控制作为例子。
如果每一朵花都需要自动的生长,我们应该怎么做呢?没错,我们要使用tick,在每次进入下一帧的时候调用tick函数,传入时间间隔timeSpan,累加这些时间,并且判断花朵是否应该长大,从而更换花朵的状态。
为此,我们写了一个新的类BaseObject类,该类继承Sprite类,该类有个方法addObject代替addChild方法(但是我们不重写addChild,因为也有用到的时候),addObject只能用于添加另一个BaseObject类,该方法的作用是,将另一个BaseObject类的实例化对象加入该类中的一个数组里,作为他的“子”,并且在tick方法中调用它所有“子”的tick,而他所有“子”还将调用“子”中“子”数组的tick方法(如果有这么多“子”)的话。
可以看一下这个类的构造函数和addObject方法以及tick方法
public function BaseObject(mc:MoviClip) : void
{
baseObjects = new Array(); // baseObjects 是私有属性
content = mc; // content 是私有属性
}
public function addObject(baseObj:BaseObject)
{
objectsToAdd.push(obj);//objectsToAdd 是私有属性 用于存储需要添加的对象(这是一个临时的数组,当执行了addAndRemoveObjects()方法以后,objectsToAdd才会真正被添加到baseObjects数组中)
}
public function tickBase(timeSpan:uint) : void
{
for each(var i in baseObjects)
{
i.tickBase(timeSpan);
}
tick(timeSpan);
addAndRemoveObjects();//这个方法下次会讲到,很重要,功能是在tick的时候处理把对象添加到显示列表中
return;
}
public function tick(timeSpan:uint)
{
//该方法没有实现是个抽象方法,子类继承该抽象方法以完成tick中的内容
}
虽然这个类没有完整的书写(还不能用),但是现在已经可以对其功能进行了解。任何继承这个类的子类都会有tick方法,一旦使用了addObject方法添加其他继承该类的对象,只要在上一讲中的ENTERFRAME中,调用一个“父”级的BaseObject中的tickBase,就可以自动的传入所有该对象中的所有“子”级对象中的tick。
一旦这么做,我们可以先建立一个BaseObject对象land,然后使用land.addObject(flowe)方法,不过flowe对象也得是BaseObject的实例,然后在EnterFrame事件中执行land.tickBase()
方法,在每次进入下一帧的时候,flower就会执行自己的tick方法,于是在tick中我们可以执行计算时间并选择播放花朵的那段动画的过程函数了。
这样的好处是,即便对象之间的关系很复杂(比如land中有grass(草地),grass里有pot(花盆),pot中有5个flower),我们仍然能自由的去写每一个类的tick方法,他们可以有自己的处理方式,然后只要通过addObject方法来添加他的子级就可以达到预期的效果了。
好了,下次我们再说BaseObject中的具体实现方式,现在只要了解我们是如何控制我们的对象的就可以了。
前段时间比较忙,所以一直没有更新,不好意思。废话不多说,继续我们的控制流第三讲
这次主要讲两个内容:1、完善插入对象以及移出对象功能
2、在合适的时候更新显示列表,并更新层深
1插入以及移出对象
我们设想,因为程序需要,我们要在场景中插入一个对象,但又因为其他因素,这个对象需要立刻被移出,而这之间的间隔非常小,小到在两帧之间,这个时候我们就没有必要将该对象真正插入到显示列表中(这种情况虽然不多,但是也有可能出现)。
对应public var objectsToAdd:Array(待添加对象数组) ,我们在建一个数组 public var objectsToRemove:Array(待移出对象数组)
然后我们在addObject方法中判断该对象是否也在objectsToRemove出现,如果有,则从objectsToRemove数组中移出该对象,否则,添加到objectsToAdd数组中,removeObject方法也如法炮制。代码如下:
public function addObject(obj:BaseObject) : void
{
var removeIndex:int;
if (obj)
{
removeIndex = objectsToRemove.indexOf(obj);
if (removeIndex != -1)
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论