zoukankan      html  css  js  c++  java
  • Android实战开发——拼图游戏

    具体代码的实现托管到了GitHub:https://github.com/ydd997/Android_pintu
    下面介绍重要的几个模块。

    时间改变的实现

    MainActivity.java 中的 onCreate 函数中添加如下内容:

    //一进来每隔1s就发一条空消息出去,接收到这个空消息并让TextView发生改变,形成计数器的效果
    //延迟1s发送一条空消息:发送消息的编号是1,延迟时间为1000ms=1s
    handler.sendEmptyMessageDelayed(1,1000);
    

    之后在 onCreate 函数外添加如下内容:

    //定义计数时间的变量
    int time=0;
    
    //消息通信机制,重写handleMessag方法用来接收消息,形成时间累计的效果
    Handler handler=new Handler(){
        @Override
        public void handleMessage(@NonNull Message msg) {
            if(msg.what==1){
                time++;
                timeTv.setText("时间:"+time+"秒");
                handler.sendEmptyMessageDelayed(1,1000);
            }
        }
    };
    

    时间变化的情况有两种,一是当拼图游戏完成的时候时间要停止,二是重新开始的时候要重新计时,现在先实现点击重新开始按钮时重新计时:

    public void restart(View view) {
        //中断之前的消息
        handler.removeMessages(1);
        //将时间重新归零并且重新开始计时
        time=0;
        timeTv.setText("时间:"+time+"秒");
        handler.sendEmptyMessageDelayed(1,1000);
    }
    

    拼图打乱显示

    思路:通过数组的随机排位来使图片随机排列

    首先声明一些变量:

    //存放碎片的数组,便于统一管理
    private int[]image={R.mipmap.img_00x00,R.mipmap.img_00x01,R.mipmap.img_00x02,R.mipmap.img_01x00,R.mipmap.img_01x01,R.mipmap.img_01x02,R.mipmap.img_02x00,R.mipmap.img_02x01,R.mipmap.img_02x02};
    
    //声明一个图片数组的下标数组,随机排列这个数组
    private int[]imageIndex=new int[image.length];
    

    接下来写一个打乱的方法,使得 onCreate 一进入就显示打乱的数组。
    首先打乱角标,接着把乱序的角标设置到ImageButton中,保证一进入就是打乱的状态,具体代码如下:

        //随机打乱数组中的元素,以不规则的形式进行图片显示
        private void disruptRandom() {
            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)); //Math.random()生成的是0—1之间的随机数,再乘以最大值减去最小值(即8-0),最后整体加上最小值0
                //第二次随机生成的角标不能和第一次相同,如果相同就不方便交换
                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[rand2]=imageIndex[rand1];
            imageIndex[rand1]=temp;
        }
    

    碎片位置切换

    碎片移动的条件:空白区域只能和向同行或者相同列上并且是相邻的图片进行移动,否则不能完成。

    需要判断空白位置和其他图的位置是否在同一行或同一列中。

    移动的过程写在 onClick 中:

        public void onClick(View view) {
            int id = view.getId();
            //九个按钮执行点击事件的逻辑是相同的:如果有空格在周围则可以改变图片的位置,否则点击事件不响应
            switch (id){
                case R.id.pt_ib_00x00:
                    move(R.id.pt_ib_00x00,0);
                    break;
                case R.id.pt_ib_00x01:
                    move(R.id.pt_ib_00x01,1);
                    break;
                case R.id.pt_ib_00x02:
                    move(R.id.pt_ib_00x02,2);
                    break;
                case R.id.pt_ib_01x00:
                    move(R.id.pt_ib_01x00,3);
                    break;
                case R.id.pt_ib_01x01:
                    move(R.id.pt_ib_01x01,4);
                    break;
                case R.id.pt_ib_01x02:
                    move(R.id.pt_ib_01x02,5);
                    break;
                case R.id.pt_ib_02x00:
                    move(R.id.pt_ib_02x00,6);
                    break;
                case R.id.pt_ib_02x01:
                    move(R.id.pt_ib_02x01,7);
                    break;
                case R.id.pt_ib_02x02:
                    move(R.id.pt_ib_02x02,8);
                    break;
            }
        }
    
    

    其中 move 函数具体实现过程:

        /*表示移动指定位置的按钮的函数:将图片和空白区域进行交换*/
        private void move(int imageButtonId, int site) {
    
            //判断选中的图片在第几行,取整来判断
            int sitex=site / imageX;
    
            //判断选中的图片在第几列,趋于来判断
            int sitey=site % imageY;
    
            //获取空白区域的坐标
            int blackx=blackSwap / imageX;
            int blacky=blackSwap % imageY;
    
            //可以移动的条件
            //1.在同一行,列数相减绝对值为1,可以移动;2.在同一列,行数相减绝对值为1,可以移动。
            int x=Math.abs(sitex-blackx);
            int y=Math.abs(sitey-blacky);
            if((x==0&&y==1)||(x==1&&y==0)){
                //通过id查找到这个可以移动的按钮
                ImageButton clickButton=findViewById(imageButtonId);
                //该可移动按钮不在显示图片
                clickButton.setVisibility(View.INVISIBLE);
                //查找空白区域的按钮
                ImageButton blackButton=findViewById(blackImgid);
                //将空白按钮设置为显示图片
                blackButton.setImageResource(image[imageIndex[site]]);
                //移动之前是不可见的,移动之后将控件设置为可见
                blackButton.setVisibility(View.VISIBLE);
    
                //上面的交换并没有存在数组之中,要调用swap函数,将改变角标的过程记录在存储图片位置的数组当中
                swap(site,blackSwap);
    
                //新的空白区域位置更新
                blackSwap=site;
                blackImgid=imageButtonId;
            }
        }
    

    目前为止效果展示:

    拼图成功的条件

    每次拼图结束之后,要判断一下当前拼图顺序是否满足正确顺序。
    这里是判断存放图片角标的数组的顺序。

        /*判断拼图是否成功*/
        private void judgeGameOver() {
            boolean loop=true; //定义标志位
            //对存放图片角标的数组imageIndex进行判断
            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);
                AlertDialog dialog = builder.create();
                dialog.show();
            }
        }
    

    游戏重新开始

    现在需要将拼图重新打乱,重新打乱的函数 disruptRandom() 在前面已经写好,直接引用即可。
    但是之前游戏成功已经禁止拼图继续移动,所以将打乱之前要恢复按钮可以移动的功能,同时还要还原被点击图片初始化的样子,具体代码如下:

        /*重新开始按钮的点击事件*/
        public void restart(View view) {
            //将状态还原
            restore();
    
            //将拼图重新打乱
            disruptRandom();
    
            //中断之前的消息
            handler.removeMessages(1);
            //将时间重新归零并且重新开始计时
            time=0;
            timeTv.setText("时间:"+time+"秒");
            handler.sendEmptyMessageDelayed(1,1000);
        }
    
        private void restore() {
            //拼图游戏重新开始,允许玩家重新触碰按钮
            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);
    
            //还原被点击的图片按钮变成初始化的模样
            //最后一次选中的空白区域显示出来
            ImageButton clickButton=findViewById(blackImgid);
            clickButton.setVisibility(View.VISIBLE);
    
            //定义一个新的图片按钮,设置为第九个,让其隐藏(默认隐藏第九张图片)
            ImageButton blackBtn=findViewById(R.id.pt_ib_02x02);
            blackBtn.setVisibility(View.INVISIBLE);
    
            //初始化空白区域的按钮id
            blackImgid=R.id.pt_ib_02x02;
            blackSwap=imageCount-1;
        }
    }
    
    

    最终效果:

    思考

    整个过程不是很难理解,只有一个页面,布局也比较简单,采用了最基本的线性布局。感觉比较适合入门。在打乱九个碎片的顺序时候采用了两个数组,第一先将九个碎片按照正确的顺序存储在一个数组中,第二用一个数组存储碎片存放的位置,通过打乱放置位置的数组来打乱图片。接着是切换点击,能够将碎片和空白位置进行交换,之后是要判断何时游戏成功,判断完成点击重新开始又可以重新打乱顺序进行游戏。

  • 相关阅读:
    mac/unix系统:C++实现一个端口扫描器
    C++:通过gethostbyname函数,根据服务器的域名,获取服务器IP
    PostMan Setting Proxy 设置 代理
    企业架构 Red Hat Drools KIE Project 三大核心产品
    IDS,IPS,IPD
    Vehicle routing with Optaplanner graph-theory
    SonarQube Detection of Injection Flaws in Java, C#, PHP
    Spring AOP Log
    Code Quality and Security | SonarQube
    Gradle vs. Maven: Performance, Compatibility, Speed, & Builds
  • 原文地址:https://www.cnblogs.com/yangdd/p/13290232.html
Copyright © 2011-2022 走看看