flex 联机游戏开发 - 五子棋游戏:(一)游戏核心

刚看到flex做的东西的时候,一下子很怀念当年用applet编程的日子,applet真的算是互联网的美好时光之一,可惜在主流浏览器的绞杀下最终烟消云散,过了10年,adobe又把这东西拾起来做成了flex,而我,在羡慕adobe flash 98%的用户装机量的同时,也不得不选择了用flex来开发一些自己的应用,能信任silverlight吗,连微软都要风传收购adobe的时候?你能信任javafx吗,他自己历时10年都掌握不了主流的互联网浏览器,很意外oracle为什么不把firefox一起收购了。这样,。。这样。

Hello,wolrd是所有程序员的开始,五子棋游戏应该也算是所有联机游戏开发的开始吧,我今天用这个游戏来练练手,了解一下flex的主要功能,换肤技术等,力求用最真实的开发过程来展示开发中的问题与思考。

1) 巧妇难为无米之炊,先画一个棋盘吧,,我斩时希望这个棋盘基本素质是,横,竖 一些线条,另外,在每个线杀的交叉点上有一个默认的棋子。额外的素质是,1,棋盘的线条多少是可变的,2)棋子的点击半径是可变的。棋子的颜色是可变的。

好了。画棋盘。。

1) 五子棋棋盘

//棋子直径 
   private var radios:int=22; 
   //边间隔 
   private var padding:int=20; 
   //线条的多少,代表了五子棋的难度 
   private var totalsize:int=15; 
   //棋子的数组 
   private var boardArray:Array; 
   //默认的颜色,与背景色同, 
   private const DEFAULT_COLOR:SolidColor=new SolidColor(0xeeeeee,0); 
   //黑棋 
   private const BLACK_COLOR:SolidColor=new SolidColor(0x000000,1); 
   //白棋 
   private const WHITE_COLOR:SolidColor=new SolidColor(0xffffff,1); 
   //玩家一 
   private const PLAYER_RONE_TURN:int=0; 
   //玩家二 
   private const PLAYER_TWO_TURN:int=1; 
   //当前玩家 
   private var turn:int;

//y 轴的线条 
    for (var i:int=0;i<=totalsize;i++) 
    { 
     var line:Line=new Line(); 
     line.xFrom=0+padding; 
     line.xTo=board.width-padding; 
     line.y=i*(board.height-2*padding)/totalsize+padding; 
     line.stroke=new SolidColorStroke(0x000000,1,1,false); 
     board.addElement(line); 
    } 
    //x 轴的线条 
    for (var j:int=0;j<=totalsize;j++) 
    { 
     var line2:Line=new Line(); 
     line2.yFrom=0+padding; 
     line2.yTo=board.height-padding; 
     line2.x=j*(board.width-2*padding)/totalsize+padding; 
     line2.stroke=new SolidColorStroke(0x000000,1,1,false); 
     board.addElement(line2); 
    } 
    //默认的棋子, 
    for (var x:int=0;x<=totalsize;x++) 
    { 
     for (var y:int=0;y<=totalsize;y++) 
     { 
      var ellipse:Ellipse=new Ellipse(); 
      ellipse.width=radios; 
      ellipse.height=radios; 
      ellipse.x=x*(board.width-2*padding)/totalsize-radios/2+padding; 
      ellipse.y=y*(board.height-2*padding)/totalsize-radios/2+padding; 
      ellipse.fill=DEFAULT_COLOR; 
      board.addElement(ellipse); 
      boardArray[x][y]=ellipse; 
     } 
    }

棋盘的mxml文件中

<s:BorderContainer backgroundColor="#eeeeee" id="board" borderVisible="false"  verticalCenter="0" horizontalCenter="0" click="boardClick(event)" width="400" height="400"> 
</s:BorderContainer>

画出来的效果如图

2 五子棋事件

现在已经有锅了,开始上米,给棋盘添加点击事件,逻辑就是当用户点中上面的黑色的圆框时,我们就让这个圆框根据用户的角色变颜色。形成自己的棋子。点击后就将游戏当前玩家交给另一方。将上面那个棋盘的测试黑棋换成背景色就可以开始了。

protected function boardClick(event:MouseEvent):void{ 
    var posx:int=event.localX; 
    var posy:int=event.localY; 
    var clickEllipse:Ellipse; 
    for (var x:int=0;x<=totalsize;x++) 
    { 
     for (var y:int=0;y<=totalsize;y++) 
     { 
      var ellipse:Ellipse=boardArray[x][y] as Ellipse; 
      if (posx>=ellipse.x && posx<=(ellipse.x+radios)&&posy>=ellipse.y &&posy<=(ellipse.y+radios)) 
       { 
        clickEllipse=ellipse; 
        break; 
       } 
     } 
    } 
    if (clickEllipse==null) return; 
    if (clickEllipse.fill!=DEFAULT_COLOR) return; 
    if (turn==PLAYER_RONE_TURN) 
    { 
     clickEllipse.fill=BLACK_COLOR; 
     turn=PLAYER_TWO_TURN; 
    } 
    else 
    { 
     clickEllipse.fill=WHITE_COLOR; 
     turn=PLAYER_RONE_TURN; 
    } 
   }

