为网格绘制圆角描边,嗯,我不知道怎么描绘它了

近期老大开始研究各种消除类游戏的界面设计,发现其中一个细节是,我们的界面风格无论怎么看都都有一种硬邦邦的感觉,过多尖锐的直角很容易令人紧张,不利于治愈人心,所以我们开始尝试改变,其中一点就是,如何让尖锐的边缘变得圆润,涉及到要绘制一个连续的圆形边缘效果,两个放在一起对比一下区别还是比较明显的。

[![](http://tiger-a-s-s.tobybai.cn/%2525E5%2525B1%25258F%2525E5%2525B9%252595%2525E5%2525BF%2525AB%2525E7%252585%2525A7%2525202013-11-01%252520%2525E4%2525B8%25258B%2525E5%25258D%25258810.34.24.png)](http://tiger-a-s-s.tobybai.cn/%2525E5%2525B1%25258F%2525E5%2525B9%252595%2525E5%2525BF%2525AB%2525E7%252585%2525A7%2525202013-11-01%252520%2525E4%2525B8%25258B%2525E5%25258D%25258810.34.24.png)
添加了圆角描边
[![](http://tiger-a-s-s.tobybai.cn/%2525E5%2525B1%25258F%2525E5%2525B9%252595%2525E5%2525BF%2525AB%2525E7%252585%2525A7%2525202013-11-01%252520%2525E4%2525B8%25258B%2525E5%25258D%2525889.40.04.png)](http://tiger-a-s-s.tobybai.cn/%2525E5%2525B1%25258F%2525E5%2525B9%252595%2525E5%2525BF%2525AB%2525E7%252585%2525A7%2525202013-11-01%252520%2525E4%2525B8%25258B%2525E5%25258D%2525889.40.04.png)
未添加圆角描边
嗯……我不能强迫人家说上面的比较好看,我觉得上面的比较舒服而已,如果我给它起个名字,就叫《有缓冲的社交关系网》,啊,我在写什么啊,总之今天上午老大要我研究实现这种效果的实现办法,咱是写代码的~得弄出点不容易叫人复制得东西嘛~
[![](http://tiger-a-s-s.tobybai.cn/Challenge_accepted.png)](http://tiger-a-s-s.tobybai.cn/Challenge_accepted.png)
首先我要搞清楚,边缘的判定办法,这时就需要对某一网格做八方位的判定,一共有8个值来对应这些判定结果,于是我定义了一个这样的类来存储他们:
 package  
 {  
      public class GridNeighbor  
      {  
           public var t:Boolean = false;  
           public var b:Boolean = false;  
           public var l:Boolean = false;  
           public var r:Boolean = false;  
           public var tl:Boolean = false;  
           public var tr:Boolean = false;  
           public var bl:Boolean = false;  
           public var br:Boolean = false;  
           public function GridNeighbor()  
           {  
           }  
           public function get haveTROut():Boolean  
           {  
                return t&&r&&tr;  
           }  
           public function get haveTLOut():Boolean  
           {  
                return t&&l&&tl;  
           }  
           public function get haveBROut():Boolean  
           {  
                return b&&r&&br;  
           }  
           public function get haveBLOut():Boolean  
           {  
                return b&&l&&bl;  
           }  
           public function get haveTRInnerT():Boolean  
           {  
                return t&&!tr;  
           }  
           public function get haveTRInnerR():Boolean  
           {  
                return r&&!tr;  
           }  
           public function get haveTLInnerT():Boolean  
           {  
                return t&&!tl;  
           }  
           public function get haveTLInnerL():Boolean  
           {  
                return l&&!tl;  
           }  
           public function get haveBRInnerB():Boolean  
           {  
                return b&&!br;  
           }  
           public function get haveBRInnerR():Boolean  
           {  
                return r&&!br;  
           }  
           public function get haveBLInnerB():Boolean  
           {  
                return b&&!bl;  
           }  
           public function get haveBLInnerL():Boolean  
           {  
                return l&&!bl;  
           }  
           public function toString():String  
           {  
                return "t:"+t+  
                          " b:"+b+  
                          " l:"+l+  
                          " r:"+r+  
                          " tl:"+tl+  
                          " tr:"+tr+  
                          " br:"+br+  
                          " bl:"+bl;  
           }  
      }  
 }  
`</pre>
所有的点都存放在二维数组中,所以我可以很方便地判定某一特定位置是否存在元素,然后遍历他们,判定的条件是,如果某方格的某一方向不存在方格元素,则标记该方向的量为true,也许有很多其他办法,反正我是按照正常人类的思路来模拟的。
判定的函数如下:
<pre>` private function findNeighborBox(theBox:Box):void  
 {  
      var pos:Point = theBox.indexPos;  
      var gn:GridNeighbor = new GridNeighbor();  
      var box:Box;  
      for (var i:int = pos.x - 1; i &lt;= pos.x + 1; i++)   
      {  
           for (var j:int = pos.y - 1; j &lt;= pos.y + 1; j++)   
           {  
                if(i == pos.x &amp;&amp; j == pos.y){  
                     continue;  
                }  
                if(i &lt; 0 || i &gt; COLUMNS - 1 || j &lt; 0 || j &gt; ROWS - 1)  
                {  
                     box = null;  
                }else  
                {  
                     box = arr2d[i][j] as Box;  
                }  
                if(box == null)  
                {  
                     if(i == pos.x)  
                     {  
                          if(j &gt; pos.y){  
                               gn.b = true;  
                          }else{  
                               gn.t = true;  
                          }  
                     }  
                     if(j == pos.y)  
                     {  
                          if(i &gt; pos.x){  
                               gn.r = true;  
                          }else{  
                               gn.l = true;  
                          }  
                     }  
                     if(i &gt; pos.x &amp;&amp; j &gt; pos.y){  
                          gn.br = true;  
                     }  
                     if(i &gt; pos.x &amp;&amp; j &lt; pos.y){  
                          gn.tr = true;  
                     }  
                     if(i &lt; pos.x &amp;&amp; j &lt; pos.y){  
                          gn.tl = true;  
                     }  
                     if(i &lt; pos.x &amp;&amp; j &gt; pos.y){  
                          gn.bl = true;  
                     }  
                }  
           }  
      }  
      theBox.gn = gn;  
 }  
`</pre>
通过这一番标定之后,我就知道每一个方格周边的情况了,开始的时候我考虑的是想通过graphics.beginFill函数,下面开始绘线来实现不规则形状的填充。例如如下代码可以填充出一个三角形,
<pre>` this.graphics.beginFill(0x8C9397,1);  
 this.graphics.moveTo(0,0);  
 this.graphics.lineTo(gap2,0);  
 this.graphics.lineTo(0,-gap2);  
 this.graphics.lineTo(0,0);  
 this.graphics.endFill();  
`</pre>
但是当我发现想让代码逻辑按照人类的思维顺序为不规则方格群组描边是一件如此麻烦的事(我为我是人类而感到庆幸,不过一定有更简单的判定办法,我比较笨),而如果描绘的过程不是按照顺序来的话,就无法实现一个填充的效果。所以我决定改变实现办法。
如果直接为每个方块绘制一个圆角的背景板,出现的效果是这样的。
<div>[![](http://tiger-a-s-s.tobybai.cn/%2525E5%2525B1%25258F%2525E5%2525B9%252595%2525E5%2525BF%2525AB%2525E7%252585%2525A7%2525202013-11-002.png)](http://tiger-a-s-s.tobybai.cn/%2525E5%2525B1%25258F%2525E5%2525B9%252595%2525E5%2525BF%2525AB%2525E7%252585%2525A7%2525202013-11-002.png)</div>
<div>从放大的部分可以清晰地看到,由于每个背景板都是一个圆角矩形,所以当他们连接时就会出现这种豁牙子一般的缺口,为了消除这个缺口,我发现Graphics类居然提供了这么一个函数,drawRoundRectComplex,这个玩意居然并没有被记录在API文档中(有人说是被记录在mx.utils.GraphicUtils中,Why?),从参数可以得知,它可以绘制圆角矩形并指定不同圆角的半径,就是说我可以根据周围的方格情况决定是否要使用半径,或者绘制直角。</div>
<div>下面就开始一马平川了,为每个方格绘制背景板的方法如下(利用之前判断好了的周边情况变量做判断):</div>
<pre>` private function drawOuterRect(theBox:Box, g:Graphics):void  
 {  
      sp.x = theBox.position.x - Box.GAP;  
      sp.y = theBox.position.y - Box.GAP;  
      ep.x = Box.BOX_WIDTH + Box.GAP*2;  
      ep.y = Box.BOX_HEIGHT + Box.GAP*2;  
      var trR:Number = theBox.gn.haveTROut ? Box.GAP*2:0;  
      var tlR:Number = theBox.gn.haveTLOut ? Box.GAP*2:0;  
      var brR:Number = theBox.gn.haveBROut ? Box.GAP*2:0;  
      var blR:Number = theBox.gn.haveBLOut ? Box.GAP*2:0;  
      g.beginFill(0,1);  
      g.beginFill(0x8C9397,1);  
      g.drawRoundRectComplex(sp.x,sp.y,  
                                    ep.x,ep.y,tlR,trR,blR,brR);  
      g.endFill();  
 }  
`</pre>
不过到此为止得到的效果是这样的:
<div>[![](http://tiger-a-s-s.tobybai.cn/%2525E5%2525B1%25258F%2525E5%2525B9%252595%2525E5%2525BF%2525AB%2525E7%252585%2525A7%2525202013-11-01%252520%2525E4%2525B8%25258B%2525E5%25258D%25258811.14.43.png)](http://tiger-a-s-s.tobybai.cn/%2525E5%2525B1%25258F%2525E5%2525B9%252595%2525E5%2525BF%2525AB%2525E7%252585%2525A7%2525202013-11-01%252520%2525E4%2525B8%25258B%2525E5%25258D%25258811.14.43.png)</div>
我觉得看起来还是别扭,原因是当某方块斜上方有一个方块时,他们之间的过度太过生硬,他们需要一些小的圆弧做弥补,
绘制办法如下:
<pre>` package  
 {  
      import flash.display.Sprite;  
      public class EclipseArc extends Sprite  
      {  
           public function EclipseArc()  
           {  
                super();  
                var gap2:int = Box.GAP*2;  
                this.graphics.beginFill(0x8C9397,1);  
                this.graphics.moveTo(0,0);  
                this.graphics.lineTo(gap2,0);  
                this.graphics.lineTo(0,-gap2);  
                this.graphics.lineTo(0,0);  
                this.graphics.moveTo(0,-gap2);  
                this.graphics.curveTo(0,0,gap2,0);  
                this.graphics.endFill();  
           }  
      }  
 }  

最后的效果如下所示: