Android实现连连看游戏

Android实现连连看游戏

本文实例为大家分享了Android实现连连看游戏的具体代码,供大家参考,具体内容如下

本人用 android studio 实现的

源码

主活动 类:

package packageName; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.view.ViewGroup; import android.widget.Button; import android.widget.LinearLayout; import MaView; public class MainActivity extends AppCompatActivity {     @Override     protected void onCreate(Bundle savedInstanceState) {         super.onCreate(savedInstanceState);         setContentView(R.layout.activity_main);         ViewGroup.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);         final MaView mainView = new MaView(this);         addContentView(mainView, params);         // 添加三个按钮执行相应的方法         Button btn = new Button(this);         btn.setText("新游戏");         btn.setTextSize(20);         btn.setX(40);         btn.setY(40);         btn.setOnClickListener(new View.OnClickListener() {             @Override             public void onClick(View v) {                 mainView.newGame();             }         });         addContentView(btn, params);         Button tipBtn = new Button(this);         tipBtn.setText("提示");         tipBtn.setTextSize(20);         tipBtn.setX(380);         tipBtn.setY(40);         tipBtn.setOnClickListener(new View.OnClickListener() {             @Override             public void onClick(View v) {                 mainView.getTip();             }         });         addContentView(tipBtn, params);         Button resetBtn = new Button(this);         resetBtn.setText("重置");         resetBtn.setTextSize(20);         resetBtn.setX(720);         resetBtn.setY(40);         resetBtn.setOnClickListener(new View.OnClickListener() {             @Override             public void onClick(View v) {                 mainView.reset();             }         });         addContentView(resetBtn, params);     } }

MaView 类

package packageName; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Picture; import android.graphics.Rect; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.PictureDrawable; import android.os.Build; import android.support.annotation.RequiresApi; import android.transition.Explode; import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.widget.Toast; import java.util.Random; import java.util.Timer; import java.util.TimerTask; public class MaView extends View {     // 连连看规则: 在一个方形有若干个格子,当选择其中的两个格子时,存在以下几种连线关系时就会被消灭     // 连线只有水平和垂直方向     // 1, 其水平或垂直方向相同,并且两个格子之间无其它非空格子的直线关系     // 2, 有一个折点的 一折点关系     // 3, 有两个折点的 二折点关系     // 左边距     public static final int MARGINLEFT = 40;     // 上边距     public static final int MARGINTOP = 400;     // 格子的行列数     public static final int ROW = 10;     // 格子的宽高     public static final int W = 100;     // 图片的宽高     public static final int IMGW = 90;     // 格子为空     public static final int NULL = -1;     // 连接状态为 直线     public static final int STRAIGHT = 1;     // 连接状态为 一折点     public static final int ONELINK = 2;     // 连接状态为 二折点     public static final int TWOLINK = 3;     // 格子的种类数     public static final int L = 25;     // 存放格子信息的地图     private int[] map = new int[ROW * ROW];     // 存放格子的图片     private Bitmap[] imgs = new Bitmap[L];     // 判断触屏事件是否为点击     private boolean isMove;     // 是否为第一次选择格子     private boolean isFirstSelect;     // 是否可以画连接线和格子的选中边框     private boolean canDrawLine, canDrawRect;     // 是否有提示,没有的话要重置当前格子位置     private boolean canTip;     // 是否可以选择格子     private boolean canPlay;     // 是否已经点击了提示     private boolean firstTip;     // 存储第一次和第二次选中方块的位置     private int x1 = NULL, y1 = NULL, x2 = NULL, y2 = NULL;     // 第一个折点和第二个折点的位置     private int px1, py1, px2, py2;     // 连接线的类别     private int linkState;     // 计数器,用于解决异步问题     private int count = 0;     public MaView(Context context) {         super(context);         // 初始化图片         initImg();         // 初始化游戏         newGame();         // 设置触屏事件         setOnTouchListener(new OnTouchListener() {             @Override             public boolean onTouch(View v, MotionEvent event) {                 // 当前状态不可以点击,如画连接线时会有 0.5 秒的等待时间                 if (!canPlay) {                     return false;                 }                 switch (event.getAction()) {                     case MotionEvent.ACTION_DOWN:                         isMove = false;                         break;                     case MotionEvent.ACTION_MOVE:                         isMove = true;                     case MotionEvent.ACTION_UP:                         // 若为移动事件则不执行                         if (!isMove) {                             // 获取当前点击的位置在网格中的位置                             int x = (int) event.getX() - MARGINLEFT;                             int y = (int) event.getY() - MARGINTOP;                             // 是否超出边界                             if (x < 0 || x > W * ROW || y < 0 || y > W * ROW) {                                 return false;                             }                             // 转化为格子的坐标                             // x 为列, y 为行                             x = x / W % ROW;                             y = y / W;                             // 是否为第一次选择                             if (isFirstSelect) {                                 // 点击的位置是否为空格子                                 if (map[y * ROW + x] == NULL) {                                     return false;                                 }                                 // 存储第一个格子的位置                                 x1 = x;                                 y1 = y;                                 // 可以画边框                                 canDrawRect = true;                                 isFirstSelect = false;                                 // View 自带的方法,会异步执行 onDraw() 方法,起到更新视图的作用                                 invalidate();                             } else {                                 if (map[y * ROW + x] == NULL) {                                     return false;                                 }                                 // 点击的格子是是同一个则重置选择                                 if (x1 == x && y1 == y) {                                     noDraw();                                     // 更新视图                                     invalidate();                                     return false;                                 }                                 // 存储第二个格子的位置                                 x2 = x;                                 y2 = y;                                 // 判断两个格子是否相同                                 if (map[y1 * ROW + x1] == map[y2 * ROW + x2]) {                                     // 是否可以连接                                     if (isCanLink(x1, y1, x2, y2)) {                                         canDrawLine = true;                                         // 更新视图                                         invalidate();                                         // 计数器,防止视图效果不同步                                         count++;                                         waitLose();                                     } else {                                         noDraw();                                         invalidate();                                     }                                 } else {                                     noDraw();                                     invalidate();                                 }                             }                         }                 }                 return true;             }         });     }     // 判断是否赢了     private boolean isWin() {         for (int i = 0; i < ROW * ROW; i++) {             if (map[i] != NULL) {                 return false;             }         }         return true;     }     // 判断是否可以将消除的格子     private void waitLose() {         if (count == 2) {             map[y2 * ROW + x2] = NULL;             map[y1 * ROW + x1] = NULL;             count = 0;         }     }     // 开始新游戏     public void newGame() {         randomMap();         noDraw();         firstTip = true;         canPlay = true;         invalidate();     }     private boolean isCanLink(int x1, int y1, int x2, int y2) {         // 要经过直线连接,一折点连接,二折点连接三个判断         // 垂直直线连接, 其列坐标相同         if (x1 == x2 && isVLink(x1, y1, y2)) {             linkState = STRAIGHT;             return true;         }         // 水平直线连接,其行坐标相同         if (y1 == y2 && isHLink(y1, x1, x2)) {             linkState = STRAIGHT;             return true;         }         // 判断一个折点的连接         if (isOneLink(x1, y1, x2, y2)) {             linkState = ONELINK;             return true;         }         // 判断两个折点的连接         if (isTwoLink(x1, y1, x2, y2)) {             linkState = TWOLINK;             return true;         }         return false;     }     // 垂直直线判断     private boolean isVLink(int x1, int y1, int y2) {         // 保证 y1 永远不大于 y2         if (y1 > y2) {             int t = y1;             y1 = y2;             y2 = t;         }         // 遍历 x, y1 到 y2 的格子         for (int i = y1 + 1; i < y2; i++) {             // 有一个不为空则不能连接             if (map[i * ROW + x1] != NULL) {                 return false;             }         }         return true;     }     // 水平直线判断     private boolean isHLink(int y1, int x1, int x2) {         // 保证 x1 永远不大于 x2         if (x1 > x2) {             int t = x1;             x1 = x2;             x2 = t;         }         // 遍历 x1 到 x2, y 的格子         for (int i = x1 + 1; i < x2; i++) {             // 有一个不为空则不能连接             if (map[y1 * ROW + i] != NULL) {                 return false;             }         }         return true;     }     // 两个折点判断     private boolean isTwoLink(int x1, int y1, int x2, int y2) {         // 保证第一个坐标在左边,便于遍历         if (x1 > x2) {             int t = x1;             x1 = x2;             x2 = t;             t = y1;             y1 = y2;             y2 = t;         }         // 有四个方向判断         // top         // 先将第一个折点上移,然后将第一个折点与第二个坐标用 矩形连接法 进行判断         for (int i = y1 - 1; i >= -1; i--) {             // 若到达了边界,则判断第二个坐标在这个方向是否也能到达边界,若能则可以连接             if (i == -1) {                 // 第二个坐标是否能到达上边界                 if (isCanTop(x2, y2)) {                     // 存储第一个和第二个折点                     px1 = x2;                     py1 = i;                     px2 = x1;                     py2 = i;                     return true;                 }                 break;             }             if (map[x1 + i * ROW] != NULL) {                 break;             }             if (isOneLink(x1, i, x2, y2)) {                 // 存储第二个折点,第一个折点在 一折点连接 中存了                 px2 = x1;                 py2 = i;                 return true;             }         }         // down         for (int i = y1 + 1; i <= ROW; i++) {             if (i == ROW) {                 if (isCanDown(x2, y2)) {                     px1 = x2;                     py1 = i;                     px2 = x1;                     py2 = i;                     return true;                 }                 break;             }             if (map[x1 + i * ROW] != NULL) {                 break;             }             if (isOneLink(x1, i, x2, y2)) {                 px2 = x1;                 py2 = i;                 return true;             }         }         // left         for (int i = x1 - 1; i >= -1; i--) {             if (i == -1) {                 if (isCanLeft(x2, y2)) {                     px2 = i;                     py2 = y1;                     px1 = i;                     py1 = y2;                     return true;                 }                 break;             }             if (map[i + y1 * ROW] != NULL) {                 break;             }             if (isOneLink(i, y1, x2, y2)) {                 px2 = i;                 py2 = y1;                 return true;             }         }         // right         for (int i = x1 + 1; i <= ROW; i++) {             if (i == ROW) {                 if (isCanRight(x2, y2)) {                     px2 = i;                     py2 = y1;                     px1 = i;                     py1 = y2;                     return true;                 }                 break;             }             if (map[i + y1 * ROW] != NULL) {                 break;             }             if (isOneLink(i, y1, x2, y2)) {                 px2 = i;                 py2 = y1;                 return true;             }         }         return false;     }     private boolean isCanTop(int x2, int y2) {         // 遍历坐标与上边界之间的格子,若又不为空的则不能         for (int i = y2 - 1; i >= -1; i--) {             if (i == -1) {                 break;             }             if (map[i * ROW + x2] != NULL) {                 return false;             }         }         return true;     }     private boolean isCanLeft(int x2, int y2) {         for (int i = x2 - 1; i >= -1; i--) {             if (i == -1) {                 break;             }             if (map[y2 * ROW + i] != NULL) {                 return false;             }         }         return true;     }     private boolean isCanRight(int x2, int y2) {         for (int i = x2 + 1; i <= ROW; i++) {             if (i == ROW) {                 break;             }             if (map[y2 * ROW + i] != NULL) {                 return false;             }         }         return true;     }     private boolean isCanDown(int x2, int y2) {         for (int i = y2 + 1; i <= ROW; i++) {             if (i == ROW) {                 break;             }             if (map[i * ROW + x2] != NULL) {                 return false;             }         }         return true;     }     // 一个折点判断     private boolean isOneLink(int x1, int y1, int x2, int y2) {         // 保证第一个坐标在左边,便于遍历         if (x1 > x2) {             int t = x1;             x1 = x2;             x2 = t;             t = y1;             y1 = y2;             y2 = t;         }         // 一个折点的用 矩形判断法, 两个坐标在对角处,折点在另外的对角处         // 先判断这个折点是否为空,不为空就不能连接         // 为空就将两个坐标点与这个折点用直线连接判断,若可以,则可以连接         if (map[y1 * ROW + x2] == NULL) {             if (isHLink(y1, x1, x2) && isVLink(x2, y1, y2)) {                 // 存储第一个折点的位置,便于画线                 px1 = x2;                 py1 = y1;                 return true;             }         }         // 另外一个折点         if (map[x1 + y2 * ROW] == NULL) {             // 注意 x, y 的变换位置             if (isHLink(y2, x1, x2) && isVLink(x1, y1, y2)) {                 // 存储第一个折点的位置,便于画线                 px1 = x1;                 py1 = y2;                 return true;             }         }         return false;     }     private void initImg() {         int id;         for (int i = 0; i < imgs.length; i++) {             id = getResources().getIdentifier("a" + (i + 1), "drawable", getContext().getPackageName());             // 显示图片原尺寸 //            BitmapFactory.Options options = new BitmapFactory.Options(); //            options.inScaled = false;             imgs[i] = BitmapFactory.decodeResource(getResources(), id);             int w = imgs[i].getWidth();             int h = imgs[i].getHeight();             Matrix matrix = new Matrix();             matrix.postScale(IMGW * 1.0f / w, IMGW * 1.0f / h);             imgs[i] = Bitmap.createBitmap(imgs[i], 0, 0, w, h, matrix, true);         }     }     private Bitmap getMyImg(Bitmap rootImg, int goalW, int goalH) {         int rootW = rootImg.getWidth();         int rootH = rootImg.getHeight();         // graphics 包下的         Matrix matrix = new Matrix();         matrix.postScale(goalW * 1.0f / rootW, goalH * 1.0f / rootH);         return Bitmap.createBitmap(rootImg, 0, 0, rootW, rootH, matrix, true);     }     private void randomMap() {         // 初始化地图并将位置打乱         int c = 0;         // 每种格子有四个         for (int i = 0; i < L; i++) {             for (int j = 0; j < 4; j++) {                 map[c] = i;                 c++;             }         }         // 循环 500 次打乱位置         int a, b, t;         Random random = new Random();         for (int i = 0; i < 500; i++) {             a = random.nextInt(ROW * ROW);             b = random.nextInt(ROW * ROW);             if (map[a] == NULL || map[b] == NULL) {                 continue;             }             t = map[a];             map[a] = map[b];             map[b] = t;         }     } //    private void showMap() { //        String s = ""; //        int c = 0; //        for (int i = 0; i < ROW; i++) { //            for (int j = 0; j < ROW; j++) { //                s += map[c] + " "; //                c++; //            } //            s = ""; //        } //    }     @Override     protected void onDraw(Canvas canvas) {         int x, y;         int c = 0;         // 画格子         for (int i = 0; i < ROW; i++) {             for (int j = 0; j < ROW; j++) {                 x = MARGINLEFT + j * W;                 y = MARGINTOP + i * W;                 if (map[c] != NULL) {                     canvas.drawBitmap(imgs[map[c]], x, y, new Paint());                 }                 c++;             }         }         // 画提示的格子边框         if (canTip) {             // 设置线条的样式             Paint paint = new Paint();             paint.setStrokeWidth(8);             paint.setColor(Color.parseColor("#08ffc8"));             paint.setStyle(Paint.Style.STROKE);             x = x1 * W + MARGINLEFT;             y = y1 * W + MARGINTOP;             canvas.drawRect(x, y, x + W - 3, y + W - 3, paint);             x = x2 * W + MARGINLEFT;             y = y2 * W + MARGINTOP;             canvas.drawRect(x, y, x + W - 3, y + W - 3, paint);             canTip = false;             noDraw();         }         // 画已选格子的边框         if (canDrawRect) {             Paint paint = new Paint();             paint.setStrokeWidth(8);             paint.setColor(Color.RED);             paint.setStyle(Paint.Style.STROKE);             // 第一个格子             if (x1 != NULL) {                 x = x1 * W + MARGINLEFT;                 y = y1 * W + MARGINTOP;                 canvas.drawRect(x, y, x + W - 3, y + W - 3, paint);                 firstTip = true;             }             // 第二个格子             if (x2 != NULL) {                 x = x2 * W + MARGINLEFT;                 y = y2 * W + MARGINTOP;                 canvas.drawRect(x, y, x + W - 3, y + W - 3, paint);                 count++;                 waitLose();             }         }         // 画连接线         if (canDrawLine) {             Paint paint = new Paint();             paint.setStrokeWidth(8);             paint.setColor(Color.RED);             paint.setStyle(Paint.Style.FILL);             int sx1, sy1, sx2, sy2, zx1, zy1, zx2, zy2;             // 第一个坐标             sx1 = x1 * W + W + MARGINLEFT - W / 2;             sy1 = y1 * W + W + MARGINTOP - W / 2;             // 第二个坐标             sx2 = x2 * W + W + MARGINLEFT - W / 2;             sy2 = y2 * W + W + MARGINTOP - W / 2;             switch (linkState) {                 case STRAIGHT:                     // 画直线                     canvas.drawLine(sx1, sy1, sx2, sy2, paint);                     break;                 case ONELINK:                     // 画一折点线                     zx1 = px1 * W + MARGINLEFT + W / 2;                     zy1 = py1 * W + MARGINTOP + W / 2;                     canvas.drawLine(sx1, sy1, zx1, zy1, paint);                     canvas.drawLine(zx1, zy1, sx2, sy2, paint);                     break;                 case TWOLINK:                     // 画二折点线                     // 第二个折点                     zx1 = px1 * W + MARGINLEFT + W / 2;                     zy1 = py1 * W + MARGINTOP + W / 2;                     // 第一个折点                     zx2 = px2 * W + MARGINLEFT + W / 2;                     zy2 = py2 * W + MARGINTOP + W / 2;                     // 到边界了改变一下线条的位置                     if (px1 == -1) {                         zx1 += 30;                         zx2 += 30;                     } else if (px1 == ROW) {                         zx1 -= 30;                         zx2 -= 30;                     }                     // 有左右两种情况,上下两种情况,但第一个折点一定与第一个坐标的 x 或 y 相同                     if (px1 == x1 || py1 == y1) {                         int t = zx1;                         zx1 = zx2;                         zx2 = t;                         t = zy1;                         zy1 = zy2;                         zy2 = t;                     }                     canvas.drawLine(sx1, sy1, zx2, zy2, paint);                     canvas.drawLine(zx2, zy2, zx1, zy1, paint);                     canvas.drawLine(zx1, zy1, sx2, sy2, paint);             }             noDraw();             // 画线过程不能点击             canPlay = false;             // 开一个线程做连接效果             new Timer().schedule(new TimerTask() {                 @Override                 public void run() {                     // 这个方法用于转到主线程中执行,更新视图操作必须放到主线程中执行 其 invalidate() 跟新了视图                     post(new Runnable() {                         @Override                         public void run() {                             invalidate();                             // 判断是否赢了没                             if (isWin()) {                                 Toast.makeText(getContext(), "You Win! Please New Game", Toast.LENGTH_SHORT).show();                             }                             // 可以点击了                             canPlay = true;                         }                     });                 }             }, 500);         }     }     // 重置当前图片的位置     public void reset() {         if (!canPlay) {             return;         }         int a, b, t;         Random random = new Random();         for (int i = 0; i < 500; i++) {             a = random.nextInt(ROW * ROW);             b = random.nextInt(ROW * ROW);             if (map[a] == NULL || map[b] == NULL) {                 continue;             }             t = map[a];             map[a] = map[b];             map[b] = t;         }         invalidate();     }     // 获取提示     public void getTip() {         if (!canPlay) {             return;         }         // 不能连续点击         if (!firstTip) {             Toast.makeText(getContext(), "Alright Tip!", Toast.LENGTH_SHORT).show();             return;         }         firstTip = false;         int count = 0;         int x1, y1, x2, y2;         Tag:         for (int i = 0; i < ROW * ROW; i++) {             if (map[i] == NULL) {                 continue;             }             for (int j = i + 1; j < ROW * ROW; j++) {                 if (map[j] == NULL) {                     continue;                 }                 if (map[i] == map[j]) {                     x1 = i % ROW;                     y1 = i / ROW;                     x2 = j % ROW;                     y2 = j / ROW;                     if (isCanLink(x1, y1, x2, y2)) {                         count++;                         this.x1 = x1;                         this.y1 = y1;                         this.x2 = x2;                         this.y2 = y2;                         break Tag;                     }                 }             }         }         // 不为空则有可连接的格子         if (count != 0) {             canTip = true;             invalidate();         } else {             Toast.makeText(getContext(), "No One! Please Click New Game", Toast.LENGTH_SHORT).show();         }     }     // 重置选择格子     private void noDraw() {         canDrawRect = false;         canDrawLine = false;         isFirstSelect = true;         x1 = NULL;         x2 = NULL;         y1 = NULL;         y2 = NULL;     } }

推荐阅读