热门标签 | HotTags
当前位置:  开发笔记 > Android > 正文

Android自定义View实现数独游戏

这篇文章主要为大家详细介绍了Android自定义View实现数独游戏,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

先说一下数独游戏的规则:

1.在整个横坐标和纵坐标的9个格子上只能填土1-9的数字且不重复
2.在当前3*3 的格子上填入1-9数字且不重复

先给大家看效果图

项目思路

1、UI呈现:这个放在 GameView 类里面
        显示原始数据
        显示当然用户填写的数据
        显示用户当前点击的位置
        显示候选区数据

2、逻辑处理:这个是放在Matrix类里面的
    原始数据:游戏开始的时候就要创建出来的,
    当前数据:用户填写上去的实时数据
    数据判断:判断这个位置可以修改数据吗? 比如,原始数据就是不可以修改的
            判断这个位置可以填入的数据,比如,原始数据这个位置有8了,就不能填8了。

代码 GameView 类

public class GameView extends View {

 private int PhoneWidth; // 手机屏幕的宽度
 private int mGridWidth; // 当前格子的宽度

 private int[] mFalseNumber; // 候选区不能填写的数字

 private Paint mLinePaint; // 白线
 private Paint mDarkPaint; // 浅蓝色的 方格子
 private Paint mOptDarkPaint; // 用户点击 浅绿色的格子
 private Paint numberPaint; // 原始数据 数字
 private Paint changePaint; // 用户填写的数字
 private Paint mOptPaint; // 候选区数字

 private Matrix M; // 用户计算类

 private float tCX; 
 private float tCY;
 private int mOptBoard;
 private int mOptNumber;

 public GameView(Context context, AttributeSet attrs, int defStyleAttr) {
 super(context, attrs, defStyleAttr);
 initView();
 }

 public GameView(Context context, AttributeSet attrs) {
 super(context, attrs);
 initView();
 }

 public GameView(Context context) {
 super(context);

 initView();
 }

 private void initView() {

 PhOneWidth= getResources().getDisplayMetrics().widthPixels;
 mGridWidth = (PhoneWidth - 40) / 9;

 tCX = mGridWidth / 2;
 tCY = tCX - tCX / 2;

 mFalseNumber = new int[9];

 for (int i = 0; i <9; i++) {
  mFalseNumber[i] = i;
 }

 M = new Matrix();
 initPaint();

 invalidate();
 }

 private void initPaint() {
 mLinePaint = new Paint();
 mLinePaint.setColor(Color.WHITE);
 mLinePaint.setStyle(Paint.Style.STROKE);
 mLinePaint.setStrokeWidth(2f);

 mDarkPaint = new Paint();
 mDarkPaint.setColor(Color.parseColor("#52E7CD"));
 mDarkPaint.setStyle(Paint.Style.FILL);

 numberPaint = new Paint();
 numberPaint.setColor(Color.WHITE);
 numberPaint.setTextSize(mGridWidth * 0.65f);
 numberPaint.setTextAlign(Paint.Align.CENTER);
 numberPaint.setShadowLayer(10F, -5F, 8F, Color.parseColor("#999999"));
 numberPaint.setAntiAlias(true);

 mOptPaint = new Paint();
 mOptPaint.setColor(Color.WHITE);
 mOptPaint.setTextSize(mGridWidth * 0.65f+15);
 mOptPaint.setTextAlign(Paint.Align.CENTER);
 mOptPaint.setShadowLayer(10F, -5F, 8F, Color.parseColor("#999999"));
 mOptPaint.setAntiAlias(true);

 changePaint = new Paint();
 changePaint.setColor(Color.parseColor("#FCA454"));
 changePaint.setTextSize(mGridWidth * 0.65f);
 changePaint.setTextAlign(Paint.Align.CENTER);
 changePaint.setShadowLayer(10F, -5F, 8F, Color.parseColor("#999999"));
 changePaint.setAntiAlias(true);

 mOptDarkPaint = new Paint();
 mOptDarkPaint.setColor(Color.parseColor("#52E76E"));
 mOptDarkPaint.setStyle(Paint.Style.FILL);
 }

