android 自定义五子棋
来源:互联网 发布:最小公倍数的算法 编辑:程序博客网 时间:2024/05/17 08:18
中午休息的时候,坐我旁边的同事喜欢玩五子棋,玩的很入迷。作为吃瓜群众的我,偶尔看他玩一两局。于是乎这两天想着实现一个简易的五子棋小游戏。本文重点是图形绘制。
首先看效果图:
下面讲解下思路:
1.绘制棋盘区域
针对手机这种宽度比长度小的,默认取宽度的1/11为棋盘的单位长度,然后根据在onSizeChanged()中获取到测量宽高尺寸getMeasuredWidth()和getMeasuredHeight(),然后在onDraw()中进行画线。
@Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); width = getMeasuredWidth(); height = getMeasuredHeight(); itemW = width / 11; row = height / itemW; column = width / itemW; coos = new Point[row][column]; //確定坐标点 for (int i = 0; i < row; i++) { for (int j = 0; j < column; j++) { coos[i][j] = new Point(j * itemW, i * itemW); } } //新建 Bitmap 对象,用来双缓冲 if (bitmapBuffer == null) bitmapBuffer = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); bitmapCanvas = new Canvas(bitmapBuffer); }
@Override protected void onDraw(Canvas canvas) { //先画线 for (int i = 0; i < row; i++) {//水平线 canvas.drawLine(0, itemW * i, width, itemW * i, paintLine); //确定每个点的坐标 } for (int j = 0; j < column; j++) {//竖直线 canvas.drawLine(itemW * j, 0, itemW * j, height, paintLine); } }
2.绘制棋子
棋子有两种,即红黑(别人家的都是黑白,嘿嘿),可以找美工要俩棋子的图片,然后往canvas上绘制图片,也可以自己绘制,这样减少apk的资源包占用。绘制过程中,需要做渐变的处理,系统提供了很多种渐变的支持,我们用RadialGradient渐变。
绘制黑棋过程:
Paint paint = new Paint();paint.setColor(Color.BLACK); paint.setShader(new RadialGradient(currPoint.x, currPoint.y, itemW / 3, Color.WHITE, Color.BLACK , Shader.TileMode.CLAMP));bitmapCanvas.drawCircle(currPoint.x, currPoint.y, itemW / 3, paint);//画棋子if (currPoint != null) { canvas.drawBitmap(bitmapBuffer, 0, 0, null);}
/** * 根据点击的位置确定坐标 * * @param pressX * @param pressY */ private Point measureCoo(float pressX, float pressY) { int x = (int) (pressX / itemW + 0.5f); int y = (int) (pressY / itemW + 0.5f); Log.d(TAG, "y=" + y + " x=" + x + " column=" + column); if (y >= row || x >= column) return null; return coos[y][x]; }
应用了双缓冲机制,目的是保留上次绘制的状态,防止下次绘制清空上次的绘制。
3.监听用户交互事件
重写onTouchEvent(MotionEvent event)事件,监听手指抬起的动作,然后向目标位置绘制五子棋。
@Override public boolean onTouchEvent(MotionEvent event) { int action = event.getAction(); switch (action) { case MotionEvent.ACTION_UP: if (!isEditAble) { Toast.makeText(context, "重新开局!", Toast.LENGTH_LONG).show(); resetData(); invalidate(); return true; } float pressX = event.getX(); float pressY = event.getY(); currPoint = measureCoo(pressX, pressY); if (currPoint == null || blackPoints.contains(currPoint) || redPoints.contains(currPoint)) return true; if (type == Type.TYPE_BLACK) blackPoints.add(currPoint);//保存到记录中,用于计算输赢 else redPoints.add(currPoint); paint.setColor(type == Type.TYPE_BLACK ? Color.BLACK : Color.RED); paint.setShader(new RadialGradient(currPoint.x, currPoint.y, itemW / 3, Color.WHITE, type == Type.TYPE_BLACK ? Color.BLACK : Color.RED, Shader.TileMode.CLAMP)); if (calculateVictory(type)) { //如果胜了,直接弹出toast isEditAble = false;//胜利了,本局结束 paint.setStyle(Paint.Style.STROKE); paint.setPathEffect(new DashPathEffect(new float[]{2, 2}, 1)); Toast.makeText(context, type == Type.TYPE_BLACK ? "黑棋胜利了" : "红旗胜利了", Toast.LENGTH_LONG).show(); } bitmapCanvas.drawCircle(currPoint.x, currPoint.y, itemW / 3, paint); invalidate(); paint.setStyle(Paint.Style.FILL); paint.setPathEffect(null); type = Type.change(type); break; } return true; }
4.处理判断输赢的算法。
上面代码中calculateVictory()为处理判断输赢,目前想到了这样一个时间复杂度为O(N*k)的算法。但是感觉还是不够完善。如果有更好的建议希望能提出,在此先谢过。
private boolean calculateVictory(Type type) { if (type == Type.TYPE_BLACK) { if (blackPoints.size() < 5) return false; if (horizonOrVerticalOk(blackPoints) || gradientOk(blackPoints)) return true; } else { if (redPoints.size() < 5) return false; if (horizonOrVerticalOk(redPoints) || gradientOk(redPoints)) return true; } return false; } List<Integer> xlistY = new ArrayList<>(); List<Integer> ylistX = new ArrayList<>(); /** * 水平方向满足连续5个则获胜 * * @param points * @return */ private boolean horizonOrVerticalOk(List<Point> points) { int xCount = 1, yCount = 1; xlistY.clear(); ylistX.clear(); Point currPoint = points.get(points.size() - 1);//获取当前棋子 int currX = currPoint.x; int currY = currPoint.y; xlistY.add(currY); ylistX.add(currX); for (int j = 0; j < points.size() - 1; j++) { if (currX == points.get(j).x) { xlistY.add(points.get(j).y); xCount++; } if (currY == points.get(j).y) { ylistX.add(points.get(j).x); yCount++; } } if (xCount >= 5) { for (int m = 0; m < xlistY.size(); m++) {//由于不确定最后一个棋子所处的位置,所以需要遍历 int targetY = xlistY.get(m); int pos = targetY / itemW; try { if (xlistY.contains((pos + 1) * itemW) && xlistY.contains((pos + 2) * itemW) && xlistY.contains((pos + 3) * itemW) && xlistY.contains((pos + 4) * itemW)) return true; } catch (Exception e) { e.printStackTrace(); } } } if (yCount >= 5) { for (int n = 0; n < ylistX.size(); n++) { int xVal = ylistX.get(n); int pos = xVal / itemW; try { if (ylistX.contains((pos + 1) * itemW) && ylistX.contains((pos + 2) * itemW) && ylistX.contains((pos + 3) * itemW) && ylistX.contains((pos + 4) * itemW)) return true; } catch (Exception e) { e.printStackTrace(); } } } return false; } /** * 倾斜方向上满足连续5个则获胜 * * @param points * @return */ private boolean gradientOk(List<Point> points) { int xCount = 1, yCount = 1; xlistY.clear(); ylistX.clear(); Point currPoint = points.get(points.size() - 1);//获取当前棋子 int currX = currPoint.x; int currY = currPoint.y; xlistY.add(currY); ylistX.add(currX); for (int j = 0; j < points.size()-1; j++) { if ((points.get(j).x - currX) == (points.get(j).y) - currY) { xlistY.add(points.get(j).y); xCount++; } if ((currX - points.get(j).x) == (points.get(j).y) - currY) { ylistX.add(points.get(j).x); yCount++; } } if (xCount >= 5) { for (int m = 0; m < xlistY.size(); m++) { int yVal = xlistY.get(m); int pos = yVal / itemW; try { if (xlistY.contains((pos + 1) * itemW) && xlistY.contains((pos + 2) * itemW) && xlistY.contains((pos + 3) * itemW) && xlistY.contains((pos + 4) * itemW)) return true; } catch (Exception e) { e.printStackTrace(); } } } if (yCount >= 5) { for (int n = 0; n < ylistX.size(); n++) { int xVal = ylistX.get(n); int pos = xVal / itemW; try { if (ylistX.contains((pos + 1) * itemW) && ylistX.contains((pos + 2) * itemW) && ylistX.contains((pos + 3) * itemW) && ylistX.contains((pos + 4) * itemW)) return true; } catch (Exception e) { e.printStackTrace(); } } } return false; }
核心内容基本是这些。
0 0
- android 自定义五子棋
- android自定义View 五子棋小游戏
- Android 开发 -------- 自定义View 画 五子棋
- Android之自定义view的五子棋游戏
- android自定义View之五子棋小游戏
- Android自定义View实现五子棋小游戏
- 自定义控件--五子棋
- 自定义View之一五子棋
- 自定义View实现五子棋游戏
- 自定义view(二)五子棋
- android 五子棋实验总结
- android五子棋游戏源码
- android studio 五子棋游戏
- 详细注释-Android五子棋
- android-五子棋项目
- Android 五子棋开发经验
- Android五子棋棋盘的绘制
- Android 画五子棋的棋盘
- vector操作小结
- android真机socket连接要点
- Mysql的四种隔离级别
- H5停车场预订位置(电影院选座)前端后端
- 用汇编的思想理解C/C++
- android 自定义五子棋
- 性能调优攻略|系统调优
- 重温HTTP
- 2.python开源——scrapy使用
- 单例模式学习
- 一天就学会Android开发四大组件
- bzoj 4327: JSOI2012 玄武密码 (AC自动机)
- leecode 解题总结:365. Water and Jug Problem
- 关于python的bottle框架跨域请求报错问题的处理