Android实战源码--围住神经猫

最终效果:

 

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.caobotao.crazycat" >

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme" >
        <activity android:name=".MainActivity" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

 

 

MainActivity.java

package com.example.caobotao.crazycat;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(new PlayGround(this));
    }
}

 

 

Dot.java

package com.example.caobotao.crazycat;

/**
 * Created by caobotao on 15/11/9.
 */
public class Dot  {
    private int x;
    private int y;
    private int status;
    static final int STATUS_ON = 1;//障碍的圆圈状态
    static final int STATUS_OFF = 0;//可点击的圆圈状态
    static final int STATUS_IN = 9;//猫所在的圆圈状态
    public Dot(){}
    //实例化时每个圆圈都是可点击的状态
    public Dot(int x,int y){
        this.x = x;
        this.y = y;
        status = STATUS_OFF;
    }

    public int getX() {
        return x;
    }

    public void setX(int x) {
        this.x = x;
    }

    public int getY() {
        return y;
    }

    public void setY(int y) {
        this.y = y;
    }

    public int getStatus() {
        return status;
    }

    public void setStatus(int status) {
        this.status = status;
    }

    public void setXY(int x,int y){
        this.x = x;
        this.y = y;
    }
}

 

 

PlayGround.java

package com.example.caobotao.crazycat;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.SurfaceView;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.Toast;

import java.util.HashMap;
import java.util.Vector;

/**
 * Created by caobotao on 15/11/9.
 */
