最近研究了一下android,写了一个数独游戏,具体如下:

游戏界面需要重写一个ShuduView继承View,

然后自定义一个Dialog:

1.需要继承 Dialog 类,

2.并要定义一个有参构造函数(因为父类里面没有无参构造函数)

3.重写 onCreate方法,一切操作将在此方法进行

流程:

为每个按钮添加监听事件,

刷新九宫格里的数字,也就是重新绘制画面(在view类中调用 invalidate();),

更新备选数字数组 ( 每次修改之后都得 进行重新计算 不可用的值   calculateAllUsedTiles() ; )

下面介绍主要代码:

ShuduView:

 package com.soccer.shudu;

 import android.content.Context;
import android.graphics.*;
import android.graphics.Paint.FontMetrics; import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager; public class ShuduView extends View{ public ShuduView(Context context) {
super(context);
// TODO Auto-generated constructor stub
} private float width;
private float height; private Game game = new Game(); @Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
//计算当前单元格宽度和高度
this.height = h / 9f;
this.width = w / 9f;
super.onSizeChanged(w, h, oldw, oldh);
} //当android的系统需要绘制一个view对象时,就需要调用该对象的onDraw方法
@Override
protected void onDraw(Canvas canvas) {
//生成用户绘制背景色的画笔
Paint backgroundPaint = new Paint();
//设置画笔颜色
backgroundPaint.setColor(getResources().getColor(R.color.shudu_background));
//绘制背景色
canvas.drawRect(0, 0, getWidth(), getHeight(), backgroundPaint); Paint darkPaint = new Paint();
darkPaint.setColor(getResources().getColor(R.color.shudu_dark)); Paint hilitePaint = new Paint();
hilitePaint.setColor(getResources().getColor(R.color.shudu_hilite)); Paint lightPaint = new Paint();
lightPaint.setColor(getResources().getColor(R.color.shudu_light)); for(int i = 0;i < 9;i++){
//绘制横向的线
canvas.drawLine(0, i * height,getWidth(), i * height, lightPaint);
canvas.drawLine(0, i * height + 1,getWidth(), i * height + 1, hilitePaint);
//绘制纵向的线
canvas.drawLine(i * width, 0, i * width, getHeight(), lightPaint);
canvas.drawLine(i * width + 1, 0, i * width + 1, getHeight(), hilitePaint);
} for(int i = 0;i < 3;i++){
//绘制横向的线
canvas.drawLine(0, i * 3 * height, getWidth(), i * 3 * height, darkPaint);
canvas.drawLine(0, i * 3 * height + 1, getWidth(), i * 3 * height + 1, darkPaint);
//绘制纵向的线
canvas.drawLine(i * 3 * width, 0, i * 3 * width, getHeight(), darkPaint);
canvas.drawLine(i * 3 * width + 1, 0, i * 3 * width + 1, getHeight(), darkPaint);
}
//绘制数字
Paint numberPaint = new Paint();
numberPaint.setColor(Color.BLACK);
//numberPaint.setStyle(Paint.Style.STROKE);
numberPaint.setTextSize( height * 0.75f);
numberPaint.setTextAlign(Paint.Align.CENTER);
//将数字加到格子中
FontMetrics fm = numberPaint.getFontMetrics();
float x = width / 2;
float y = height / 2 - (fm.ascent + fm.descent) / 2;
//canvas.drawText("1", 3 * width + x, height + y , numberPaint);
for(int i = 0;i < 9;i++){
for(int j = 0;j < 9;j++){
canvas.drawText(game.getTileString(i, j), i * width+x, j * height + y, numberPaint);
}
} super.onDraw(canvas);
} int selectedX;
int selectedY; @Override
public boolean onTouchEvent(MotionEvent event) {
if(event.getAction() != MotionEvent.ACTION_DOWN){
return super.onTouchEvent(event);
} selectedX = (int)(event.getX() / width);
selectedY = (int)(event.getY() / height); int used[] = game.getUsedTileByCoor(selectedX, selectedY);
StringBuffer sb = new StringBuffer();
for(int i = 0; i < used.length;i++){
System.out.println(used[i] );
//sb.append(used[i]);
} //生成一个LayoutInflater对象
//LayoutInflater layoutInflater = LayoutInflater.from(this.getContext());
//View layoutView = layoutInflater.inflate(R.layout.dialog, null);
//从生成好的textView中 取出相应的控件
//TextView textView =(TextView)layoutView.findViewById(R.id.usedTextId); //textView.setText(sb.toString()); //AlertDialog.Builder builder = new AlertDialog.Builder(this.getContext());
//builder.setView(layoutView); //AlertDialog dialog = builder.create();
//dialog.show();
//dialog.getWindow().setLayout(300, 200);
KeyDialog keyDialog = new KeyDialog(getContext(), used,this);
//透明度
WindowManager.LayoutParams lp=keyDialog.getWindow().getAttributes();
lp.alpha=0.9f;
keyDialog.getWindow().setAttributes(lp); keyDialog.show();
return true;
} public void setSelectedTile(int tile){ if(game.setTileIfValid(selectedX,selectedY,tile)){
invalidate();
}
} }

