近期2048游戏好像挺火。在公交,吃饭,甚至在路上走路都有人拿着手机在玩,之前我看同事玩,认为非常幼稚,移来移去太无聊了吧
到后面自己也下了。发现确实挺无聊的,也就是在无聊的时候打发无聊的时间,后来就想用flex写
下这个游戏。 移动的逻辑借鉴了这个安卓的实现:http://www.jikexueyuan.com/study/index/cid/43/lid/9.html
上个周末实现了上下左右移动的逻辑。今天晚上把界面和一些样式加上一些小BUG攻克了下,基本上玩是没问题了
先看几张我刚刚玩的截图:
以下就看看代码吧,代码中有相关凝视,这里就不啰嗦了
首先新建一个组件 NumberTile.mxml
<?xml version="1.0" encoding="utf-8"?> <s:Group xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:mx="library://ns.adobe.com/flex/mx" width="100%" height="100%"> <fx:Declarations> <!-- 布丰(Bufoon)--> </fx:Declarations> <fx:Script> <![CDATA[ [Bindable] public var text:String; [Bindable] public var textColor:uint; [Bindable] public var bacolor:uint [Bindable] public var textSize:uint = 40; ]]> </fx:Script> <s:BorderContainer width="100%" height="100%" cornerRadius="1" borderVisible="false" backgroundColor="{bacolor}"> <s:Label text="{text}" color="{textColor}" verticalCenter="0" fontWeight="bold" fontFamily="Microsoft YaHei" fontSize="{textSize}" horizontalCenter="0"/> </s:BorderContainer> </s:Group>
主应用Main.mxml
<?xml version="1.0" encoding="utf-8"?> <s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600" initialize="initApp(event)" addedToStage="stage.addEventListener(KeyboardEvent.KEY_DOWN,appKeyDown)" > <fx:Declarations> <!-- 布丰(Bufoon)--> </fx:Declarations> <fx:Script> <![CDATA[ import mx.controls.Alert; import mx.events.CloseEvent; import mx.events.FlexEvent; //存放方格的Vector private var tileVector:Vector.<NumberTile> = new Vector.<NumberTile>(); [Bindable] private var score:int = 0; //得分 private var winContinue:Boolean = true; //赢了是否继续 protected function initApp(event:FlexEvent):void { // 游戏初始化 // 加入16个方格 for(var i:int = 0; i < 16; i++){ //自己定义的方格组件 var bcChild:NumberTile = new NumberTile(); bcChild.bacolor = 0xCDC0B4; //设置背景色 bcChild.name = i + ""; //加入组件名称 tileVector.push(bcChild); //将创建的组件加入到Vector bcc.addElement(bcChild); //加入到容器中 } //加入键盘事件 this.addEventListener(KeyboardEvent.KEY_DOWN, appKeyDown); } [Bindable] private var isStart:Boolean = true; protected function start_clickHandler(event:MouseEvent):void { //随机生成两个方格的数字 this.get2or4(this.getNullTileIndex()); this.get2or4(this.getNullTileIndex()); isStart = false; } protected function restart_clickHandler(event:MouseEvent):void { isStart = false; //随机生成两个方格的数字 for(var i:int = 0; i < tileVector.length; i++){ tileVector[i].text = null; tileVector[i].bacolor = 0xCDC0B4; } score = 0; this.get2or4(this.getNullTileIndex()); this.get2or4(this.getNullTileIndex()); } //随机产生方格的数字 num:随机产生的空方格索引 private function get2or4(num:int):void{ if(num == -1){ return; } var str:String = "2"; //方格数字 var bacolor:uint = 0xEEE4DA; //数字相应的背景颜色 var randonNum:int = Math.round(Math.random()*10); //随机数 var nt:NumberTile = tileVector[num]; //获取方格对象 if(randonNum > 8){ //假设随机数大于8 就是4,相当于概率在20%左右 str = "4"; //更改方格数字 bacolor = 0xEDE0C8; //设置数字相应的方格背景颜色 } //更改生成的方格数字,背景色和文字颜色 nt.text = str; nt.textColor = 0x776E65; nt.bacolor = bacolor; } //随机获取空的方格的索引 private function getNullTileIndex():Number{ //空方格 数组 var nullArray:Array = new Array(); for(var i:int = 0; i < tileVector.length; i++){ if(tileVector[i].text == null){ nullArray.push(tileVector[i].name); } } //假设没有空的方格返回-1 相应get2or4方法里面的为-1,就不生成方格 if(nullArray.length == 0){ return -1; } var num:Number = Math.round(Math.random()*(nullArray.length - 1)); return Number(nullArray[num]); } //键盘上下左右方向键处理 protected function appKeyDown(event:KeyboardEvent):void { // TODO Auto-generated method stub switch(event.keyCode.toString()) { case "37": //left { this.leftMoveHandle(); break; } case "38": //top { this.upMoveHandle(); break; } case "39": //right { this.rightMoveHandle(); break; } case "40": { this.downMoveHandle(); break; //bottom } } } /** * 上下左右按键的操作逻辑,由于flex中没有二维数组。只是也能够模拟二维数组,就是用下标表示 * 可是这里没有模拟而是直接就操作Vecotr容器 * 由于总共是16个方格,4*4矩阵,加入两个循环 * 例如以下矩阵: * 0 1 2 3 * 4 5 6 7 * 8 9 10 11 * 12 13 14 15 * * 看以下两组公式 : * 【4*i+j】和【4*i+j1】获取行索引--左右 * 【4*j+i】和【4*j1+i】获取列索引--上下 * * 上下左右逻辑都几乎相同,就是循环的比較两个相邻方格。然后做操作 **/ private function leftMoveHandle():void{ this.checkComplete(); //检測游戏是否结束 var moveFlag:Boolean = false; //移动标记。用来推断是否生成方格数字 var count:Number = 0; //用来推断中间是否有相隔的数字,如 242这样 for(var i:int = 0; i < 4; i++){ for(var j:int = 0; j < 4; j++){ for(var j1:int = j + 1; j1 < 4; j1++){ if(tileVector[4*i+j1].text != null){ if(tileVector[4*i+j].text == null){ this.setTileStyle(i,j,j1,0,0); j--; //继续本行的循环 moveFlag = true; break; } else if(tileVector[4*i+j].text == tileVector[4*i+j1].text){ if(count == 0){ score = score + int(tileVector[4*i+j].text)*2; this.setTileStyle(i,j,j1,0,1); moveFlag = true; break; } } else{ count++; } } } count = 0; } } isWin(); if(moveFlag){ this.get2or4(this.getNullTileIndex()); } } private function rightMoveHandle():void{ this.checkComplete(); var moveFlag:Boolean = false; var count:Number = 0; for(var i:int = 0; i < 4; i++){ for(var j:int = 3; j >= 0; j--){ for(var j1:int = j - 1; j1 >= 0; j1--){ if(tileVector[4*i+j1].text != null){ if(tileVector[4*i+j].text == null){ this.setTileStyle(i,j,j1,0,0); j++; moveFlag = true; break; } else if(tileVector[4*i+j].text == tileVector[4*i+j1].text){ if(count == 0){ score = score + int(tileVector[4*i+j].text)*2; this.setTileStyle(i,j,j1,0,1); moveFlag = true; break; } } else{ count++; } } } count = 0; } } isWin(); if(moveFlag){ this.get2or4(this.getNullTileIndex()); } } private function upMoveHandle():void{ this.checkComplete(); var moveFlag:Boolean = false; var count:Number = 0; for(var i:int = 0; i < 4; i++){ for(var j:int = 0; j < 4; j++){ for(var j1:int = j + 1; j1 < 4; j1++){ if(tileVector[4*j1+i].text != null){ if(tileVector[4*j+i].text == null){ this.setTileStyle(i,j,j1,1,0); j--; moveFlag = true; break; } else if(tileVector[4*j+i].text == tileVector[4*j1+i].text){ if(count == 0){ score = score + int(tileVector[4*j+i].text)*2; this.setTileStyle(i,j,j1,1,1); moveFlag = true; break; } } else{ count++; } } } count = 0; } } isWin(); if(moveFlag){ this.get2or4(this.getNullTileIndex()); } } private function downMoveHandle():void{ this.checkComplete(); var moveFlag:Boolean = false; var count:Number = 0; for(var i:int = 0; i < 4; i++){ for(var j:int = 3; j >= 0; j--){ for(var j1:int = j - 1; j1 >= 0; j1--){ if(tileVector[4*j1+i].text != null){ if(tileVector[4*j+i].text == null){ this.setTileStyle(i,j,j1,1,0); j++; moveFlag = true; break; } else if(tileVector[4*j+i].text == tileVector[4*j1+i].text){ if(count == 0){ score = score + int(tileVector[4*j+i].text)*2; this.setTileStyle(i,j,j1,1,1); moveFlag = true; break; } } else{ count++; } } } count = 0 } } isWin(); if(moveFlag){ this.get2or4(this.getNullTileIndex()); } } //移动 方格属性更替 private function setTileStyle(i:int, j:int, j1:int, rFlag:int, cFlag:int):void{ var tile1:NumberTile = null; var tile2:NumberTile = null; if(rFlag == 0){ //left right tile1 = tileVector[4*i+j]; tile2 = tileVector[4*i+j1] }else{ //up down tile1 = tileVector[4*j+i]; tile2 = tileVector[4*j1 + i] } if(cFlag == 0){ //null tile1.text = tile2.text; var arr1:Array = this.getStyleArrayByNum(int(tile1.text)); tile1.textSize = arr1[0]; tile1.textColor = arr1[1]; tile1.bacolor = arr1[2]; tile2.text = null; tile2.bacolor = 0xcdc0b4; } else{ // plus tile1.text = (int(tile2.text) * 2) + ""; var arr2:Array = this.getStyleArrayByNum(int(tile1.text)); tile1.textSize = arr2[0]; tile1.textColor = arr2[1]; tile1.bacolor = arr2[2]; tile2.text = null; tile2.bacolor = 0xcdc0b4; } } //依据数字获取相应的相关属性值 private function getStyleArrayByNum(num:Number):Array{ var arr:Array = new Array(); var textColor:uint; var baColor:uint; var textSize:uint; if(num == 2){ textColor = 0x776E65; baColor = 0xEEE4DA; textSize = 40; }else if(num == 4){ textColor = 0x776E65; baColor = 0xEDE0C8; textSize = 40; }else if(num == 8){ textColor = 0xF9F6F3; baColor = 0xF2B179; textSize = 40; }else if(num == 16){ textColor = 0xF9F6F3; baColor = 0xF59563; textSize = 40; }else if(num == 32){ textColor = 0xF9F6F3; baColor = 0xF67C5F; textSize = 40; }else if(num == 64){ textColor = 0xF9F6F3; baColor = 0xF6653E; textSize = 40; }else if(num >= 128){ textColor = 0xF9F6F3; baColor = 0xEDC951; textSize = 36; if(num > 1000){ textSize = 26; } } arr.push(textSize) arr.push(textColor); arr.push(baColor); return arr; } private var alertFlag:Boolean = false; private function checkComplete():void{ var flag:Boolean = true; out:for(var i:int = 0; i < 4; i++){ for(var j:int = 0; j < 4; j++){ if(tileVector[4*i + j].text == null || (j > 0 && tileVector[4*i + j].text == tileVector[4*i + j - 1].text) || (j < 3 && tileVector[4*i + j].text == tileVector[4*i + j + 1].text) || (j > 0 && tileVector[4*j + i].text == tileVector[4*j + i - 4].text) || (j < 3 && tileVector[4*j + i].text == tileVector[4*j + i + 4].text) ){ flag = false; break out; } } } if(flag && !alertFlag){ Alert.yesLabel = "Restart"; Alert.cancelLabel = "No"; Alert.show("GAME OVER","STATUS",9,this,gameOverHandle); alertFlag = true; } } private function gameOverHandle(event:CloseEvent):void{ alertFlag = false; isStart = false; if(event.detail == Alert.YES) { for(var i:int = 0; i < tileVector.length; i++){ tileVector[i].text = null; tileVector[i].bacolor = 0xCDC0B4; } this.start_clickHandler(null); this.setFocus(); score = 0; } } //推断是否赢了 private function isWin():Boolean{ var flag:Boolean = false; for(var i:int = 0; i < tileVector.length; i++){ if(tileVector[i].text == "2048"){ flag = true; } } if(flag && !alertFlag){ alertFlag = true; Alert.yesLabel = "Continue"; Alert.cancelLabel = "No"; Alert.show("you Win! is Continue?","win",9,this,winHandle); } return flag; } private function winHandle(event:CloseEvent):void{ alertFlag = false; isStart = false; if(event.detail == Alert.NO) { for(var i:int = 0; i < tileVector.length; i++){ tileVector[i].text = null; tileVector[i].bacolor = 0xCDC0B4; } score = 0; } } ]]> </fx:Script> <s:BorderContainer width="400" height="580" verticalCenter="0" horizontalCenter="0" backgroundColor="0xDEDEDE" borderColor="0x666666"> <s:BorderContainer borderVisible="false" backgroundColor="0xff7f17" width="100%" height="60"> <s:Label text="2048" fontFamily="Microsoft YaHei" fontSize="40" horizontalCenter="0" verticalCenter="0" fontWeight="bold"/> </s:BorderContainer> <s:HGroup y="80" right="0" verticalAlign="middle" width="130"> <s:Label text="Score:" fontFamily="Microsoft YaHei" fontSize="20" color="0xB704DD" fontWeight="bold"/> <s:Label text="{score}" fontFamily="Microsoft YaHei" fontSize="20" color="0xB704DD" fontWeight="bold"/> </s:HGroup> <s:HGroup y="120" horizontalCenter="0" horizontalAlign="center" verticalAlign="middle"> <s:BorderContainer enabled="{isStart}" width="100" height="50" backgroundColor="0x6FCDCD" borderVisible="false" click="start_clickHandler(event)" buttonMode="true"> <s:Label text="Start" fontWeight="bold" color="0xEEEEEE" fontFamily="Microsoft YaHei" fontSize="28" horizontalCenter="0" verticalCenter="0"/> </s:BorderContainer> <s:BorderContainer width="100" height="50" backgroundColor="0x79B900" borderVisible="false" click="restart_clickHandler(event)" buttonMode="true"> <s:Label text="Retart" fontWeight="bold" color="0xEEEEEE" fontFamily="Microsoft YaHei" fontSize="28" horizontalCenter="0" verticalCenter="0"/> </s:BorderContainer> </s:HGroup> <s:BorderContainer id="bcc" x="20" y="180" cornerRadius="4" backgroundColor="0xBBADA0" width="360" height="360" borderColor="0xDEDEDE"> <s:layout> <s:TileLayout requestedColumnCount="4" requestedRowCount="4" columnAlign="justifyUsingWidth" rowAlign="justifyUsingHeight" verticalGap="10" horizontalGap="10" paddingBottom="10" paddingLeft="10" paddingTop="10" paddingRight="10"/> </s:layout> </s:BorderContainer> <s:Label text="By布丰(Bufoon)" fontFamily="Microsoft YaHei" fontSize="13" fontWeight="bold" bottom="1" horizontalCenter="0"/> </s:BorderContainer> </s:Application>
By 布丰(Bufoon)http://blog.csdn.net/songanling/article/details/26012645