战争迷雾
2014-06-21 21:25 truenight 阅读(494) 评论(0) 编辑 收藏 举报
其实可见区域与不可见区域的重叠只是二进制运算,加上查表得到相应 mask对场景混色即可。之前纠结于如何画出圆形域,实际上直接写一块静态数组更加简单粗暴有效。
首先需要这么一张mask图(右下角应该是纯黑),这个是从9RIA论坛找的,所枚举的情况实在太少,所以画出来的圆形域也不够精细。
这张图是4*4 共16个mask单元组成,对每个单元再做4宫格形式的划分。则染黑4宫格中的哪些格子唯一的标识了这个mask单元.如图第2行1列的单元,即可用cell(1,0)=<左上,左下,右下>来表示.
其实里面cell(1,2)和cell(2,1)毫无用处,因为实际场景中迷雾的边缘不会出现这种情况。如果我们需要更精细的迷雾,则每个单元用9宫格划分,那我们需要枚举2^9种mask,当然里面那些不能切合迷雾边缘的是无用的。
如果我们将地图上某块tile的左上,左下,右下,右上四角是否被迷雾笼罩用互斥的位标识,则它们的|运算得到一个二进制的值,这个值表示这块tile到底有多黑。然后根据查询事先设置的表,将这个二进制的值映射成相应的mask单元即可。
package { import flash.display.BitmapData; import flash.geom.ColorTransform; import flash.geom.Matrix; import flash.geom.Rectangle; public class FogUtil { public static const FOW_BIT_1:int = (1 << 0) //左上 public static const FOW_BIT_2:int = (1 << 1) //右上 public static const FOW_BIT_3:int = (1 << 2) //左下 public static const FOW_BIT_4:int = (1 << 3) //右下 public static const fow_none:int = 0; public static const fow_all:int = (FOW_BIT_2|FOW_BIT_1|FOW_BIT_4|FOW_BIT_3); public static const FOW_NUM:int = fow_all; // straights public static const fow_24 = (FOW_BIT_4 | FOW_BIT_2) public static const fow_12 = (FOW_BIT_2| FOW_BIT_1) public static const fow_13 = (FOW_BIT_1 | FOW_BIT_3) public static const fow_34 = (FOW_BIT_3 | FOW_BIT_4) //NE NW 1 2 //SE SW 3 4 // corners public static const fow_123 = (FOW_BIT_2 |FOW_BIT_1 |FOW_BIT_3) public static const fow_124 = (FOW_BIT_1 | FOW_BIT_4 | FOW_BIT_2) public static const fow_234 = ( FOW_BIT_2 |FOW_BIT_3 | FOW_BIT_4) public static const fow_134 = (FOW_BIT_4 | FOW_BIT_1 |FOW_BIT_3) // joins public static const MIN_RADIUS = 1; public static const MAX_RADIUS = 2; private static const circle_mask:Array = [ [ fow_123,fow_12,fow_124, fow_13,fow_none,fow_24, fow_134,fow_34,fow_234, ], [ fow_all,fow_123,fow_12,fow_124,fow_all, fow_123,FOW_BIT_1,fow_none,FOW_BIT_2,fow_124, fow_13,fow_none,fow_none,fow_none,fow_24, fow_134,FOW_BIT_3,fow_none,FOW_BIT_4,fow_234, fow_all,fow_134,fow_34,fow_234,fow_all ] ]; private static var fow_frame_table:Array = null; public function FogUtil() { } public static function buildFowTable():void { if(fow_frame_table) return; fow_frame_table = new Array(FOW_NUM); for(var i:int = 0;i<FOW_NUM;++i) { fow_frame_table[i] = -1; } fow_frame_table[fow_all] = -1; fow_frame_table[FOW_BIT_1] = 7; fow_frame_table[FOW_BIT_2] = 11; fow_frame_table[FOW_BIT_3] = 13; fow_frame_table[FOW_BIT_4] = 14; fow_frame_table[fow_none] = 0; fow_frame_table[fow_24] = 10; fow_frame_table[fow_12] = 3; fow_frame_table[fow_13] = 5; fow_frame_table[fow_34] = 12; fow_frame_table[fow_123] = 1; fow_frame_table[fow_124] = 2; fow_frame_table[fow_234] = 8; fow_frame_table[fow_134] = 4; } public static const MAP_BOUNDX:int = 13; public static const MAP_BOUNDY:int = 10; public static function fowCircleMidpoint(cx:int,cy:int,radius:int,tiles:Array):void { if(radius<MIN_RADIUS || radius>MAX_RADIUS) return; var len:int = (radius*2)+1; var num_entries:int = len*len; var tile_cnt:int = 0; for(var y:int = cy-int(len/2);y<=cy+int(len/2);++y) for(var x:int = cx-int(len/2);x<=cx+int(len/2);++x) { if(x<0 || y<0 || x>=MAP_BOUNDX ||y>=MAP_BOUNDY) { ; } else { var mask:int = circle_mask[radius-MIN_RADIUS][tile_cnt] tiles[y][x] &=mask; } ++tile_cnt; } } public static const OFFC:int = 55; public static function renderFoW(tiles:Array,bmd:BitmapData,mipmap:Vector.<BitmapData>):void { var w:int = Warfog.FOG_CELL_W; var h:int = Warfog.FOG_CELL_H; var ct:ColorTransform = new ColorTransform(1,1,1,1,OFFC,OFFC,OFFC); for(var y:int = 0;y<MAP_BOUNDY;++y) for(var x:int = 0;x<MAP_BOUNDX;++x) { var id:int = tiles[y][x]; var ridx:int = fow_frame_table[id]; if(id< 0 || ridx<0) { //纯黑 bmd.fillRect(new Rectangle(x*w,y*h,w,h),0xff363636); } else { var mip:BitmapData = mipmap[ridx]; bmd.draw(mip,new Matrix(1,0,0,1,x*w,y*h),ct); } } } } }