KeyDialog:

 package com.soccer.shudu;

 import android.app.Dialog;
import android.content.Context;
import android.os.Bundle;
import android.view.View;
import android.widget.Button; //该类用于实现dialog自定义对话框功能
public class KeyDialog extends Dialog{
private final View keys [] = new View[9];
private final int used[]; private ShuduView shuduView = null; public KeyDialog(Context context,int [] used,ShuduView shuduView){
super(context);
this.used = used;
this.shuduView = shuduView;
}
//当一个dialog第一次显示的时候,会调用其onCreate方法
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setTitle("可选数字");
setContentView(R.layout.keypad);
findViews();
for(int i = 0;i < used.length;i++){
if(used[i] != 0){
keys[used[i] - 1].setVisibility(View.INVISIBLE);
}
}
//为每个键设置监听器
setListeners(); //为返回按钮设置监听器
Button back_Button = (Button)findViewById(R.id.back_1);
back_Button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dismiss(); }
});
} private void findViews(){
keys[0] = findViewById(R.id.keypad_1);
keys[1] = findViewById(R.id.keypad_2);
keys[2] = findViewById(R.id.keypad_3);
keys[3] = findViewById(R.id.keypad_4);
keys[4] = findViewById(R.id.keypad_5);
keys[5] = findViewById(R.id.keypad_6);
keys[6] = findViewById(R.id.keypad_7);
keys[7] = findViewById(R.id.keypad_8);
keys[8] = findViewById(R.id.keypad_9);
} //通知ShuduView对象,刷新整个九宫格显示的数据
private void returnResult(int tile){
shuduView.setSelectedTile(tile);
dismiss();
} private void setListeners(){
for(int i = 0; i < keys.length; i++){
final int t = i + 1;
keys[i].setOnClickListener(new View.OnClickListener() { @Override
public void onClick(View v) {
returnResult(t); }
});
}
} }

keypad.xml:

 <?xml version="1.0" encoding="utf-8"?>
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/keypad"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:stretchColumns="*" > <TableRow>
<Button android:id="@+id/keypad_1"
android:text="1">
</Button>
<Button android:id="@+id/keypad_2"
android:text="2">
</Button>
<Button android:id="@+id/keypad_3"
android:text="3">
</Button>
</TableRow> <TableRow>
<Button android:id="@+id/keypad_4"
android:text="4">
</Button>
<Button android:id="@+id/keypad_5"
android:text="5">
</Button>
<Button android:id="@+id/keypad_6"
android:text="6">
</Button>
</TableRow> <TableRow>
<Button android:id="@+id/keypad_7"
android:text="7">
</Button>
<Button android:id="@+id/keypad_8"
android:text="8">
</Button>
<Button android:id="@+id/keypad_9"
android:text="9">
</Button>
</TableRow> <TableRow>
<Button android:text="">
</Button>
<Button android:id="@+id/back_1"
android:text="@string/back_1">
</Button>
<Button android:text="">
</Button>
</TableRow> </TableLayout>