效果如图。

3)五子棋胜负判断

现在,你如果跟你朋友下这个棋盘的话,把子填满也是分出胜负的,我们得加上一些判断胜负的条件,对于一个联机游戏,不涉及人工智能是比较简单的,当用户投子后我们只要判断用户的横,竖,斜4个方向是否有五个子连成一条线,有的话就表示用户胜利了。

在click事件的后部加上

if (isWinner()) 
    { 
     mx.controls.Alert.show("玩家"+turn+"记得比赛"); 
     initBoard(); 
    }

然后专心做isWinner()函数。我们可以通过暴力的方式获得当前ellipse的坐标值,但显然,代码就不容易让人理解,为了把视图与逻辑进行分离,我们需要引入另一个数组来定位用户下的棋的一个点,这个点包括四个值,x丝标,y坐标,棋子所属的玩家,还有一个圆。就命名为Qizhi吧。

public class Qizhi 
{ 
  public var x:int; 
  public var y:int; 
  public var turn:int; 
  public var ellipse:Ellipse; 
  public function Qizhi(x:int,y:int,turn:int,ellipse:Ellipse) 
  { 
   this.x=x; 
   this.y=y; 
   this.turn=turn; 
   this.ellipse=ellipse; 
  } 
}

click后的函数的第一次重构

protected function boardClick(event:MouseEvent):void{ 
    var posx:int=event.localX; 
    var posy:int=event.localY; 
    var clickQizhi:Qizhi; 
    for (var x:int=0;x<=totalsize;x++) 
    { 
     for (var y:int=0;y<=totalsize;y++) 
     { 
      var qizhi:Qizhi=boardArray[x][y] as Qizhi; 
      var ellipse:Ellipse=qizhi.ellipse as Ellipse; 
      if (posx>=ellipse.x && posx<=(ellipse.x+radios)&&posy>=ellipse.y &&posy<=(ellipse.y+radios)) 
       { 
        clickQizhi=qizhi; 
        break; 
       } 
     } 
    } 
    if (clickQizhi==null) return; 
    var clickEllipse:Ellipse=clickQizhi.ellipse as Ellipse; 
    if (clickQizhi.turn!=PLAYER_NONE) return; 
    if (turn==PLAYER_ONE_TURN) 
    { 
     clickQizhi.turn=PLAYER_ONE_TURN; 
     clickEllipse.fill=BLACK_COLOR; 
    } 
    else 
    { 
     clickQizhi.turn=PLAYER_TWO_TURN; 
     clickEllipse.fill=WHITE_COLOR; 
    } 
    if (isWinner(clickQizhi)) 
    { 
     mx.controls.Alert.show("玩家 "+turn+" 赢得比赛","恭喜你!"); 
     if (winArray.length>0) 
     { 
      for each(var item:Qizhi in winArray) 
      { 
       item.ellipse.fill=RED_COLOR; 
      } 
     } 
     board.removeEventListener(MouseEvent.CLICK,boardClick); 
     btnstart.enabled=true; 
     btnlose.enabled=false; 
     return; 
    } 
    if (turn==PLAYER_ONE_TURN) 
    { 
     turn=PLAYER_TWO_TURN; 
    } 
    else 
    { 
     turn=PLAYER_ONE_TURN; 
    } 
   }

判断胜负的寒素

