从零开始学AS3游戏开发【六】 设置地图

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

转载请注名来源于天地会

前篇勘误:在Monster.as中,第44行对计算频率进行控制时,if (date.time-_lastAction.time > _fps/1000)应为if (date.time-_lastAction.time > 1000/_fps)。感谢各位兄弟的提示!

第六篇 设置地图

上一篇教程中。我们对游戏进行了美化,同时加入了简单的碰撞检测。在本篇中,我们将设置地图,先来看一下我们预期的效果
1.jpg 

像上图这样,如果像我们原来那样通过for循环去生成地图,那基本上写if和else就可以把我们累死了。我们需要寻找规律,来达到批量处理的目的。

从上图我们可以看出,所有的游戏对象都是比较整齐的摆放的。摆放的间距也基本上与游戏对象的宽度成比例。如果我们把可以通过的位置以0来表示,不能通过的位置以1来表示,那么,可以得到下图:
2.jpg 

这让你想到了什么吗?是的,是数组,我们可以用数组来标识地图:

  1. private var mapconfig:Array = [
  2.                         [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  3.                         [0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0],
  4.                         [0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0],
  5.                         [0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0],
  6.                         [1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1],
  7.                         [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  8.                         [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  9.                         [1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1],
  10.                         [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  11.                         [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]                        
  12.                 ];
复制代码

在上面这个数组中,mapconfig[line]记录了第line行的全部地图元素,例如,当line为0的时候,也就是mapconfig[0]的元素“[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]”,可以看出,在这一行中,全部都是空位置。而当line为1的时候,mapconfig[1]的元素“[0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0]”告诉我们,中间有6个元素的位置是障碍物,无法通过。同样的,我们可以用2来表示敌人出现的位置,用3来表示自己的坦克出现的位置,于是,上面的数组就变成了现在这样

  1. private var mapconfig:Array = [
  2.                         [0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0],
  3.                         [0, 2, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0],
  4.                         [0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0],
  5.                         [0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0],
  6.                         [1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1],
  7.                         [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  8.                         [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  9.                         [1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1],
  10.                         [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  11.                         [0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0]                        
  12.                 ];
复制代码

可以看出,在第一行的倒数第三个位置,出现了一个敌人,在第二行的第二个位置,出现了一个敌人,而自己则出现在最后一行的第五个元素。如果你喜欢用y来表示行,用x来表示列的话,那么第y行第x列的地图元素数据应该为mapconfig[y][x]。

好了,下面让我们来用程序实现对这个地图数据的解析。

我们新建一个类,继承自gameScene,暂时定义为D5Scene吧,当然,如果你喜欢其他的名字,可以自己定义:)

在这个类里,我们声明一个用来保存地图数据的变量

  1.                 /**
  2.                  * 地图数据
  3.                  */
  4.                 protected var _mapData:Array;
复制代码

还有一个解析方法,我们需要对_mapData进行循环解析,把其中的数字转换成可以通过的位置,或者障碍物,或者敌人,或者我们自己的角色。

  1.                  /**
  2.                  * 配置地图
  3.                  * 
  4.                  * @param        arr        地图数据
  5.                  */
  6.                 public function setup(arr:Array):void
  7.                 {
  8.                         _mapData = arr;
  9.                         if (arr[0] == null || arr[0][0]==null) return;
  10.                         var y:uint = 0;
  11.                         var x:uint;
  12.                         
  13.                         for each(var line:Array in arr)
  14.                         {
  15.                                 x = 0;
  16.                                 for each(var data:uint in line)
  17.                                 {
  18.                                         if (data != 0)
  19.                                         {
  20.                                                 
  21.                                         }
  22.                                         x++;
  23.                                 }
  24.                                 y++;
  25.                         }
  26.                 }
复制代码

我们需要为setup传递入一个参数arr,即地图的配置文件,而接下来,arr应该是一个2维数组,也就是必须有arr[y][x]这样的结构。因此arr[0]和arr[0][0]都不应该为空,否则就是不符合格式要求的数据,程序将不予以解析。所以,我们在这里做了一个格式判断:if (arr[0] == null || arr[0][0]==null) return;。而接下来,则对数组中的全部数据进行了循环解析。如果发现data不为0,也就是不可通过的位置,则进行相关的处理。

到这里,我们已经可以分析到数组中的全部元素数据了,但是,我们现在得到的是0,1,2,3这样的数字,而不是最终的游戏对象。所以,我们需要有一个函数对这些数字来进行翻译:

  1. /**
  2.                  * 通过数字ID获取对应的元素
  3.                  * 
  4.                  * @param        id        地图数字
  5.                  * @return gameObject
  6.                  */
  7.                 protected function getObjById(id:uint):gameObject
  8.                 {
  9.                         var result:gameObject;
  10.                         switch(id)
  11.                         {
  12.                                 case 1:
  13.                                         result = new Stone(new stuff());
  14.                                         result.part = 1;
  15.                                         break;
  16.                                 case 2:
  17.                                         result = new Monster(new MonsterControler(), new Skin2());
  18.                                         result.part = 2;
  19.                                         break;
  20.                                 case 3:
  21.                                         result = new Player(new KeyController(), new Skin1());
  22.                                         result.part = 3;
  23.                                         break;
  24.                         }
  25.                         return result;
  26.                 }
复制代码

代码都是我们熟悉的,只是根据不同的ID进行了区分而已,不再过多的描述。这样,我们可以在刚才的setup函数中,if (data != 0)后面做文章了,来看一下完整的setup代码:

  1. /**
  2.                  * 配置地图
  3.                  * 
  4.                  * @param        arr        地图数据
  5.                  */
  6.                 public function setup(arr:Array):void
  7.                 {
  8.                         _mapData = arr;
  9.                         if (arr[0] == null || arr[0][0]==null) return;
  10.                         var y:uint = 0;
  11.                         var x:uint;
  12.                         
  13.                         var obj:gameObject;
  14.                         for each(var line:Array in arr)
  15.                         {
  16.                                 x = 0;
  17.                                 for each(var data:uint in line)
  18.                                 {
  19.                                         if (data != 0)
  20.                                         {
  21.                                                 obj = getObjById(data);
  22.                                                 if (obj != null)
  23.                                                 {
  24.                                                         addObject(obj);
  25.                                                         obj.x = obj.width * x;
  26.                                                         obj.y = obj.height * y;
  27.                                                 }
  28.                                         }
  29.                                         x++;
  30.                                 }
  31.                                 y++;
  32.                         }
  33.                 }
复制代码

这里,我们认为所有的游戏对象均使用了相同的规格,因此,可以根据他们在地图元素中的下标来计算其在场景中的坐标。

最后,对游戏的主入口函数做出修改:

  1. private var mapconfig:Array = [
  2.                         [0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0],
  3.                         [0, 2, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0],
  4.                         [0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0],
  5.                         [0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0],
  6.                         [1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1],
  7.                         [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  8.                         [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  9.                         [1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1],
  10.                         [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  11.                         [0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0]                        
  12.                 ];
  13.                 public function Main() 
  14.                 {
  15.                         var scene:D5Scene = new D5Scene(stage);                // 声明游戏舞台
  16.                         scene.setup(mapconfig);
  17.                         // 生成基地
  18.                         var base:Base = new Base(new basicController(),new Skin_base());
  19.                         base.x = (stage.stageWidth-base.width)/2;
  20.                         base.y = stage.stageHeight-base.height;
  21.                         Global.base = base;
  22.                         scene.addObject(base);
  23.                         
  24.                         // 显示游戏舞台
  25.                         addChild(scene);
  26.                 }
复制代码

代码看起来比原来精简多了吧。运行测试一下吧

小问题:现在基地没有放到场景里去,你可以自己修改程序,把基地也通过地图数组来进行管理

小提示:背景改为黑色后,是不是子弹看不见了?去子弹类里把填充色由0x000000改为0xffffff就可以了,白色的子弹就可以看清楚了。

最终效果:
 main.swf (20.31 KB) 

源代码:
 Teach.rar (409.92 KB) 


第七篇教程,也将是从零开始系列的最后一篇。我们将研究简单效果的实现思路,声音的播放,以及游戏道具的实现方法。之后,从零开始系列教程将结束,我们将引入位图缓冲等概念,开启新一系列的教程。

原文地址:https://www.cnblogs.com/keng333/p/2304963.html