public class PlayGround extends SurfaceView implements OnTouchListener{
    private static int WIDTH = 45;//圆圈宽度
    private static final int ROW = 10;//每行显示的圆圈数
    private static final int COL = 10;//每列显示的圆圈数
    private static final int Blocks = 13;//初始化障碍的个数
    private Dot matrix[][];
    private Dot cat;
    public PlayGround(Context context) {
        super(context);
        getHolder().addCallback(callback);
        //声明ROW x COL的圆圈矩阵并初始化
        matrix = new Dot[ROW][COL];
        for (int i = 0;i < ROW;i ++){
            for (int j = 0;j < ROW;j ++){
                matrix[i][j] = new Dot(j,i);
            }
        }
        initGame();
        setOnTouchListener(this);
    }
    private void redraw(){
        //初始化画板
        Canvas canvas = getHolder().lockCanvas();
//        Log.i("info", "222222");
        //设置画板背景色
        canvas.drawColor(Color.LTGRAY);
        Paint p = new Paint();
        p.setFlags(Paint.ANTI_ALIAS_FLAG);
        //设置不同状态的圆圈的颜色,并绘制
        for (int i = 0;i < ROW;i ++){
            int offset = 0;
            //如果为偶数行,设置半个圆圈宽度的偏移量
            if (i % 2 != 0){
                offset = WIDTH / 2;
            }
            for (int j = 0;j < COL; j ++){
                Dot one = getDot(j, i);
                switch (one.getStatus()){
                    case Dot.STATUS_OFF:
                        p.setColor(0xFFEEEEEE);
                        break;
                    case Dot.STATUS_ON:
                        p.setColor(0xFFFFAA00);
                        break;
                    case Dot.STATUS_IN:
                        p.setColor(0xFFFF0000);
                        break;
                }
                RectF rectF = new RectF(one.getX() * WIDTH + offset, one.getY() * WIDTH,
                                       (one.getX() + 1) * WIDTH + offset, (one.getY() + 1) * WIDTH);;
//                if(i % 2 ==0) {
//                    rectF = new RectF((one.getX() + 1) * WIDTH, (one.getY() + 2) * WIDTH, (one.getX() + 2) * WIDTH, (one.getY() + 2) * WIDTH);
//                }
                canvas.drawOval(rectF,p);
            }
        }
        getHolder().unlockCanvasAndPost(canvas);
    }
    private void initGame(){
        //将每个圆圈初始化为可点击状态
        for (int i = 0;i < ROW;i ++){
            for (int j = 0;j < ROW;j ++){
                matrix[i][j].setStatus(Dot.STATUS_OFF);
            }
        }
        //将(4,5)设置初始化为猫所在的圆圈,并将状态设置为猫所在
        cat = getDot(4,5);
        cat.setStatus(Dot.STATUS_IN);
        //随机设置Blocks个障碍
        for (int i = 0 ;i < Blocks;){
            int x = (int) ((Math.random() * 1000)%COL);
            int y = (int) ((Math.random() * 1000)%ROW);
            if(getDot(x,y).getStatus() == Dot.STATUS_OFF){
                getDot(x,y).setStatus(Dot.STATUS_ON);
                i ++;
            }
        }

    }
    private boolean isAtEdge(Dot dot){
        //判断某个圆圈是否在边缘
        if(dot.getX() * dot.getY() == 0 || dot.getX()+1 == ROW || dot.getY() + 1 == COL){
            return true;
        }
        return false;
    }
    //获取某个圆圈的左起1,2,3,4,5,6方向的相邻的圆圈
    private Dot neighbour(Dot dot,int dir){
        int x = -1;
        int y = -1;
        switch (dir){
            case 1:
                //return getDot(dot.getX()-1,dot.getY());
                x = dot.getX()-1;
                y = dot.getY();
                break;
            case 2:
                if(dot.getY() % 2 == 0){
                    x = dot.getX() - 1;
                    y = dot.getY() - 1;
                }
                else {
                    x = dot.getX();
                    y = dot.getY() - 1;
                }
                break;
            case 3:
                if(dot.getY() % 2 == 0){
                    x = dot.getX() ;
                    y = dot.getY() - 1;
                }
                else {
                    x = dot.getX() + 1;
                    y = dot.getY() - 1;
                }
                break;
            case 4:
                x = dot.getX() + 1;
                y = dot.getY();
                break;
            case 5:
                if(dot.getY() % 2 == 0){
                    x = dot.getX() ;
                    y = dot.getY() + 1;
                }
                else {
                    x = dot.getX() + 1;
                    y = dot.getY() + 1;
                }
                break;
            case 6:
                if(dot.getY() % 2 == 0){
                    x = dot.getX() - 1;
                    y = dot.getY() + 1;
                }
                else {
                    x = dot.getX();
                    y = dot.getY() + 1;
                }
                break;
        }
        if (x != -1 || y != -1){
            return getDot(x,y);
        }
        return null;
    }
    //获取某个圆圈在某个方向到矩阵边缘或到障碍的距离,如果是到边缘,返回正值,如果是到障碍,返回负值
    private int getDistance(Dot dot,int dir){
        int distance = 0;
        if (isAtEdge(dot)){
            return 1;
        }
        Dot ori = dot;
        Dot next;
        while (true){
            next = neighbour(ori,dir);
            if (next.getStatus() == Dot.STATUS_ON){
                return distance * -1;
            }
            if (isAtEdge(next)){
                distance ++;
                return distance;
            }
            distance ++;
            ori = next;
        }
    }
    //将猫移动到某个圆圈
    private void moveTo(Dot dot){
        Dot temp = new Dot();
        temp = dot;
        dot = cat;
        cat = temp;
        cat.setStatus(Dot.STATUS_IN);
        dot.setStatus(Dot.STATUS_OFF);
        //如果移动后猫已在矩阵边缘,则游戏失败
        if (isAtEdge(cat)){
            lose();
        }
//        getDot(cat.getX(),cat.getY()).setStatus(Dot.STATUS_OFF);
//        dot.setStatus(Dot.STATUS_IN);
//        cat.setXY(dot.getX(), dot.getY());
    }
    private Dot getDot(int x,int y){
        return matrix[y][x];
    }
    Callback callback = new Callback() {
        @Override
        public void surfaceCreated(SurfaceHolder holder) {
            redraw();
        }

        @Override
        public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
            //根据屏幕自适应每个圆圈的宽度
            WIDTH = width / (COL + 1);
            redraw();
        }