Game.java:

 package com.soccer.shudu;

 public class Game {
//数独初始化数据
private final String str = "360000000004230800000004200"
+"070460003820000014500013020"
+"001900000007048300000000045";
private int sudoku [] = new int[9*9];
//用于存储每个单元格已经不可用的数据
private int used[][][] = new int[9][9][]; public Game(){
sudoku = fromPuzzleString(str);
calculateAllUsedTile();
}
//根据九宫格当中的坐标,返回该坐标对应的数字
private int getTile(int x,int y){
return sudoku[y*9 + x];
}
private void setTile(int x,int y,int value){
sudoku[y * 9 + x] = value;
} public String getTileString(int x, int y){
int v = getTile(x,y);
if(v == 0){ //0就不显示
return "";
}
else
return String.valueOf(v);
}
protected boolean setTileIfValid(int x,int y,int value){
int tiles[] = getUsedTileByCoor(x,y);
if(value != 0){
for(int tile : tiles){
if(tile == value)
return false;
}
}
setTile(x,y,value);
calculateAllUsedTile();
return true;
} //根据一个字符串数据生成一个整形数组,作为数独游戏的初始化数据
protected int[] fromPuzzleString(String src){
int []sudo = new int[src.length()];
for(int i = 0;i < sudo.length;i++)
{
sudo[i] = src.charAt(i) - '0';
}
return sudo;
} //计算所有单元格对应的不可用数据
public void calculateAllUsedTile(){
for(int x = 0;x < 9;x++){
for(int y = 0;y < 9;y++){
used[x][y] = calculateUsedTiles(x, y);
}
}
} //取出某一单元格当中已经不可用的数据
public int[] getUsedTileByCoor(int x,int y){
return used[x][y];
} //计算某一单元格当中已经不可用的数据
public int[] calculateUsedTiles(int x,int y){
int c[] = new int[9]; for(int i = 0;i < 9;i++){
if(i == y)
continue;
int t = getTile(x, i);
if(t != 0)
c[t - 1] = t;
} for(int i = 0;i < 9;i++){
if(i == x)
continue;
int t = getTile(i, y);
if(t != 0)
c[t - 1] = t;
} int startx = (x / 3) * 3;
int starty = (y / 3) * 3;
for(int i = startx; i < startx + 3; i++){
for(int j = starty;j < starty + 3; j++){
if(i == x && j == y)
continue;
int t = getTile(i,j);
if(t!=0)
c[t-1] = t;
}
}
//compress
int nused = 0;
for(int t:c){
if(t!=0)
nused++;
}
int c1[] = new int[nused];
nused = 0;
for(int t:c){
if(t!=0)
c1[nused++] = t;
}
return c1;
}
}

界面效果如下:

android开发——数独游戏的更多相关文章

  1. iOS开发 Swift开发数独游戏(一)

    一.前言 我姥姥是一名退休数学老师,一直很喜欢玩数独游戏.我以前答应过她要给她写一个数独游戏.本来计划是写一个Android应用的,但恰好我学了好长时间iOS开发一直没做什么"大项目&quo ...

  2. iOS开发 Swift开发数独游戏(四) 游戏界面的界面与逻辑

    一.游戏界面涉及到的功能点 1)数独格子的建模 (1)绘制数独格子要考虑到标记功能 所以要在每个格子内预先塞入9个标记数字,仅数独格子算下来就有9*9*9=729个格子且存在大量嵌套(这导致我在操作S ...

  3. iOS开发 Swift开发数独游戏(三) 选关界面

    一.选关界面涉及到的功能点 1)需要UITableView以及相应数据代理.协议的实现 2)读取plist文件并转化成模型 3)在单元格点击后进入数独游戏,涉及到把数据经segue在UIViewCon ...

  4. iOS开发 Swift开发数独游戏(二)数独题目的生成

    一.Plist文件结构设计 由于要预先生成数独题目的文件,我自然而然想到用plist存取. 我用Xcode建了几个plist文件来熟悉这种文件使用的结构后设计了如下结构: 为区分难度(后来了解到挖空数 ...

  5. iOS开发 Swift开发数独游戏(五)显示游戏答案

          要点是设置好Tag就好,通过代码找到并初始化即可. 1: // 2: // ShowAnswerController.swift 3: // sudoku-v02 4: // 5: // ...

  6. Android开发学习——游戏开发小demo

    public class MainActivity extends Activity { private GameUI gameUI; @Override protected void onCreat ...

  7. 使用Xamarin开发移动应用示例——数独游戏(一)项目的创建与调试

    最近项目中需要移动客户端,由于团队基本上使用.Net产品线,所以决定使用Xmarin进行开发,这样技术路线统一,便于后期维护.官网上是这样介绍的" Xamarin 允许你使用 .NET 代码 ...

  8. 【转】针对iOS VS. Android开发游戏的优劣——2013-08-25 17

    http://game.dapps.net/gamedev/experience/8670.html 问题:如果你正在一个新工作室开发一款新的平板/手机游戏,你会选择iOS还是Android? 回答: ...

  9. 怎样在Android开发中FPS游戏实现的两种方式比较

    怎样在Android开发中FPS游戏实现的两种方式比较 如何用Android平台开发FPS游戏,其实现过程有哪些方法,这些方法又有哪些不同的地方呢?首先让我们先了解下什么是FPS 英文名:FPS (F ...

随机推荐

  1. asp.net framework identity 学习笔记

    关于 cookie expiry & securityStamp http://www.jamessturtevant.com/posts/ASPNET-Identity-Cookie-Aut ...

  2. 研究了下apache的漏洞CVE-2012-0053

    发一个大cookie过去,最新版本的,竟然显示了个\n 嘛意思 干嘛不直接删掉 Your browser sent a request that this server could not under ...

  3. 7.3.1 Establishing a Backup Policy

    7.3 Example Backup and Recovery Strategy 备份和恢复策略实例 7.3.1 Establishing a Backup Policy 7.3.2 Using Ba ...

  4. Two Sum 解答

    Question: Given an array of integers, find two numbers such that they add up to a specific target nu ...

  5. [Java] List / ArrayList - 源代码学习笔记

    在阅读 List / ArrayList 源代码过程中,做了下面的笔记. LinkedList 的笔记较多,放到了另一篇博文 LinkedList / Queue- 源代码学习笔记 List List ...

  6. openstack theme topic

  7. Hive从概念到安装使用总结

    一.Hive的基本概念 1.1 hive是什么? (1)Hive是建立在hadoop数据仓库基础之上的一个基础架构: (2)相当于hadoop之上的一个客户端,可以用来存储.查询和分析存储在hadoo ...

  8. Hadoop集群与RAID磁盘阵列

    Hadoop集群规范 硬盘选型 尽管建议采用RAID(Redundant Array of Independent Disk,即磁盘阵列)作为NameNode的存储器以保护元数据,但是若将RAID作为 ...

  9. Linq to Sql语法及实例大全

    LINQ to SQL语句(1)之Where Where操作 适用场景:实现过滤,查询等功能. 说明:与SQL命令中的Where作用相似,都是起到范围限定也就是过滤作用的 ,而判断条件就是它后面所接的 ...

  10. Windows平台下,Scrapy Installation,安装问题解决

    按理说直接:pip install scrapy 就可以成功,但是出现了错误"libxml/xpath.h: No such file or directory" "er ...