 @Override
 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
 super.onMeasure(widthMeasureSpec, heightMeasureSpec);
 setMeasuredDimension(PhoneWidth, PhoneWidth + mGridWidth+20);
 }

 @Override
 protected void onDraw(Canvas canvas) {

 drawBoard(canvas);

 int x = mOptBoard / 9;
 int y = mOptBoard % 9;
 // 画出棋盘选择框
 canvas.drawRect(x * mGridWidth+22, y * mGridWidth+22, x * mGridWidth+20 + mGridWidth, y * mGridWidth+20 + mGridWidth, mOptDarkPaint);

 // 当前棋盘数据
 for (int i = 0; i <9; i++) {
  for (int j = 0; j <9; j++) {
  int cutData = M.getCutData(i, j);
  if (M.getOnClicked(i,j) && cutData>0) {
   canvas.drawText(Integer.toString(cutData), i * mGridWidth + tCX+20, j*mGridWidth + mGridWidth - tCY+20, changePaint);
  }
  } 
 }

 // 候选区文字

 drawTrueText(canvas);

 }

 private void drawTrueText(Canvas canvas) {
 float startY = PhoneWidth + 30;

 // 画平行四边形
 canvas.drawLine(50, startY, PhoneWidth-50, startY, mLinePaint);
 canvas.drawLine(10, startY + mGridWidth - 40, PhoneWidth-10, startY + mGridWidth-40, mLinePaint);
 canvas.drawLine(50, startY, 10, startY + mGridWidth - 40, mLinePaint);
 canvas.drawLine(PhoneWidth-50, startY, PhoneWidth-10, startY + mGridWidth-40, mLinePaint);

 float y = (mGridWidth - 30)/2.0f;

 for (int i = 0; i <9; i++) {
  if (mFalseNumber[i] == 0) {
  canvas.drawText(Integer.toString(i+1), i * mGridWidth + tCX+ 20, startY + (mGridWidth - tCY) - y, mOptPaint);
  }
 }
 }

 private void drawBoard(Canvas canvas) {

 // 画底色
 for (int i = 0; i <9; i++) {
  for (int j = 0; j <9; j++) {
  int x = i / 3;
  int y = j / 3;
  if ((x == 0 || x == 2) && (y == 0 || y == 2)) {
   canvas.drawRect(mGridWidth * j + 20, 20 + mGridWidth * i,
    mGridWidth * j + 20 + mGridWidth, 20 + mGridWidth
     * i + mGridWidth, mDarkPaint);
  } else if (y == 1 && x == 1) {
   canvas.drawRect(mGridWidth * j + 20, 20 + mGridWidth * i,
    mGridWidth * j + 20 + mGridWidth, 20 + mGridWidth
     * i + mGridWidth, mDarkPaint);
  }

  }
 }

 // 画白线
 for (int i = 0; i <10; i++) {
  canvas.drawLine(20, mGridWidth * i + 1 + 20, 9 * mGridWidth + 20,
   mGridWidth * i + 1 + 20, mLinePaint);
  canvas.drawLine(mGridWidth * i + 1 + 20, 0 + 20, mGridWidth * i + 1
   + 20, 9 * mGridWidth + 20, mLinePaint);
 }

 //画初始数字
 for (int i = 0; i <9; i++) {
  for (int j = 0; j <9; j++) {
  if (!M.getOnClicked(i, j)) {
   canvas.drawText(M.getText(i, j), i * mGridWidth +20+tCX, mGridWidth * j + 20+mGridWidth-tCY, numberPaint);

  }
  }
 }
 }


 @Override
 public boolean onTouchEvent(MotionEvent event) {
 if (event.getAction() != MotionEvent.ACTION_DOWN) {
  return super.onTouchEvent(event);
 }

 if (event.getX()<20 || event.getY()<20 || event.getX()>PhoneWidth-20) {
  Log.e("123", "点到边了");
  return super.onTouchEvent(event);
 }

 int choX = (int) ((event.getX()-20) / mGridWidth);
 int choY = (int) ((event.getY()-20) / mGridWidth);

 Log.i("game ", "optX "+choX+" optY "+choY);

 if (event.getY() 

代码 Matrix类

public class Matrix {

 private int [][]mData ; // 原始数据
 private int [][]mCutData; // 当前数据


 public Matrix() {

 int i = (int)(Math.random()*5);

 switch (i) {
 case 1:
  mData = GAMEDATA1;
  break;
 case 2:
  mData = GAMEDATA2;
  break;
 case 3:
  mData = GAMEDATA3;
  break;
 case 4:
  mData = GAMEDATA4;
  break;
 case 0:
  mData = GAMEDATA2;
  break;

 }
 initCutData();
 Log.e("Matrix", "random :"+i);

 }


 /** 得到当前坐标上的文字 */
 public String getText(int x, int y){

 String index = mData[x][y]+"";

 if ("0".equals(index)) {
  index = "";
 }

 return index;

 }

 /** 判断该坐标是否可以点击 */
 public boolean getOnClicked(int x, int y){

 if (mData[x][y] == 0) {
  return true;
 }
 return false;

 }

 /** 判断该坐标有哪些数不可用 */
 public int[] getFalseData(int x, int y){
 Set set = new TreeSet();

 // 检查X 轴有哪些不能点

 for (int i = 0; i <9; i++) {
  int d = mData[y][i];

  if (d!=0) {
  set.add(d);
//  LogUtils.e("x: "+d);
  }
 }
 // 检查 y 轴有哪些不能点
 for (int i = 0; i <9; i++) {
  int d = mData[i][x];
  if (d!=0) {
  set.add(d);
//  LogUtils.e("Y: "+d);
  }
 }

 // 检查 3*3 方格哪些不能点

 x = x/3*3;
 y = y/3*3;

// LogUtils.e(" x "+x+" Y "+y);

 for (int i = x; i 

代码 MainActivity 类

public class MainActivity extends Activity {

 private GameView gV;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);

 gV = (GameView) findViewById(R.id.game);
 }

 public void rePay(View v){
 gV.repeat();
 }
 public void newPay(View v){
 gV.play();

 }

acitivity_main.xml 文件



 

 

 

 

然后运行起来就是这个样子的了。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。


推荐阅读
  • Android 九宫格布局详解及实现:人人网应用示例
    本文深入探讨了人人网Android应用中独特的九宫格布局设计,解析其背后的GridView实现原理,并提供详细的代码示例。这种布局方式不仅美观大方,而且在现代Android应用中较为少见,值得开发者借鉴。 ... [详细]
  • 优化ListView性能
    本文深入探讨了如何通过多种技术手段优化ListView的性能,包括视图复用、ViewHolder模式、分批加载数据、图片优化及内存管理等。这些方法能够显著提升应用的响应速度和用户体验。 ... [详细]
  • 深入理解OAuth认证机制
    本文介绍了OAuth认证协议的核心概念及其工作原理。OAuth是一种开放标准,旨在为第三方应用提供安全的用户资源访问授权,同时确保用户的账户信息(如用户名和密码)不会暴露给第三方。 ... [详细]
  • 深入解析Android自定义View面试题
    本文探讨了Android Launcher开发中自定义View的重要性,并通过一道经典的面试题,帮助开发者更好地理解自定义View的实现细节。文章不仅涵盖了基础知识,还提供了实际操作建议。 ... [详细]
  • 国内BI工具迎战国际巨头Tableau,稳步崛起
    尽管商业智能(BI)工具在中国的普及程度尚不及国际市场,但近年来,随着本土企业的持续创新和市场推广,国内主流BI工具正逐渐崭露头角。面对国际品牌如Tableau的强大竞争,国内BI工具通过不断优化产品和技术,赢得了越来越多用户的认可。 ... [详细]
  • 本文详细介绍如何使用arm-eabi-gdb调试Android平台上的C/C++程序。通过具体步骤和实用技巧,帮助开发者更高效地进行调试工作。 ... [详细]
  • 深入理解 Oracle 存储函数:计算员工年收入
    本文介绍如何使用 Oracle 存储函数查询特定员工的年收入。我们将详细解释存储函数的创建过程,并提供完整的代码示例。 ... [详细]
  • 本文总结了2018年的关键成就,包括职业变动、购车、考取驾照等重要事件,并分享了读书、工作、家庭和朋友方面的感悟。同时,展望2019年,制定了健康、软实力提升和技术学习的具体目标。 ... [详细]
  • 在计算机技术的学习道路上,51CTO学院以其专业性和专注度给我留下了深刻印象。从2012年接触计算机到2014年开始系统学习网络技术和安全领域,51CTO学院始终是我信赖的学习平台。 ... [详细]
  • CSS 布局:液态三栏混合宽度布局
    本文介绍了如何使用 CSS 实现液态的三栏布局,其中各栏具有不同的宽度设置。通过调整容器和内容区域的属性,可以实现灵活且响应式的网页设计。 ... [详细]
  • Linux 系统启动故障排除指南:MBR 和 GRUB 问题
    本文详细介绍了 Linux 系统启动过程中常见的 MBR 扇区和 GRUB 引导程序故障及其解决方案,涵盖从备份、模拟故障到恢复的具体步骤。 ... [详细]
  • 本文介绍了如何使用jQuery根据元素的类型(如复选框)和标签名(如段落)来获取DOM对象。这有助于更高效地操作网页中的特定元素。 ... [详细]
  • 本文将详细介绍如何使用剪映应用中的镜像功能,帮助用户轻松实现视频的镜像效果。通过简单的步骤,您可以快速掌握这一实用技巧。 ... [详细]
  • 深入理解Cookie与Session会话管理
    本文详细介绍了如何通过HTTP响应和请求处理浏览器的Cookie信息,以及如何创建、设置和管理Cookie。同时探讨了会话跟踪技术中的Session机制,解释其原理及应用场景。 ... [详细]
  • 本文介绍如何在 Xcode 中使用快捷键和菜单命令对多行代码进行缩进,包括右缩进和左缩进的具体操作方法。 ... [详细]
author-avatar
我就唔分_753
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有