游戏效果:
前提摘要:
前两天粘贴出来了地址,不知道大家下载了没有,如果玩的话,是不是发现了几个潜在的问题,如果按完开始键后,不停的点击上一关或者下一关就会出现应用闪退的情况,这种情况是toast的问题,目前已经修复,当然了还有,滑着滑着,有的格子就不见了的问题,这种问题,虽然很少见,但是确实出现过,它是因为滑动的距离过长,本来是走一格,一不小心多走了一格,这就尴尬了,我觉得最大的问题就是滑着不是很灵敏,有时滑不动,这样那样潜在的问题是很多了,毕竟这个简单的游戏,仅仅用了十几个小时开发出来的,问题是在所难免的,大家有兴趣的可以去优化。
灵感源于:
来新公司有一段时间了,由于处于没有需求的状态,只好不停的去学习,去研究一些自己感兴趣的技术,之前没有去开源的东西,自己也正在逐步的整理,逐步的开源,前几天,新的一季最强大脑已经开播了,模式似乎发生了改变,不过具有智慧的游戏还是依旧未变,第一集的数字华容道便是我的灵感,打乱的格子推来推去,紧张的时间下,透露着分秒必争,那么我能不能做一个呢,于是,就开始尝试了起来。
代码存在问题:
毋庸置疑,代码是很烂的,很多都是重复性的代码,自己写的,看的都想吐,我也准备做一个抽取,当然了,大家也可以去优化,也许网上也有很多的实现方式,毕竟思维不一样,实现也不一样也许别人的更加简单,更高级,这个是不能否定的,自己水平有限,也只能这样了。
具体实现:
其实我的实现方式很是简单,自定义一个View,确定View大小后,绘制八个格子,确定八个格子的左上右下,随机给八个格子绘制数据,比如第八个格子绘制的是“1”,那么,随着手势的移动当第八个格子也就是“1”的左上右下和第一个格子的左上右下相等时,那么这个格子的位置是正确的,同理,其它格子也是如此实现,当所有的格子都找到位置后,一一比较都是相等的,那么我们就可以判断,移动成功,那么就可以进入下一关了,如下图。
主要代码(这里只贴出主要实现的代码,全部代码请下载源码,源码里都有注释):
/*** 记录每个格子移动的左上右下* rect0:空白格子,rect1:第一个格子 ……* x_0:左* x_1:右* y_0:上* y_1:下* x_t:绘制文字的x坐标* y_t:绘制文字的y坐标* */privateintrect0_x_0,rect0_x_1,rect0_y_0,rect0_y_1;//空隙位置privateintrect1_x_0,rect1_x_1,rect1_y_0,rect1_y_1,rect1_x_t,rect1_y_t; privateintrect2_x_0,rect2_x_1,rect2_y_0,rect2_y_1,rect2_x_t,rect2_y_t; privateintrect3_x_0,rect3_x_1,rect3_y_0,rect3_y_1,rect3_x_t,rect3_y_t; privateintrect4_x_0,rect4_x_1,rect4_y_0,rect4_y_1,rect4_x_t,rect4_y_t; privateintrect5_x_0,rect5_x_1,rect5_y_0,rect5_y_1,rect5_x_t,rect5_y_t; privateintrect6_x_0,rect6_x_1,rect6_y_0,rect6_y_1,rect6_x_t,rect6_y_t; privateintrect7_x_0,rect7_x_1,rect7_y_0,rect7_y_1,rect7_x_t,rect7_y_t; privateintrect8_x_0,rect8_x_1,rect8_y_0,rect8_y_1,rect8_x_t,rect8_y_t; 获取View的宽高,及每个格子的宽高:mWidth=getMeasuredWidth(); mHeight=getMeasuredHeight(); floatX_6=mWidth/6; floatY_6=mHeight/6; floatX=mWidth/3; floatY=mHeight/3; 初始化八个格子和空白格子的位置,这里的padding等于10dp,是边框距离左上右下的距离/*** 第一个格子的位置* */privatevoidcreateView_1() { rect1_x_0=padding; rect1_x_1=floatX+padding; rect1_y_0=padding; rect1_y_1=floatY+padding; rect1_x_t=(floatX+padding)/2; rect1_y_t=(floatY+padding)/2; } /*** 第二个格子的位置* */privatevoidcreateView_2() { rect2_x_0=padding+floatX; rect2_x_1=floatX*2+padding; rect2_y_0=padding; rect2_y_1=floatY+padding; rect2_x_t=(floatX*2+padding)-floatX_6; rect2_y_t=(floatY+padding)/2; } /*** 第三个格子的位置* */privatevoidcreateView_3() { rect3_x_0=padding+floatX*2; rect3_x_1=mWidth-padding; rect3_y_0=padding; rect3_y_1=floatY+padding; rect3_x_t=(mWidth-padding)-floatX_6; rect3_y_t=(floatY+padding)/2; } /*** 第四个格子的位置* */privatevoidcreateView_4() { rect4_x_0=padding; rect4_x_1=floatX+padding; rect4_y_0=padding+floatY; rect4_y_1=floatY*2+padding; rect4_x_t=(floatX+padding)/2; rect4_y_t=(floatY*2+padding)-floatY_6; } /*** 第五个格子的位置* */privatevoidcreateView_5() { rect5_x_0=padding+floatX; rect5_x_1=floatX*2+padding; rect5_y_0=padding+floatY; rect5_y_1=floatY*2+padding; rect5_x_t=(floatX*2+padding)-floatX_6; rect5_y_t=(floatY*2+padding)-floatY_6; } /*** 第六个格子的位置* */privatevoidcreateView_6(){ rect6_x_0=padding+floatX*2; rect6_x_1=mWidth-padding; rect6_y_0=padding+floatY; rect6_y_1=floatY*2+padding; rect6_x_t=(mWidth-padding)-floatX_6; rect6_y_t=(floatY*2+padding)-floatY_6; } /*** 第七个格子的位置* */privatevoidcreateView_7(){ rect7_x_0=padding; rect7_x_1=floatX+padding; rect7_y_0=padding+floatY*2; rect7_y_1=mHeight-padding; rect7_x_t=(floatX+padding)/2; rect7_y_t=(mHeight-padding)-floatY_6; } /*** 第八个格子的位置* */privatevoidcreateView_8() { rect8_x_0=padding+floatX; rect8_x_1=floatX*2+padding; rect8_y_0=padding+floatY*2; rect8_y_1=mHeight-padding; rect8_x_t=(floatX*2+padding)-floatX_6; rect8_y_t=(mHeight-padding)-floatY_6; } /*** 每次移动格子,记录空白格子的位置* */privatevoidcreateView_9(intnum1,intnum2,intnum3,intnum4) { Log.i("createView_9",num1+"==="+num2+"==="+num3+"==="+num4); rect0_x_0=num1; rect0_x_1=num2; rect0_y_0=num3; rect0_y_1=num4; }
onTouchEvent事件:当手指抬起的时候去移动格子,根据手指抬起的XY坐标和空白格子进行比较,如果条件符合,那么就可以执行下一步,否则不让移动,目的解决乱移动现象,具体移动多少,才可以移动格子,这里我设置的是手指必须移动的距离,必须得大于一格半,MainActivity.isStart是我设置的一个开始暂停按钮。
具体是否移动了哪一格:需要根据按下的XY进行判断,这里我只列出了第一个格,其它格子判断和第一格一样,都是一些重复性的代码。
caseMotionEvent.ACTION_UP: upX= (int) event.getX(); upY= (int) event.getY(); //如果不是大于空白格子,那么就不移动booleanisScroll=upX>rect0_x_0&&upX<rect0_x_1&&upY>rect0_y_0&&upY<rect0_y_1; if(!isScroll){ returntrue; } //如果移动的距离大于一格半,那么就不移动,必须在一格半之内if(Math.abs(upX-downX)>floatX+floatX/2||Math.abs(upY-downY)>floatY/2+floatY){ returntrue; } if(!MainActivity.isStart){ listener.toast(); returntrue; } if(downX>rect1_x_0&&downX<rect1_x_1&&downY>rect1_y_0&&downY<rect1_y_1) {//移动了1号Log.i("Scroll2048","111111"); if(Math.abs(upY-downY)>floatY/2&&Math.abs(upX-downX)<floatX/2){ //纵向移动if(upY>downY&&upY>floatY+padding&&upY<floatY*2+padding) { //第一行往下resert_down_1_1(); }elseif(upY>downY&&upY>floatY*2+padding&&upY<mHeight-padding){ //第二行往下resert_down_1_2(); }elseif(upY<downY&&upY>floatY+padding&&upY<floatY*2+padding){ //第三行往上resert_up_1_1(); }elseif(upY<downY&&upY>padding&&upY<floatY+padding){ //第二行往上resert_up_1_2(); } }elseif(Math.abs(upX-downX)>floatX/2&&Math.abs(upY-downY)<floatY/2){ //横向移动if(upX>downX&&upX>floatX+padding&&upX<floatX*2+padding){ //第一纵行往右滑动resert_left_1_1(); }elseif(upX>downX&&upX>floatX*2+padding&&upX<mWidth-padding){ //第二纵行往右滑动resert_left_1_2(); }elseif(upX<downX&&upX<mWidth-padding&&upX>floatX+padding){ //第三纵行往左滑动resert_right_1_1(); }elseif(upX<downX&&upX<floatX+padding&&upX>padding){ //第二纵行往左滑动resert_right_1_2(); } } }
以下是移动后,改变第一格的左上右下,以及空白格子的位置重新确定,你不知道用户会移动到哪一格,所以啊九种情况都需要去考虑。
//第1格第1行向下移动privatevoidresert_down_1_1(){ if(upX>padding&&upX<floatX+padding){//第4格createView_9(padding,floatX+padding,padding,floatY+padding); view_1_4(); }elseif(upX>floatX+padding&&upX<floatX*2+padding){//第5格createView_9(padding+floatX,floatX*2+padding,padding,floatY+padding); view_1_5(); }elseif(upX>floatX*2+padding&&upX<mWidth-padding){//第6格createView_9(padding+floatX*2,mWidth-padding,padding,floatY+padding); view_1_6(); } } //第1格第2行向下移动privatevoidresert_down_1_2() { if(upX>padding&&upX<floatX+padding){//第7格createView_9(padding,floatX+padding,padding+floatY,floatY*2+padding); view_1_7(); }elseif(upX>floatX+padding&&upX<floatX*2+padding){//第8格createView_9(padding+floatX,floatX*2+padding,padding+floatY,floatY*2+padding); view_1_8(); }elseif(upX>floatX*2+padding&&upX<mWidth-padding){//第9格createView_9(floatX*2+padding,mWidth-padding,padding+floatY,floatY*2+padding); view_1_9(); } } //第1格第3行向上移动privatevoidresert_up_1_1() { if(upX>padding&&upX<floatX+padding){//第2格createView_9(padding,floatX+padding,padding+floatY*2,mHeight-padding); view_1_4(); }elseif(upX>floatX+padding&&upX<floatX*2+padding){//第3格createView_9(floatX+padding,floatX*2+padding,padding+floatY*2,mHeight-padding); view_1_5(); }elseif(upX>floatX*2+padding&&upX<mWidth-padding){//第5格createView_9(floatX*2+padding,mWidth-padding,padding+floatY*2,mHeight-padding); view_1_6(); } } //第1格第2行向上移动privatevoidresert_up_1_2() { if(upX>padding&&upX<floatX+padding){//第1格createView_9(padding,floatX+padding,padding+floatY,floatY*2+padding); view_1_1(); }elseif(upX>floatX+padding&&upX<floatX*2+padding){//第2格createView_9(floatX+padding,floatX*2+padding,padding+floatY,floatY*2+padding); view_1_2(); }elseif(upX>floatX*2+padding&&upX<mWidth-padding){//第3格createView_9(floatX*2+padding,mWidth-padding,padding+floatY,floatY*2+padding); view_1_3(); } } //第1格第1竖行向右边移动privatevoidresert_left_1_1() { if(upY>padding&&upY<floatY+padding){ createView_9(padding,floatX+padding,padding,floatY+padding); view_1_2(); }elseif(upY>floatY+padding&&upY<floatY*2+padding){ createView_9(padding,floatX+padding,padding+floatY,floatY*2+padding); view_1_5(); }elseif(upY>floatY*2+padding&&upY<mHeight-padding){ createView_9(padding,floatX+padding,floatY*2+padding,mHeight-padding); view_1_8(); } } //第1格第2竖行向右边移动privatevoidresert_left_1_2() { if(upY>padding&&upY<floatY+padding){ createView_9(padding+floatX,floatX*2+padding,padding,floatY+padding); view_1_3(); }elseif(upY>floatY+padding&&upY<floatY*2+padding){ createView_9(padding+floatX,floatX*2+padding,padding+floatY,floatY*2+padding); view_1_6(); }elseif(upY>floatY*2+padding&&upY<mHeight-padding){ createView_9(padding+floatX,floatX*2+padding,padding+floatY*2,mHeight-padding); view_1_9(); } } //第1格第2竖行向左边移动privatevoidresert_right_1_2() { if(upY>padding&&upY<floatY+padding){ createView_9(padding+floatX,floatX*2+padding,padding,floatY+padding); view_1_1(); }elseif(upY>floatY+padding&&upY<floatY*2+padding){ createView_9(padding+floatX,floatX*2+padding,floatY+padding,floatY*2+padding); view_1_4(); }elseif(upY>floatY*2+padding&&upY<mHeight-padding){ createView_9(padding+floatX,floatX*2+padding,floatY*2+padding,mHeight-padding); view_1_7(); } } //第1格第3竖行向左边移动privatevoidresert_right_1_1() { if(upY>padding&&upY<floatY+padding){ createView_9(padding+floatX*2,mWidth-padding,padding,floatY+padding); view_1_2(); }elseif(upY>floatY+padding&&upY<floatY*2+padding){ createView_9(padding+floatX*2,mWidth-padding,floatY+padding,floatY*2+padding); view_1_5(); }elseif(upY>floatY*2+padding&&upY<mHeight-padding){ createView_9(padding+floatX*2,mWidth-padding,floatY*2+padding,mHeight-padding); view_1_8(); } } //第1格移动到第1格privatevoidview_1_1(){ rect1_x_0=padding; rect1_x_1=floatX+padding; rect1_y_0=padding; rect1_y_1=floatY+padding; rect1_x_t=(floatX+padding)/2; rect1_y_t=(floatY+padding)/2; } //第1格移动到第2格privatevoidview_1_2(){ rect1_x_0=padding+floatX; rect1_x_1=floatX*2+padding; rect1_y_0=padding; rect1_y_1=floatY+padding; rect1_x_t=(floatX*2+padding)-floatX_6; rect1_y_t=(floatY+padding)/2; } //第1格移动到第3格privatevoidview_1_3(){ rect1_x_0=padding+floatX*2; rect1_x_1=mWidth-padding; rect1_y_0=padding; rect1_y_1=floatY+padding; rect1_x_t=(mWidth-padding)-floatX_6; rect1_y_t=(floatY+padding)/2; } //第1格移动到第4格privatevoidview_1_4(){ rect1_x_0=padding; rect1_x_1=floatX+padding; rect1_y_0=padding+floatY; rect1_y_1=floatY*2+padding; rect1_x_t=(floatX+padding)/2; rect1_y_t=(floatY*2+padding)-floatY_6; } //第1格移动到第5格privatevoidview_1_5(){ rect1_x_0=padding+floatX; rect1_x_1=floatX*2+padding; rect1_y_0=padding+floatY; rect1_y_1=floatY*2+padding; rect1_x_t=(floatX*2+padding)-floatX_6; rect1_y_t=(floatY*2+padding)-floatY_6; } //第1格移动到第6格privatevoidview_1_6(){ rect1_x_0=padding+floatX*2; rect1_x_1=mWidth-padding; rect1_y_0=padding+floatY; rect1_y_1=floatY*2+padding; rect1_x_t=(mWidth-padding)-floatX_6; rect1_y_t=(floatY*2+padding)-floatY_6; } //第1格移动到第7格privatevoidview_1_7(){ rect1_x_0=padding; rect1_x_1=floatX+padding; rect1_y_0=padding+floatY*2; rect1_y_1=mHeight-padding; rect1_x_t=(floatX+padding)/2; rect1_y_t=(mHeight-padding)-floatY_6; } //第1格移动到第8格privatevoidview_1_8(){ rect1_x_0=padding+floatX; rect1_x_1=floatX*2+padding; rect1_y_0=padding+floatY*2; rect1_y_1=mHeight-padding; rect1_x_t=(floatX*2+padding)-floatX_6; rect1_y_t=(mHeight-padding)-floatY_6; } //第1格移动到第9格privatevoidview_1_9(){ rect1_x_0=padding+floatX*2; rect1_x_1=mWidth-padding; rect1_y_0=padding+floatY*2; rect1_y_1=mHeight-padding; rect1_x_t=(mWidth-padding)-floatX_6; rect1_y_t=(mHeight-padding)-floatY_6; }
如何判断移动成功了:
在上面的图中,我也有说过,就是比较移动后的格子的左上右下和初始化的格子的左上右下,比如,我们随机给的顺为:"8","6","3","1","5","7","2","4",那么我们比较如下,成功后进行回调:
/*** 获取初始化格子的左上右下* */privateintnumber_1_left=padding,number_1_right=floatX+padding, number_1_top=padding,number_1_bottom=floatY+padding; privateintnumber_2_left=padding+floatX,number_2_right=floatX*2+padding, number_2_top=padding,number_2_bottom=floatY+padding; privateintnumber_3_left=padding+floatX*2,number_3_right=mWidth-padding, number_3_top=padding,number_3_bottom=floatY+padding; privateintnumber_4_left=padding,number_4_right=floatX+padding, number_4_top=floatY+padding,number_4_bottom=floatY*2+padding; privateintnumber_5_left=padding+floatX,number_5_right=floatX*2+padding, number_5_top=floatY+padding,number_5_bottom=floatY*2+padding; privateintnumber_6_left=padding+floatX*2,number_6_right=mWidth-padding, number_6_top=floatY+padding,number_6_bottom=floatY*2+padding; privateintnumber_7_left=padding,number_7_right=floatX+padding, number_7_top=floatY*2+padding,number_7_bottom=mHeight-padding; privateintnumber_8_left=padding+floatX,number_8_right=floatX*2+padding, number_8_top=floatY*2+padding,number_8_bottom=mHeight-padding; if(rect1.top==number_8_top&&rect1.bottom==number_8_bottom&&rect1.left==number_8_left&&rect1.right==number_8_right&&rect2.top==number_6_top&&rect2.bottom==number_6_bottom&&rect2.left==number_6_left&&rect2.right==number_6_right&&rect3.top==number_3_top&&rect3.bottom==number_3_bottom&&rect3.left==number_3_left&&rect3.right==number_3_right&&rect4.top==number_1_top&&rect4.bottom==number_1_bottom&&rect4.left==number_1_left&&rect4.right==number_1_right&&rect5.top==number_5_top&&rect5.bottom==number_5_bottom&&rect5.left==number_5_left&&rect5.right==number_5_right&&rect6.top==number_7_top&&rect6.bottom==number_7_bottom&&rect6.left==number_7_left&&rect6.right==number_7_right&&rect7.top==number_2_top&&rect7.bottom==number_2_bottom&&rect7.left==number_2_left&&rect7.right==number_2_right&&rect8.top==number_4_top&&rect8.bottom==number_4_bottom&&rect8.left==number_4_left&&rect8.right==number_4_right){ listener.success(numberType); }
其实就是这样一一去比较,我的思路是这样,可能还是有更加简便的思路,我暂时还没有想起来,具体实现就是这样,代码比较繁琐,有更好的实现方式,可以留言探讨,不吝赐教。