zoukankan      html  css  js  c++  java
  • 从零开始学AS3游戏开发【七】永无终结,不断完善的游戏

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

    转载请注名来源于天地会

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

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

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

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

    1.jpg 

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

    1. dispatchEvent(new Event(Event.COMPLETE));
    2. stop();
    复制代码

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

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

    1. package D5Power.Objects 
    2. {
    3.         import flash.display.MovieClip;
    4.         import flash.events.Event;
    5.         /**
    6.          * 爆炸效果
    7.          * @author ...
    8.          */
    9.         public class BoomEffect extends gameObject
    10.         {
    11.                 protected var _face:MovieClip;
    12.                 /**
    13.                  * 
    14.                  * @param        face        效果MC
    15.                  */
    16.                 public function BoomEffect(face:MovieClip) 
    17.                 {
    18.                         _face = face;
    19.                         addChild(_face);
    20.                         _face.addEventListener(Event.COMPLETE, onComplate);
    21.                 }
    22.                 
    23.                 /**
    24.                  * 侦听到动画的播放结束事件
    25.                  * @param        e
    26.                  */
    27.                 private function onComplate(e:Event):void
    28.                 {
    29.                         Global.scene.removeObject(this);
    30.                         
    31.                 }
    32.                 
    33.                 override public function die():void
    34.                 {
    35.                         removeChild(_face);
    36.                         _face = null;
    37.                 }
    38.                 
    39.         }
    40. }
    复制代码

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

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

    1.                 override public function Do():void
    2.                 {
    3.                         ...
    4.                         for each(var obj:gameObject in Global.scene.AllObject)
    5.                         {
    6.                                 if (obj.hitTest && obj.part!=_shooter.part && obj!=this && obj.hitTestPoint(x, y, true))
    7.                                 {
    8.                                         // 击中目标
    9.                                         if (!obj.hitTest) continue;
    10.                                         showBoom();
    11.                                         if(obj.hasOwnProperty('Hurt')) (obj as FaceObject).Hurt(20);
    12.                                         Global.scene.removeObject(this);
    13.                                         break;
    14.                                 }
    15.                         }
    16.                         
    17.                         if (x<0 || x>Global.stage.stageWidth || y<0 || y>Global.stage.stageHeight)
    18.                         {
    19.                                 showBoom();
    20.                                 Global.scene.removeObject(this);
    21.                         }
    22.                 }
    23.                 /**
    24.                  * 实现爆炸效果
    25.                  */
    26.                 protected function showBoom():void
    27.                 {
    28.                         var boom:BoomEffect = new BoomEffect(new boom01());
    29.                         boom.x = x;
    30.                         boom.y = y;
    31.                         Global.scene.addObject(boom);
    32.                 }
    复制代码

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

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

    3.jpg 

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

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

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

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

    1. package D5Power.Objects 
    2. {
    3.         import flash.display.MovieClip;
    4.         
    5.         /**
    6.          * 道具物品
    7.          * @author ...
    8.          */
    9.         public class Item extends gameObject 
    10.         {
    11.                 protected var _face:MovieClip
    12.                 /**
    13.                  * 
    14.                  * @param        face        皮肤MC
    15.                  */
    16.                 public function Item(face:MovieClip) 
    17.                 {
    18.                         _face = face;
    19.                         _hitTest = false; // 不参与子弹碰撞
    20.                         addChild(_face);
    21.                 }
    22.                 
    23.                 /**
    24.                  *
    25.                  */
    26.                 override public function Do():void
    27.                 {
    28.                         // 检查是否发生碰撞
    29.                         for each(var obj:gameObject in Global.scene.AllObject)
    30.                         {
    31.                                 if (obj is Player || obj is Monster)
    32.                                 {
    33.                                         if (hitTestObject(obj))
    34.                                         {
    35.                                                 (obj as ActionObject).Speed = 2.4;
    36.                                                 Global.scene.removeObject(this);
    37.                                                 break;
    38.                                         }
    39.                                 }
    40.                         }
    41.                 }
    42.                                 
    43.                 override public function die():void
    44.                 {
    45.                         removeChild(_face);
    46.                         _face = null;
    47.                 }
    48.                 
    49.         }
    50. }
    复制代码

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

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

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

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

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

    1. var timer:Timer = new Timer(30000);
    2.                         timer.addEventListener(TimerEvent.TIMER, createItem);
    3.                         timer.start();
    复制代码

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

    1. private function createItem(e:TimerEvent):void
    2.                 {
    3.                         for each(var obj:gameObject in Global.scene.AllObject)
    4.                         {
    5.                                 if (obj is Item) Global.scene.removeObject(obj);
    6.                         }
    7.                         
    8.                         var p:Point = getRandomPlace();
    9.                         var item:Item = new Item(new item_upspeed());
    10.                         item.x = item.width * p.x;
    11.                         item.y = item.height * p.y;
    12.                         Global.scene.addObject(item);
    13.                 }
    复制代码

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

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

    1. /**
    2.                  * 查找一个空的位置
    3.                  * @return
    4.                  */
    5.                 private function getRandomPlace():Point
    6.                 {
    7.                         var ry:uint = int(Math.random() * mapconfig.length);
    8.                         var rx:uint = int(Math.random() * mapconfig[0].length);
    9.                         if (mapconfig[ry][rx] == 0) return new Point(rx, ry);
    10.                         return getRandomPlace();
    11.                 }
    复制代码

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

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

    4.jpg 

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

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

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


    写在最后

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

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

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

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

    D5Power

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

    本篇最终源码:

     teach.rar (414.56 KB)

  • 相关阅读:
    html5数字和颜色输入框
    WinForm设置右键菜单
    设置窗体透明C#代码
    C#调用windows api示例
    使用VS GDB扩充套件在VS上远端侦错Linux上的C/C++程序
    javascript系统时间测试题
    博客园学习的好地方
    基于jQuery的自适应图片左右切换
    HTML+CSS代码橙色导航菜单
    ASP.NET使用UpdatePanel实现AJAX
  • 原文地址:https://www.cnblogs.com/keng333/p/2304966.html
Copyright © 2011-2022 走看看