您的位置:首页 > 其它

从零开始学AS3游戏开发【五】 告别方块,添加碰撞

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

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

第五篇 告别方块,添加碰撞

上一篇教程中。我们新增了基地的概念,并让敌人可以向基地开火。但是,敌人和自己还都是四四方方一大块,分不清哪是脸哪是屁股。另外在游戏界面里,各个对象依然可以重叠在一起。这显然不太合理。在本次的教程中,我们将一一修正这些问题。

首先,换个脸。在FLASH里对原有的组件进行编辑,我们随便画一个坦克的样子,大概像下面这样:





这样,就有了比较像样(至少不是方块)的素材了。不过,新的问题出现了。这个时候测试影片,我们可以发现,当坦克向上开的时候,是没问题的,但是向其他方向移动,素材并没有发生变化,而是横着走,或者倒退了。我们需要根据坦克的方向来调整素材的旋转角度。于是,我们重写了FaceObject的direction方法:

override public function set direction(dir:uint):void

{

super.direction = dir;

var angle:Number;

var tx:Number;

var ty:Number;

switch(dir)

{

case ActionObject.UP:

angle = 0;

tx = 0;

ty = 0;

break;

case ActionObject.RIGHT:

angle = Math.PI * 0.5;

tx = _face.width;

ty = 0;

break;

case ActionObject.DOWN:

angle = Math.PI;

tx = _face.width;

ty = _face.height;

break;

case ActionObject.LEFT:

angle = Math.PI * 1.5;

tx = 0;

ty = _face.height;

break;

}

_face.transform.matrix = new Matrix(Math.cos(angle), Math.sin(angle),Math.sin(angle)*-1,Math.cos(angle),tx,ty);

}

复制代码
从代码中我们可以看出,是通过设置的方向值的不同,获取了一个特定的角度(向上0度,向右90度,向下180度,向左270度。注意这里的angle是用弧度来表示角的。)最后,我们定义了一个矩阵,并通过_face的transform来进行了形状的变化。

有兄弟可能会问为什么需要tx,ty两个属性呢?你可以把最后一行里的tx和ty去掉测试一下。可以发现,当素材旋转的时候,产生了位移。这是由于我们使用的素材的注册点是在左上角(可以看到图片上左上角那个十字么)。而旋转是围绕注册点进行的,也就是说,坦克的旋转是按照以下方式进行的:



可以看到,在旋转的过程中,坦克由于环绕左上的注册点旋转,实际上在4个方位各产生了与本身的宽度和高度相关的位移,因此,我们需要把他们移动相应的位置,使他们看起来还在原来的位置上。因此使用了tx,ty。

矩阵(Matrix)是一个非常有用的类。在我们的教程中也是第一次用到。矩阵的构造函数:

new Matrix(a,b,c,d,tx,ty)

其中各参数的说明如下:



在Adobe官方提供的文档中有详细的说明。这里不再过多描述,你可以看这里查看详细的说明:http://help.adobe.com/zh_CN/AS3L ... sh/geom/Matrix.html

现在,坦克的方向可以很清楚的看到了,下面,我们来看一下如何放置游戏场景里的物品与其他的物品撞到一起。我们来进行碰撞检测。

首先,随着游戏的扩展,并不是所有的游戏物体都能碰到(比如草丛可以踩过去等等),因此,游戏对象需要增加一个开关,来控制他是否参与碰撞检测.我们修改gameObject类,增加这个属性:

/**

* 是否参与碰撞检测

*/

protected var _hitTest:Boolean = false;

/**

* 是否参与碰撞检测

*/

public function get hitTest():Boolean

{

return _hitTest;

}

复制代码
为什么设置为protected?因为我们不需要从外部来更改它的碰撞属性,而只需要读取是否可以碰撞就可以了。

gameObject是继承自Sprite对象的。而Sprite提供了两种检测碰撞的方法,一是hitTestObject,另一个则是hitTestPoint。从API(http://help.adobe.com/zh_CN/AS3L ... /DisplayObject.html)中我们可以很清楚的看到,hitTestObject只是进行了外框的检测,也就是说,如果我们的图形不是正方形,而是其他不规则图形,哪怕图形上没有发生碰撞,只要图形的范围发生了交叠,FLASH就认为他们碰撞了。这显然不符合我们的要求(虽然我们的坦克基本上是个方块)。因此,我们还是和判断子弹的碰撞一样,选择hitTestPoint。但hitTestPoint需要一个指定的点。如何处理呢?

我们定义了8个检测目标,分别位于图形的四周(如下图所示),如果这8个目标点发生了碰撞,就认为物体撞在了一起。



由于只有ActionObject才需要检测碰撞,所以,我们根据上图给ActionObject增加检测点数组:

/**

* 碰撞检测点

*/

protected var _hitPoint:Array = [[0,0],[22,0],[45,0],[45,22],[45,45],[22,37],[0,45],[0,22]];

复制代码
进而修改nextCanMove方法:

/**

* 下一目标点是否可以移动

*/

public function get nextCanMove():Boolean

{

...

// 如果下一目标点超出屏幕范围,则不能移动

if (nx > Global.stage.stageWidth - width || nx < 0) return false;

if (ny > Global.stage.stageHeight - height || ny < 0) return false;

// 计算下一目标点的碰撞测试(本部分为新增代码)

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

{

if (obj == this || !obj.hitTest) continue;

for each(var p:Array in _hitPoint)

{

if (obj.hitTestPoint(nx + p[0], ny + p[1], true)) return false;

}

}

...

}

复制代码
我们循环了游戏场景中的所有游戏对象,如果发现游戏对象是自己或者对象并不参与碰撞检测,跳过检测,接下来,循环数组中的8个位置点,逐个判断是否发生了碰撞。如果发生,则返回false。

ActionObject是肯定参与检测的,因此,我们修改了一下ActionObject的构造函数:

public function ActionObject(ctrl:basicController)

{

super();

controller = ctrl;

controller.target = this; // 将控制器的控制目标设置为自己

_hitTest = true;// 打开碰撞检测开关

}

复制代码
在加入碰撞检测后,我们原来的子弹飞行也可以用碰撞检测开关来判断了,因此,我们修改了BulletObject的Do方法:

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.hasOwnProperty('Hurt')) (obj as FaceObject).Hurt(20);

die();

break;

}

}

复制代码
我们改成了用碰撞开关来控制是否进行判断的前提条件,而把是否伤血由属性Hurt来判定。这样,子弹在击中障碍的时候,也会消失,但障碍物不会伤血(因为障碍物可能不具备Hurt方法)

到此,碰撞检测和基本的美化就已经做完了。不过,我的程序的运行界面是这样的:



实际运行swf


main.swf (20.05 KB)

可能你的和我的不太一样吧。呵呵。可以从下面的源码中找到不同。相信经过前面4篇的学习,可以很轻松的看懂现在的源码的:


Teach.rar (408.24 KB)

在下一篇教程中,我们将研究如何更简单的实现地图,同时做一些必要的限制(比如现在可以像冲锋枪一样不停的发射子弹,如果对于一款坦克游戏来讲,这显然不太符合逻辑)。

最后,在这里提醒各位在看本教程的朋友。教程只为引导大家快速写出可以运行的东西,而非进行项目实战。因此一些处理方法并不是最好的,而是比较容易理解和操作的。例如本篇教程中的碰撞检测。对于场景中对象不多的游戏可以胜任,如果游戏对象多起来,效率就会大大降低。选择合适的算法、处理方式,是一个漫长的路程,需要经验的积累和沉淀:)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: