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; }

浙公網安備 33010602011771號