数独游戏实战学习
Android自定义View学习_数独游戏实战学习
一、使用基础
1.使用画笔paint在画布canvas上画一条线
Paint paint = new Paint();
// 向画笔赋予颜色,使用color类自带的颜色
paint.setColor(Color.RED);
// 向画笔赋予颜色,使用argb方法(透明度,颜色3位参数)0-255
paint.setARGB(200,0,100,200);
// 是否打开抗锯齿参数(true:打开;false:关闭)打开效果会更好,不打开适用于像素点游戏
paint.setAntiAlias(true);
// 使用画笔paint在画布canvas上画一条起点0,200重点200,0的线
canvas.drawLine(0,200,200,0,paint);
2.使用画笔paint在画布canvas上画一个矩形
// 使用画笔paint在画布canvas上画一个距离左边界100,上边界200,宽度50,高度300的实心矩形
canvas.drawRect(100,200,50,300,paint);
3.使用画笔paint在画布canvas上画一个空心矩形
// 设置画笔画出的为空心图形
paint.setStyle(Paint.Style.STROKE);
canvas.drawRect(100,200,50,300,paint);
4.使用画笔paint在画布canvas上画一个空心矩形,并加粗边框
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(10);
canvas.drawRect(100,200,50,300,paint);
5.使用画笔paint在画布canvas上画一个圆
// 使用画笔paint在画布canvas上画一个X轴坐标300,Y轴坐标300,半径100的圆
canvas.drawCircle(300,300,100,paint);
6.使用另一支画笔paint2在画布canvas上画一个圆
// 当想要与前一个或其他图形样式不同的图形时,可以新建一个画笔对象,使用新的画笔对象画想要的图形
Paint paint2 = new Paint();
paint2.setARGB(200,1,100,200);
paint2.setAntiAlias(true);
canvas.drawCircle(300,300,100,paint2);
7.使用一支画笔paint在画布canvas上画文字图形,同时画出文字图形基准线
Paint paint = new Paint();
// 向画笔赋予颜色,使用color类自带的颜色
paint.setColor(Color.RED);
paint.setAntiAlias(true);
paint.setTextSize(50);
// 文字内容,起始X轴坐标,Y轴坐标,画笔
canvas.drawText(“iphone”,200,200,paint);
canvas.drawLine(0,200,500,200,paint);
8.使用一支画笔paint在画布canvas上绘制图形
Paint paint = new Paint();
// 向画笔赋予颜色,使用color类自带的颜色
paint.setColor(Color.RED);
paint.setAntiAlias(true);
// 指定图片,X轴起始坐标,Y轴起始坐标,画笔对象
canvas.drawBitmap(BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher),100,200,paint);
二、绘制数独游戏基础九宫格并且放入数字
// 记录单元格宽高
private float width,height;
/*设置单元格宽高*/
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
// 每个小单元格宽高均为当前屏幕的1/9
this.width = w /9f;
this.height = h /9f;
super.onSizeChanged(w, h, oldw, oldh);
}
@Override
protected void onDraw(Canvas canvas) {
// 绘制数独游戏基础九宫格并且放入数字
Paint paint_bg = new Paint();
// 绘制background颜色
paint_bg.setColor(getResources().getColor(R.color.background));
canvas.drawRect(0,0,getWidth(),getHeight(),paint_bg);
// 绘制粗线颜色
Paint paint_blackLines = new Paint();
paint_blackLines.setColor(getResources().getColor(R.color.black));
// 绘制两种不同颜色用于拼接显示单元格
Paint paint_hiliteLines = new Paint();
paint_hiliteLines.setColor(getResources().getColor(R.color.hiliteLines));
Paint paint_lightLines = new Paint();
paint_lightLines.setColor(getResources().getColor(R.color.lightLines));
for (int i = 0; i < 9; i++) {
canvas.drawLine(0,i*height,getWidth(),i*height,paint_lightLines);
canvas.drawLine(0,i*height+1,getWidth(),i*height+1,paint_hiliteLines);
canvas.drawLine(i*width,0,i*width,getHeight(),paint_lightLines);
canvas.drawLine(i*width+1,0,i*width+1,getHeight(),paint_hiliteLines);
}
// 绘制切割线,切割为9个小单元格
for (int i = 0; i < 9; i++) {
if (i%3 != 0){
continue;
}
canvas.drawLine(0,i*height,getWidth(),i*height,paint_blackLines);
canvas.drawLine(0,i*height+1,getWidth(),i*height+1,paint_blackLines);
canvas.drawLine(i*width,0,i*width,getHeight(),paint_blackLines);
canvas.drawLine(i*width+1,0,i*width+1,getHeight(),paint_blackLines);
}
// 绘制文字
Paint numberPaint = new Paint();
numberPaint.setColor(Color.BLACK);
numberPaint.setStyle(Paint.Style.STROKE);
numberPaint.setTextSize(height*0.75f);
numberPaint.setTextAlign(Paint.Align.CENTER);
float x = width/2;
canvas.drawText("1",3*width + x ,100,numberPaint);
super.onDraw(canvas);
}
1.使用FontMetrics获得真正的居中Y轴位置
Paint.FontMetrics fm = numberPaint.getFontMetrics();
float x = width/2;
// 真正的居中高度:fm.ascent(基准线到图形顶部的距离:负数) + fm.descent(基准线到图形底部的距离:正数) /2
float y = height/2 - (fm.ascent + fm.descent) / 2;
canvas.drawText("1",3*width + x ,y,numberPaint);
2.初始化数独假数据
public class Number {
//共计81位
private final String str = “123000000000456000000000078900012346547897426465487893146548745678912300000001527”;
private int[] shudu = new int[9*9];
public Number(){
shudu = fromPuzzleString(str);
}
// 根据坐标轴返回对应数字
private int getTittle(int x,int y){
return shudu[y*9 + x];
}
// 当返回的数据是0时,返回空
public String getTittleStr(int x,int y){
int value = getTittle(x,y);
if (value == 0){
return "";
}
else {
return String.valueOf(value);
}
}
// 将字符串数据拆成int数组
protected int[] fromPuzzleString(String src){
int[] shudu = new int[src.length()];
for (int i = 0; i < shudu.length; i++) {
shudu[i] = src.charAt(i) - '0';
}
return shudu;
}
}
3.将获得的假数据放入每个单元格中
Paint.FontMetrics fm = numberPaint.getFontMetrics();
float x = width/2;
float y = height/2 - (fm.ascent + fm.descent) / 2;
Number number = new Number();
// 使用冒泡循环,i:横向坐标,j:竖向坐标
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
canvas.drawText(number.getTittleStr(i,j),i*width + x ,j*height + y,numberPaint);
}
}
4.根据单元格获得不可使用的数字(横竖当前九宫格)
public class Number {
private final String str = "123000000000456000000000078900012346547897426465487893146548745678912300000001527";
private int[] shudu = new int[9*9];
// 用于存放已经不可用的数据 [X轴][Y轴][已经不可用的数据]
private int used[][][] = new int[9][9][];
public Number(){
shudu = fromPuzzleString(str);
checkAllUseTiles();
}
private int getTittle(int x,int y){
return shudu[y*9 + x];
}
public String getTittleStr(int x,int y){
int value = getTittle(x,y);
if (value == 0){
return "";
}
else {
return String.valueOf(value);
}
}
protected int[] fromPuzzleString(String src){
int[] shudu = new int[src.length()];
for (int i = 0; i < shudu.length; i++) {
shudu[i] = src.charAt(i) - '0';
}
return shudu;
}
/*计算某一单元格中已经不可用的数据*/
public int[] checkUseTiles(int x,int y){
int c[] = new int[9];
for (int i = 0; i < 9; i++) {
if (i == y){
continue;
}
int t = getTittle(x,i);
if (t != 0){
c[t-1] = t;
}
}
for (int i = 0; i < 9; i++) {
if (i == x){
continue;
}
int t = getTittle(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 = getTittle(i,j);
if (t != 0){
c[t-1] = t;
}
}
}
int nused = 0;
for (int t : c){
if (t != 0){
nused += 1;
}
}
int c1[] = new int[nused];
nused = 0;
for (int t : c){
if (t != 0){
c1[nused++] = t;
}
}
return c1;
}
/*计算所有单元格中不可用数据*/
public void checkAllUseTiles(){
for (int x = 0; x < 9; x++) {
for (int y = 0; y < 9; y++) {
used[x][y] = checkUseTiles(x,y);
}
}
}
// 取出某一单元格中不可用数据
public int[] getUsedTilesByCoor(int x,int y){
return used[x][y];
}
}
4.获取点击事件同时获取不可用数据并打印(碰撞事件)
@Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() != MotionEvent.ACTION_DOWN){
return super.onTouchEvent(event);
}
int selectedX = (int)(event.getX() / width);
int selectedY = (int)(event.getY() / height);
int used[] = number.getUsedTilesByCoor(selectedX,selectedY);
for (int i = 0; i < used.length; i++) {
System.out.println(used[i]);
}
return true;
}
4.设置弹窗提示已使用的数字有哪些(碰撞事件)
@Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() != MotionEvent.ACTION_DOWN){
return super.onTouchEvent(event);
}
int selectedX = (int)(event.getX() / width);
int selectedY = (int)(event.getY() / height);
int used[] = number.getUsedTilesByCoor(selectedX,selectedY);
StringBuffer sb = new StringBuffer();
for (int i = 0; i < used.length; i++) {
sb.append(used[i]);
}
LayoutInflater layoutInflater = LayoutInflater.from(this.getContext());
View layoutView = layoutInflater.inflate(R.layout.dialog_number,null);
TextView textView = (TextView) layoutView.findViewById(R.id.tv_number);
textView.setText(sb.toString());
AlertDialog.Builder builder = new AlertDialog.Builder(this.getContext());
builder.setView(layoutView);
AlertDialog dialog = builder.create();
dialog.show();
return true;
}
剩下的都是原生的乱七八糟的东西,就不写了
上一篇: 求多边形面积小结