代码改变世界

战争迷雾

2014-06-21 21:25  truenight  阅读(487)  评论(0编辑  收藏  举报

 

 

其实可见区域与不可见区域的重叠只是二进制运算,加上查表得到相应 mask对场景混色即可。之前纠结于如何画出圆形域,实际上直接写一块静态数组更加简单粗暴有效。

首先需要这么一张mask图(右下角应该是纯黑),这个是从9RIA论坛找的,所枚举的情况实在太少,所以画出来的圆形域也不够精细。

image

这张图是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); 
                    } 
                } 
        } 
        
         
    } 
}
以下是两个圆形域叠加在一起的效果,这种实现应该是old fashioned了…

image