• AS3地图拼接与战争迷雾的实现[转载]


    本文摘自:http://bbs.9ria.com/thread-157487-1-1.html

    在开发游戏的过程中,特别是地图编辑器中,需要利用最少的资源,实现最丰富的地形地貌。虽然现在众多的RPG开始使用整图,但是我们偶尔还是需要能够让玩家自己编辑地图,或者其他需要自动进行地图构建的功能。
    另外,就是在一些策略类游戏里经常用到的战争迷雾,我试过自己编写Pixel Bender自己来编写过滤器而实现战争迷雾。不过效果不是很理想(速度太慢)。后来想到,可以利用地图拼接的原理来进行战争迷雾的实现。

    数学原理

    首先,我们先来看一下现成的地图拼接算法。下面是一张《魔兽争霸3》的地表素材。

    1.png 

    看到了比较清楚的图片边界是吗?我们把这张图按照64X64进行一下切分

    1.jpg 

    其实把图摆成这样是有原因的,现在,我们来看4张图:1号,2号,4号以及8号。可以发现,他们刚好是四个角落的素材。如果我们把一张64X64的图,再进行4等分,默认以0来标识,如下:

    0   |  0
    ----------------
    0   |  0

    再把刚才所提到的4张图,根据编号和位置,填到上面的结构里,如:

    1号图(右上角):

    0   |  1
    ----------------
    0   |  0


    2号图(左上角):

    2   |  0
    ----------------
    0   |  0


    4号图(右下角):

    0   |  0
    ----------------
    0   |  4


    8号图(左下角):

    0   |  0
    ----------------
    8   |  0


    或许你会很奇怪,我们为什么要定义这4个数字,下面,来做一些有趣的事情吧。

    我们把4号结构和8号结构按照对应的位置相加,得到了什么?

    0   |  0
    ----------------
    8   |  4


    此时,4个角落的数字相加,为0+0+4+8 = 12

    12,这个数字貌似我们在前面的图中看到过,找找编号看。你会发现,刚好12就是下面连成一气的草地素材。

    再做个其他试验?例如把8号和1号结构相加:

    0   |  1
    ----------------
    8   |  0


    此时,4个角落的数字相加,为0+1+8+0=9

    当然,9也刚好就是我们的素材里,右下和左上连成一气的草地素材。

    数学原理:以1,2,4,8分别代表一个区块的4个角落的素材编号。当发生叠加时候,将角落里的值进行累加,最后,4个角的合即为地图区块所对应的编号。

    程序实现

    有了数学原理,下一步就是通过程序去实现他。首先,我们需要根据编号,来保存对应的素材,为了大家看的清楚,我用了比较笨的方法——二维数组,实际上,循环取一次就可以了。
    1. // 用一个数组来标记图形中各个位置的编号
    2. var config:Array = [
    3.                                         [0,4,8,12],
    4.                                         [1,5,9,13],
    5.                                         [2,6,10,14],
    6.                                         [3,7,11,15],
    7.                                         ];
    复制代码
    然后,把图片中的各个部分取出来,放到一个数组去,数组的下表刚好就是这个图片素材的编号:
    1. // 用来存放图片素材的数组
    2. var lib:Array = new Array();
    3. var bitmap:BitmapData;
    4. // 源素材,就是我们上面的那张PNG
    5. var bd:BitmapData = new BMD();

    6. var py:uint;
    7. var px:uint;
    8. // 进行切割
    9. for(py = 0;py<config.length;py++)
    10. {
    11.         var line:Array = config[py];
    12.         for(px = 0;px < line.length;px++)
    13.         {
    14.                 bitmap = new BitmapData(128,128,true,0);
    15.                 bitmap.copyPixels(bd,new Rectangle(px*128,py*128,128,128),new Point(),null,null,true);
    16.                 // 把素材编号作为下表进行素材的保存
    17.                 lib[line[px]] = bitmap;
    18.         }
    19. }
    复制代码
    好了,这样,素材就准备好了。下面我们做一个地图试验一下

    首先,生成一个空地图,还是用数组好了:
    1.                         var arr:Array = new Array();
    2.                         // 生成10X10的地图
    3.                         for(py=0;py<10;py++)
    4.                         {
    5.                                 var data:Array = new Array();
    6.                                 for(px=0;px<10;px++)
    7.                                 {
    8.                                         // 每个地图区块包含4个顶点数据,默认为0
    9.                                         data.push([0,0,0,0]);
    10.                                 }
    11.                                 arr.push(data);
    12.                         }
    复制代码
    来看一下,当我们点击(或者说叫做地图的笔刷。。。)时,我们期望发生什么情况:

    2.jpg 

    当我们点下鼠标时候,如图所示,我们会把鼠标指针所在的位置的顶点数值设置为4,而临近的顶点数值分别设置为8,1,2,刚好拼凑成上面这样的图形。

    当然,同样用这样的方法在临近的位置点击,我们就会得到这样的效果:

    3.jpg 

    如图,我们点击的鼠标位置,和上次点击一样,我们把点击的位置顶点值设置为4,临近顶点为8,1,2。而此时,因为这个顶点和上次的8号顶点其实在同一个Tile里,导致这个Tile内的顶点总和变成了12,所以更换了素材。于是我们得到了一个非常平滑的过度。

    当然,再继续点下去,也是同样的算法,这里就不再赘述了。

    4.jpg 

    来看一下后面的代码,点击的时候,当然是计算点击位置对应的区块,然后把改区块的右下角顶点值设置为4,这里要注意,如果这个顶点已经是4了,那就没必要再设置了。如果再设置,这个顶点变成了8,很显然就不对了。
    1. stage.addEventListener(MouseEvent.CLICK,onClick);


    2. function onClick(e:MouseEvent):void
    3. {
    4.         // 计算区块
    5.         var _mx:uint = int(e.stageX/64);
    6.         var _my:uint = int(e.stageY/64);
    7.         // 区块顶点设置,3右下 2右上 1左下  0左上
    8.         if(arr[_my][_mx][3]!=4) arr[_my][_mx][3]+=4; // 当前区块的右下
    9.         if(arr[_my][_mx+1][1]!=8) arr[_my][_mx+1][1]+=8; // 右边区块的左下
    10.         if(arr[_my+1][_mx][2]!=1)arr[_my+1][_mx][2]+=1; // 下面区块的右上
    11.         if(arr[_my+1][_mx+1][0]!=2)arr[_my+1][_mx+1][0]+=2; // 下面右边区块的左上
    12.         reDraw();
    13. }
    复制代码
    然后就是根据现在的顶点,重新绘制地形:
    1. var resBD:BitmapData = new BitmapData(640,640,true,0xff000000);
    2. addChild(new Bitmap(resBD));

    3. function reDraw():void
    4. {
    5.         resBD.fillRect(resBD.rect,0);
    6.         for(py=0;py<10;py++)
    7.                         {
    8.                                 for(px=0;px<10;px++)
    9.                                 {
    10.                                         var b:uint=arr[py][px][0]+arr[py][px][1]+arr[py][px][2]+arr[py][px][3];// 计算顶点合
    11.                                         
    12.                                         if(b==0) continue;
    13.                                         if(b>15) b=15; // 超出15的顶点合是没有意义的。在魔兽争霸里,超出15会随机一个填充满的样式以丰富地表
    14.                                         resBD.copyPixels(lib[b],lib[b].rect,new Point(px*64,py*64),null,null,true);
    15.                                 }
    16.                         }
    17. }
    复制代码
    战争迷雾扩展

    同样的原理,只要我们把素材处理成战争迷雾的黑色和半透明,即可实现战争迷雾效果。

    2.png 

    5.jpg 


    源码

     mis.fla (347.23 KB, 下载次数: 501)
  • 相关阅读:
    Java中的多线程
    Service组件
    Notification和Notification Manager的使用
    Java网络编程
    Intent组件
    Android 多任务多线程断点下载
    hdu 2045
    hdu 2492
    poj 2785
    湖南省第六届程序设计大赛D(台球碰撞)
  • 原文地址:https://www.cnblogs.com/hyamw/p/2776775.html
Copyright © 2020-2023  润新知