        @Override
        public void surfaceDestroyed(SurfaceHolder holder) {

        }
    };

    @Override
    public boolean onTouch(View v, MotionEvent event) {
//        Log.i("info","33333");

        if (event.getAction() == MotionEvent.ACTION_UP){
//            Log.i("info", "44444");
//            Toast.makeText(getContext(),event.getX() + ":" + event.getY(),Toast.LENGTH_SHORT).show();
            int x,y;
            //获取点击点所在的列数
            y = (int) (event.getY() / WIDTH);
            //获取点击点所在的行数
            if (y % 2 == 0){
                x = (int) (event.getX() / WIDTH);
            }
            else {
                x = (int) ((event.getX() - WIDTH/2) / WIDTH);
            }
            //如果点击点不在矩阵范围内,重新初始化游戏
            if (x + 1 > COL || y + 1 > ROW){
                initGame();
            }
            //否则如果点击的圆圈的状态是可点击的,就将此圆圈的状态设置为障碍,并将猫进行移动
            else if (getDot(x,y).getStatus() == Dot.STATUS_OFF){
                getDot(x,y).setStatus(Dot.STATUS_ON);
                move();
            }
            redraw();
//
        }
        return true;
    }

    private void move() {
        //如果猫已在矩阵边缘,则游戏失败
        if (isAtEdge(cat)){
            lose();
            return;
        }
        //猫可以移动的圆圈
        Vector<Dot> available = new Vector<Dot>();
        //猫可以移动的到矩阵边缘没有障碍的圆圈
        Vector<Dot> positive = new Vector<Dot>();
        HashMap<Dot,Integer> al = new HashMap<Dot,Integer>();
        for (int i =1;i<7;i++){
            Dot n = neighbour(cat,i);
            if(n.getStatus() == Dot.STATUS_OFF){
                available.add(n);
                al.put(n,i);
                if (getDistance(n,i) > 0){
                    positive.add(n);
                }
            }
        }
        //如果猫没有可以移动的圆圈,则游戏成功
        if (available.size() == 0){
            win();
        }
        //如果猫只有一个可以移动的圆圈,则移动到此圆圈
        else if (available.size() == 1){
            moveTo(available.get(0));
        }
        //否则选最优的圆圈进行移动
        else{
            Dot best = null;
            //如果存在可以直接到达屏幕边缘的走向
            if (positive.size() != 0){
                System.out.println("向前进");
                int min = 999;
                for (int i = 0;i < positive.size();i ++){
                    int a = getDistance(positive.get(i), al.get(positive.get(i)));
                    if (a < min){
                        min = a;
                        best = positive.get(i);
                    }
                }
            }
            //所有路径均有路障
            else{
                System.out.println("躲路障");
                int max = 0;
                for (int i = 0; i < available.size();i ++){
                    int k = getDistance(available.get(i),al.get(available.get(i)));
                    if (k < max){
                        max = k;
                        best = available.get(i);
                    }
                }
            }

            if(best != null) {
                moveTo(best);
            }
            else{
                moveTo(available.get(0));
            }

//            Dot d = available.get(0);
//            for (int i = 1;i<available.size();i++){
//                if ( Math.min(available.get(i).getX(), available.get(i).getY()) < Math.min(d.getX(),d.getY()) ){
//                    d = available.get(i);
//                }
//            }
//            moveTo(d);
        }
    }
    //赢得游戏
    private void win() {
        Toast.makeText(getContext(),"YOU HAVE WON THE GAME!",Toast.LENGTH_SHORT).show();
    }
    //游戏失败
    private void lose() {
        Toast.makeText(getContext(),"YOU HAVE LOST THE GAME!",Toast.LENGTH_SHORT).show();
    }
}

注:由于本项目只是用于简单学习交流,代码中难免会有bug出现,请自行调试修改。

 

作者:caobotao
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接,否则保留追究法律责任的权利。
posted @ 2015-11-16 08:32  caobotao  阅读(1245)  评论(0编辑  收藏  举报