承接上篇文章,上篇文章完成了游戏中的计时和进入程序碎片的自动乱序排列,本次文章将完成剩余的部分(碎片的移动和拼图的成功逻辑)
实现流程大概:默认最后一张照片不显示,但实际存在,点击空白区域相邻的图片(也只有该空白区域的图片被点击有效)然后实现图片点击后的移动和空白区域交换,进过数次移动之后若最终的总图片组合起来和给出的最终图片相同则弹出拼图成功的提示框!
其实总结就一个数组知识。用数组的坐标值交换来呈现图片的交换,用数次图片运动后(数次数组的交换)看是否与引入的最终指定图片(规定的数值顺序)是否相同!
具体实现方法:(代码注释已经非常非常详细了,并且是按照一步一步的逻辑步走注释的,很容易理解)
如果有不明白理解的评论区可以留言或者私信我,若文章有代码,逻辑,编写错误不准确还请各位指正,我及时改正学习,谢谢各位!
实现点击碎片的效果:
//表示移动指定位置的按钮的函数,将图片和空白区域交换 private void move(int imagebuttonId, int site) { //判断选中的图片在第几行,第几列,判断方法通过求余的方法 int sitex=site/imageX; int sitey=site%imageY; //获取空白区域的坐标 int blankx=blankSwap/imageX; int blanky=blankSwap%imageY; //图片可以移动的两个条件 //1.在同一行,列数相减绝对值为1;2.在同一列,行数相减绝对值为1 int x=Math.abs(sitex-blankx); int y=Math.abs(sitey-blanky); if((x == 0&&y==1)||(y==0&&x==1)){ //通过id查找到这个可以移动的按钮 ImageButton clickButton=findViewById(imagebuttonId); clickButton.setVisibility(View.INVISIBLE); //查看空白区域的按钮 ImageButton blackButton=findViewById(blankImgid); //将空白区域设置图片 blackButton.setImageResource(image[imageIndex[site]]); //移动之间不可见,移动之后,将控件设置为可见 blackButton.setVisibility(View.VISIBLE); //将改变角标的过程记录到存储图片位置的数组当中 swap(site,blankSwap); //新的空白区域位置更新等于传入的点击按钮的位置 blankSwap=site; blankImgid=imagebuttonId; }
实现判断碎片数次移动之后是否成功的逻辑效果:
//判断拼图是否成功 private void judgeGameOver() { boolean loop=true;//定义标志位 for(int i=0;i<imageIndex.length;i++) { if (imageIndex[i] != i) { loop = false; break; } } if(loop){ //拼图成功,停止计时 handler.removeMessages(1); //拼图成功后,禁止玩家继续移动按钮 ib00.setClickable(false); ib01.setClickable(false); ib02.setClickable(false); ib10.setClickable(false); ib11.setClickable(false); ib12.setClickable(false); ib20.setClickable(false); ib21.setClickable(false); ib22.setClickable(false); ib22.setImageResource(image[8]); ib22.setVisibility(View.VISIBLE); //弹出用户成功对话框 AlertDialog.Builder builder=new AlertDialog.Builder(this); builder.setMessage("恭喜,拼图成功!您的时间为"+time+"秒").setPositiveButton("确认",null); builder.create().show(); }
Java总代码:
package com.example.jigsaw; import androidx.annotation.NonNull; import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AppCompatActivity; import android.annotation.SuppressLint; import android.media.Image; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.text.AlteredCharSequence; import android.view.View; import android.widget.Button; import android.widget.ImageButton; import android.widget.TextView; public class MainActivity extends AppCompatActivity { ImageButton ib00,ib01,ib02,ib10,ib11,ib12,ib20,ib21,ib22; Button restartBtn; TextView timeTv; //定义每行每列图片的个数 private int imageX=3; private int imageY=3; //图片总个数 private int imgCount=imageX*imageY; //空白区域的位置 private int blankSwap=imgCount-1; //初始化空白区域的按钮id private int blankImgid=R.id.pt_id_02x02; //定义时间的变量 int time = 0; //存放碎片的数组,便于进行统一的管理 private int[]image={R.drawable.pt_id_00x00,R.drawable.pt_id_00x01,R.drawable.pt_id_00x02, R.drawable.pt_tv_01x00,R.drawable.pt_tv_01x01,R.drawable.pt_tv_01x02,R.drawable.p1,R.drawable.p2,R.drawable.p3}; //声明一个图片数组的下标数组,随机排列这个数组 private int[]imageIndex=new int[image.length]; Handler handler=new Handler(){ @Override public void handleMessage(@NonNull Message msg) { if (msg.what==1){ time++; timeTv.setText("时间:"+time+" 秒"); handler.sendEmptyMessageDelayed(1,1000); } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); //打乱碎片 disruptRandpm(); handler.sendEmptyMessageDelayed(1,1000); } //随机打乱不规则 private void disruptRandpm() { for(int i=0;i<imageIndex.length;i++){ imageIndex[i]=i; } //规定20次,随机选择两个角标对应的值进行交换 int rand1,rand2; for(int j=0;j<20;j++){ //随机生成一个角标,0-8的数值 rand1=(int)(Math.random()*(imageIndex.length-1)); //第二次随机生成的角标,不能和第一次相同 do{ rand2=(int)(Math.random()*(imageIndex.length-1)); if(rand1!=rand2){ break; } }while (true); //交换两个角标上对应的值 swap(rand1,rand2); } //随机排列到指定控件上 ib00.setImageResource(image[imageIndex[0]]); ib01.setImageResource(image[imageIndex[1]]); ib02.setImageResource(image[imageIndex[2]]); ib10.setImageResource(image[imageIndex[3]]); ib11.setImageResource(image[imageIndex[4]]); ib12.setImageResource(image[imageIndex[5]]); ib20.setImageResource(image[imageIndex[6]]); ib21.setImageResource(image[imageIndex[7]]); ib22.setImageResource(image[imageIndex[8]]); } //交换 private void swap(int rand1, int rand2) { int temp=imageIndex[rand1]; imageIndex[rand1]=imageIndex[rand2]; imageIndex[rand2]=temp; } private void initView() { ib00=findViewById(R.id.pt_id_00x00); ib01=findViewById(R.id.pt_id_00x01); ib02=findViewById(R.id.pt_id_00x02); ib10=findViewById(R.id.pt_id_01x00); ib11=findViewById(R.id.pt_id_01x01); ib12=findViewById(R.id.pt_id_01x02); ib20=findViewById(R.id.pt_id_02x00); ib21=findViewById(R.id.pt_id_02x01); ib22=findViewById(R.id.pt_id_02x02); timeTv=findViewById(R.id.pt_tv_time); restartBtn=findViewById(R.id.pt_btn_restart); } public void onClick(View view) { int id=view.getId(); switch (id){ case R.id.pt_id_00x00: move(R.id.pt_id_00x00,0); break; case R.id.pt_id_00x01: move(R.id.pt_id_00x01,1); break; case R.id.pt_id_00x02: move(R.id.pt_id_00x02,2); break; case R.id.pt_id_01x00: move(R.id.pt_id_01x00,3); break; case R.id.pt_id_01x01: move(R.id.pt_id_01x01,4); break; case R.id.pt_id_01x02: move(R.id.pt_id_01x02,5); break; case R.id.pt_id_02x00: move(R.id.pt_id_02x00,6); break; case R.id.pt_id_02x01: move(R.id.pt_id_02x01,7); break; case R.id.pt_id_02x02: move(R.id.pt_id_02x02,8); break; } } //表示移动指定位置的按钮的函数,将图片和空白区域交换 private void move(int imagebuttonId, int site) { //判断选中的图片在第几行,第几列,判断方法通过求余的方法 int sitex=site/imageX; int sitey=site%imageY; //获取空白区域的坐标 int blankx=blankSwap/imageX; int blanky=blankSwap%imageY; //图片可以移动的两个条件 //1.在同一行,列数相减绝对值为1;2.在同一列,行数相减绝对值为1 int x=Math.abs(sitex-blankx); int y=Math.abs(sitey-blanky); if((x == 0&&y==1)||(y==0&&x==1)){ //通过id查找到这个可以移动的按钮 ImageButton clickButton=findViewById(imagebuttonId); clickButton.setVisibility(View.INVISIBLE); //查看空白区域的按钮 ImageButton blackButton=findViewById(blankImgid); //将空白区域设置图片 blackButton.setImageResource(image[imageIndex[site]]); //移动之间不可见,移动之后,将控件设置为可见 blackButton.setVisibility(View.VISIBLE); //将改变角标的过程记录到存储图片位置的数组当中 swap(site,blankSwap); //新的空白区域位置更新等于传入的点击按钮的位置 blankSwap=site; blankImgid=imagebuttonId; } //判断本次移动完成后,是否完成了拼图游戏 judgeGameOver(); } //判断拼图是否成功 private void judgeGameOver() { boolean loop=true;//定义标志位 for(int i=0;i<imageIndex.length;i++) { if (imageIndex[i] != i) { loop = false; break; } } if(loop){ //拼图成功,停止计时 handler.removeMessages(1); //拼图成功后,禁止玩家继续移动按钮 ib00.setClickable(false); ib01.setClickable(false); ib02.setClickable(false); ib10.setClickable(false); ib11.setClickable(false); ib12.setClickable(false); ib20.setClickable(false); ib21.setClickable(false); ib22.setClickable(false); ib22.setImageResource(image[8]); ib22.setVisibility(View.VISIBLE); //弹出用户成功对话框 AlertDialog.Builder builder=new AlertDialog.Builder(this); builder.setMessage("恭喜,拼图成功!您的时间为"+time+"秒").setPositiveButton("确认",null); builder.create().show(); } // } } //拼图游戏重新开始 public void restart(View view) { //拼图游戏重新开始,允许玩家移动碎片 ib00.setClickable(true); ib01.setClickable(true); ib02.setClickable(true); ib10.setClickable(true); ib11.setClickable(true); ib12.setClickable(true); ib20.setClickable(true); ib21.setClickable(true); ib22.setClickable(true); //拼图打乱 disruptRandpm(); handler.removeMessages(1); //时间重新归0,并且重新⏲ time=0; timeTv.setText("时间:"+time+" 秒"); handler.sendEmptyMessageDelayed(1,1000); } } 截图效果: