android开发——数独游戏
最近研究了一下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开发——数独游戏的更多相关文章
- iOS开发 Swift开发数独游戏(一)
一.前言 我姥姥是一名退休数学老师,一直很喜欢玩数独游戏.我以前答应过她要给她写一个数独游戏.本来计划是写一个Android应用的,但恰好我学了好长时间iOS开发一直没做什么"大项目&quo ...
- iOS开发 Swift开发数独游戏(四) 游戏界面的界面与逻辑
一.游戏界面涉及到的功能点 1)数独格子的建模 (1)绘制数独格子要考虑到标记功能 所以要在每个格子内预先塞入9个标记数字,仅数独格子算下来就有9*9*9=729个格子且存在大量嵌套(这导致我在操作S ...
- iOS开发 Swift开发数独游戏(三) 选关界面
一.选关界面涉及到的功能点 1)需要UITableView以及相应数据代理.协议的实现 2)读取plist文件并转化成模型 3)在单元格点击后进入数独游戏,涉及到把数据经segue在UIViewCon ...
- iOS开发 Swift开发数独游戏(二)数独题目的生成
一.Plist文件结构设计 由于要预先生成数独题目的文件,我自然而然想到用plist存取. 我用Xcode建了几个plist文件来熟悉这种文件使用的结构后设计了如下结构: 为区分难度(后来了解到挖空数 ...
- iOS开发 Swift开发数独游戏(五)显示游戏答案
要点是设置好Tag就好,通过代码找到并初始化即可. 1: // 2: // ShowAnswerController.swift 3: // sudoku-v02 4: // 5: // ...
- Android开发学习——游戏开发小demo
public class MainActivity extends Activity { private GameUI gameUI; @Override protected void onCreat ...
- 使用Xamarin开发移动应用示例——数独游戏(一)项目的创建与调试
最近项目中需要移动客户端,由于团队基本上使用.Net产品线,所以决定使用Xmarin进行开发,这样技术路线统一,便于后期维护.官网上是这样介绍的" Xamarin 允许你使用 .NET 代码 ...
- 【转】针对iOS VS. Android开发游戏的优劣——2013-08-25 17
http://game.dapps.net/gamedev/experience/8670.html 问题:如果你正在一个新工作室开发一款新的平板/手机游戏,你会选择iOS还是Android? 回答: ...
- 怎样在Android开发中FPS游戏实现的两种方式比较
怎样在Android开发中FPS游戏实现的两种方式比较 如何用Android平台开发FPS游戏,其实现过程有哪些方法,这些方法又有哪些不同的地方呢?首先让我们先了解下什么是FPS 英文名:FPS (F ...
随机推荐
- OSSEC集合
http://dcid.me/blog/2010/01/using-ossec-for-the-forensic-analysis-of-log-files/
- java签名证书
import java.io.FileInputStream; import java.security.KeyStore; import java.security.PrivateKey; impo ...
- 【转】spin_lock & mutex_lock的区别? .
原文网址:http://blog.csdn.net/wilsonboliu/article/details/19190861 本文由该问题引入到内核锁的讨论,归纳如下 为什么需要内核锁? 多核处理 ...
- 线程间同步之 semaphore(信号量)
原文地址:http://www.cnblogs.com/yuqilin/archive/2011/10/16/2214429.html semaphore 可用于进程间同步也可用于同一个进程间的线程同 ...
- cannot be resolved to a type in same package 问题解决
在 STS 上,一个类引用在相同 package 中另一个类,但是报 cannot be resolved to a type 错误. 解决方法 : Alternatively, you can hi ...
- Fork 一个仓库并同步
Fork 一个示例仓库 Fork 是对一个仓库的克隆.克隆一个仓库允许你自由试验各种改变,而不影响原始的项目. 一般来说,forks 被用于去更改别人的项目(贡献代码给已经开源的项目)或者使用别人的项 ...
- 中国四大资产管理公司 ACM
一,来历和主要业务 国家于1999年成立了四家直属国务院的资产管理公司:中国东方资产管理公司.中国信达资产管理公司.中国华融资产管理公司.中国长城资产管理公司.由于资产公司一般是是为适应体制转轨或防范 ...
- jquery 随机数
var jschars = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', ...
- JVM性能调优监控工具
命令:jps.jstat.jmap.jhat.jstack 简介:(1) jmap -dump:format=b,file=eclipse.bin 10481 生成堆转储快照eclipse.bin ...
- 具体解释VB中连接access数据库的几种方法
在VB中,连接ACCESS数据库的方法主要有以下三种 使用ADO对象,通过编写代码訪问数据库 Connection 对象 ODBC数据源 使用ADO Data 控件高速创建数据库连接 有三种连接方法 ...