private function isWinner(clickQizhi:Qizhi):Boolean { 
    //判断横向 
    if (xWinner(clickQizhi)) return true; 
    //判断横向 
    if (yWinner(clickQizhi)) return true; 
    //判断斜向 
    if (xy13Winner(clickQizhi)) return true; 
    if (xy24Winner(clickQizhi)) return true; 
    return false; 
   } 
   private function xWinner(clickQizhi:Qizhi):Boolean{ 
    winArray=new ArrayCollection(); 
    for (var xRight:int=clickQizhi.x+1;(xRight<=totalsize&&xRight<clickQizhi.x+5);xRight++) 
    { 
     var qizhiRight:Qizhi=boardArray[xRight][clickQizhi.y] as Qizhi; 
     if (qizhiRight.turn==clickQizhi.turn) 
     { 
      winArray.addItem(qizhiRight); 
     } 
     else 
     { 
      break; 
     } 
    } 
    for (var xLeft:int=clickQizhi.x-1;(xLeft>=0&&xLeft>clickQizhi.x-5);xLeft--) 
    { 
     var qizhiLeft:Qizhi=boardArray[xLeft][clickQizhi.y] as Qizhi; 
     if (qizhiLeft.turn==clickQizhi.turn) 
     { 
      winArray.addItem(qizhiLeft); 
     } 
     else 
     { 
      break; 
     } 
    } 
    if (winArray.length>=4) 
    { 
     winArray.addItem(clickQizhi); 
     return true; 
    } 
    return false; 
   } 
   private function yWinner(clickQizhi:Qizhi):Boolean{ 
    winArray=new ArrayCollection(); 
    var length:int=1; 
    for (var yRight:int=clickQizhi.y+1;(yRight<=totalsize&&yRight<clickQizhi.y+5);yRight++) 
    { 
     var qizhiBottom:Qizhi=boardArray[clickQizhi.x][yRight] as Qizhi; 
     if (qizhiBottom.turn==clickQizhi.turn) 
     { 
      winArray.addItem(qizhiBottom); 
     } 
     else 
     { 
      break; 
     } 
    } 
    for (var yLeft:int=clickQizhi.y-1;(yLeft>=0&&yLeft>clickQizhi.y-5);yLeft--) 
    { 
     var qizhiTop:Qizhi=boardArray[clickQizhi.x][yLeft] as Qizhi; 
     if (qizhiTop.turn==clickQizhi.turn) 
     { 
      winArray.addItem(qizhiTop); 
     } 
     else 
     { 
      break; 
     } 
    } 
    if (winArray.length>=4) 
    { 
     winArray.addItem(clickQizhi); 
     return true; 
    } 
    return false; 
   } 
   private function xy24Winner(clickQizhi:Qizhi):Boolean{ 
    winArray=new ArrayCollection(); 
    //第四象限 
    for (var yRight:int=clickQizhi.y+1;(yRight<=totalsize&&yRight<clickQizhi.y+5);yRight++) 
    { 
     if (clickQizhi.x+(yRight-clickQizhi.y)<=totalsize) 
     { 
      var qizhiRight:Qizhi=boardArray[clickQizhi.x+(yRight-clickQizhi.y)][yRight] as Qizhi; 
      if (qizhiRight.turn==clickQizhi.turn) 
      { 
       winArray.addItem(qizhiRight); 
      } 
      else 
      { 
       break; 
      } 
     } 
     else 
     { 
      break; 
     } 
    } 
    //第二象限 
    for (var yLeft:int=clickQizhi.y-1;(yLeft>=0&&yLeft>clickQizhi.y-5);yLeft--) 
    { 
     if (clickQizhi.x-yLeft>=0) 
     { 
      var qizhiLeft:Qizhi=boardArray[clickQizhi.x-(clickQizhi.x-yLeft)][yLeft] as Qizhi; 
      if (qizhiLeft.turn==clickQizhi.turn) 
      { 
       winArray.addItem(qizhiLeft); 
      } 
      else 
      { 
       break; 
      } 
     } 
     else 
     { 
      break; 
     } 
    } 
    if (winArray.length>=4) 
    { 
     winArray.addItem(clickQizhi); 
     return true; 
    } 
    return false; 
   } 
   private function xy13Winner(clickQizhi:Qizhi):Boolean{ 
    winArray=new ArrayCollection(); 
    //第三象限 
    for (var yRight:int=clickQizhi.y+1;(yRight<=totalsize&&yRight<clickQizhi.y+5);yRight++) 
    { 
     if (clickQizhi.x-(yRight-clickQizhi.y)>=0) 
     { 
      var qizhiBottom:Qizhi=boardArray[clickQizhi.x-(yRight-clickQizhi.y)][yRight] as Qizhi; 
      if (qizhiBottom.turn==clickQizhi.turn) 
      { 
       winArray.addItem(qizhiBottom); 
      } 
      else 
      { 
       break; 
      } 
     } 
     else 
     { 
      break; 
     } 
    } 
    //第一象限 
    for (var yLeft:int=clickQizhi.y-1;(yLeft>=0&&yLeft>clickQizhi.y-5);yLeft--) 
    { 
     if (clickQizhi.x+(clickQizhi.y-yLeft)<=totalsize) 
     { 
      var qizhiTop:Qizhi=boardArray[clickQizhi.x+(clickQizhi.y-yLeft)][yLeft] as Qizhi; 
      if (qizhiTop.turn==clickQizhi.turn) 
      { 
       winArray.addItem(qizhiTop); 
      } 
      else 
      { 
       break; 
      } 
     } 
     else 
     { 
      break; 
     } 
    } 
    if (winArray.length>=4) 
    { 
     winArray.addItem(clickQizhi); 
     return true; 
    } 
    return false; 
   }

posted @ 2010-12-20 19:06  博弈居  阅读(829)  评论(0编辑  收藏  举报

我的微博