扎扎实实学基础,开开心心拆游戏。
作为android小菜鸟,qiaoidea在这里记录自己从零开始学游戏的开发旅程,欢迎关注和批评指正。
/**
* xCount x轴方向的图标数+1
*/
protected static final int xCount =10;
/**
* yCount y轴方向的图标数+1
*/
protected static final int yCount =12;
/**
* map 连连看游戏棋盘
*/
protected int[][] map = new int[xCount][yCount];
/**
* iconSize 图标大小
*/
protected int iconSize;
/**
* iconCounts 图标的数目
*/
protected int iconCounts=19;
/**
* icons 所有的图片
*/
protected Bitmap[] icons = new Bitmap[iconCounts];
/**
* path 可以连通点的路径
*/
private Point[] path = null;
/**
* selected 选中的图标
*/
protected List<Point> selected = new ArrayList<Point>();
/**
*
* 计算图标的长宽
*/
private void calIconSize()
{
DisplayMetrics dm = new DisplayMetrics();
((Activity) this.getContext()).getWindowManager()
.getDefaultDisplay().getMetrics(dm);
iconSize = dm.widthPixels/(xCount);
}
/**
*
* @param key 特定图标的标识
* @param d drawable下的资源
*/
public void loadBitmaps(int key,Drawable d){
Bitmap bitmap = Bitmap.createBitmap(iconSize,iconSize,Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
d.setBounds(0, 0, iconSize, iconSize);
d.draw(canvas);
icons[key]=bitmap;
}
/**
* 绘制棋盘的所有图标 当这个坐标内的值大于0时绘制
*/
for(int x=0;x<map.length;x+=1){
for(int y=0;y<map[x].length;y+=1){
if(map[x][y]>0){
Point p = indextoScreen(x, y);
canvas.drawBitmap(icons[map[x][y]], p.x,p.y,null);
}
}
}
/**
* 绘制选中图标,当选中时图标放大显示
*/
for(Point position:selected){
Point p = indextoScreen(position.x, position.y);
if(map[position.x][position.y] >= 1){
canvas.drawBitmap(icons[map[position.x][position.y]],
null,
new Rect(p.x-5, p.y-5, p.x + iconSize + 5, p.y + iconSize + 5), null);
}
}
/**
* 绘制连通路径,然后将路径以及两个图标清除
*/
if (path != null && path.length >= 2) {
for (int i = 0; i < path.length - 1; i++) {
Paint paint = new Paint();
paint.setColor(Color.CYAN);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(3);
Point p1 = indextoScreen(path[i].x, path[i].y);
Point p2 = indextoScreen(path[i + 1].x, path[i + 1].y);
canvas.drawLine(p1.x + iconSize / 2, p1.y + iconSize / 2,
p2.x + iconSize / 2, p2.y + iconSize / 2, paint);
}
Point p = path[0];
map[p.x][p.y] = 0;
p = path[path.length - 1];
map[p.x][p.y] = 0;
selected.clear();
path = null;
}
/**
* 工具方法
* @param x 数组中的横坐标
* @param y 数组中的纵坐标
* @return 将图标在数组中的坐标转成在屏幕上的真实坐标
*/
public Point indextoScreen(int x,int y){
return new Point(x* iconSize , y * iconSize );
}
/**
* 工具方法
* @param x 屏幕中的横坐标
* @param y 屏幕中的纵坐标
* @return 将图标在屏幕中的坐标转成在数组上的虚拟坐标
*/
public Point screenToindex(int x,int y){
int ix = x/ iconSize;
int iy = y / iconSize;
if(ix < xCount && iy <yCount){
return new Point( ix,iy);
}else{
return new Point(0,0);
}
}
//游戏状态: public static final int WIN = 1; public static final int LOSE = 2; public static final int PAUSE = 3; public static final int PLAY = 4; public static final int QUIT = 5; //帮助和重置次数: private int Help = 3; private int Refresh = 3; /** * 第一关为100秒钟的时间 */ private int totalTime = 100; private int leftTime; /** * 音乐控制 */ public static SoundPlay soundPlay; public MediaPlayer player; /** * 计时器线程 */ private RefreshTime refreshTime; private RefreshHandler refreshHandler = new RefreshHandler(); private boolean isStop; /** * 游戏交互监听接口 */ private OnTimerListener timerListener = null; private OnStateListener stateListener = null; private OnToolsChangeListener toolsChangedListener = null; //连线路径点 private List<Point> path = new ArrayList<Point>();
/** * 声音id */ public static final int ID_SOUND_CHOOSE = 0; public static final int ID_SOUND_DISAPEAR = 1; public static final int ID_SOUND_WIN = 4; public static final int ID_SOUND_LOSE = 5; public static final int ID_SOUND_REFRESH = 6; public static final int ID_SOUND_TIP = 7; public static final int ID_SOUND_ERROR = 8;
/** * 检查状态及更新 */ private static final int REFRESH_VIEW = 1; class RefreshHandler extends Handler { @Override public void handleMessage(Message msg) { super.handleMessage(msg); if (msg.what == REFRESH_VIEW) { GameView.this.invalidate(); if (win()) { setMode(WIN); soundPlay.play(ID_SOUND_WIN, 0); isStop = true; } else if (die()) { change(); } } } public void sleep(int delayTime) { this.removeMessages(0); Message message = new Message(); message.what = REFRESH_VIEW; sendMessageDelayed(message, delayTime); } } /** * 计时线程 */ class RefreshTime extends Thread { public void run() { while (leftTime >= 0 && !isStop) { timerListener.onTimer(leftTime); leftTime--; try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } if(!isStop){ setMode(LOSE); soundPlay.play(ID_SOUND_LOSE, 0); } } }
/** * 初始化map数组, * 控制y=0,1来保证相同图片成偶数出现 * change交换图片产生随机序列。 */ public void initMap() { int x = 1; int y = 0; for (int i = 1; i < xCount - 1; i++) { for (int j = 1; j < yCount - 1; j++) { map[i][j] = x; if (y == 1) { x++; y = 0; if (x == iconCounts) { x = 1; } } else { y = 1; } } } change(); } private void change() { Random random = new Random(); int tmpV, tmpX, tmpY; for (int x = 1; x < xCount - 1; x++) { for (int y = 1; y < yCount - 1; y++) { tmpX = 1 + random.nextInt(xCount - 2); tmpY = 1 + random.nextInt(yCount - 2); tmpV = map[x][y]; map[x][y] = map[tmpX][tmpY]; map[tmpX][tmpY] = tmpV; } } if (die()) { change(); } GameView.this.invalidate(); }其中,每次结束后进行检查,是否存在无法消除 die()(即有可能是成偶出现但是连接路径均大于规则要求),若存在则重新布局排列
List<Point> p1E = new ArrayList<Point>(); List<Point> p2E = new ArrayList<Point>(); private boolean link(Point p1, Point p2) { if (p1.equals(p2)) { //如果两点为同一点 return false; } path.clear(); if (map[p1.x][p1.y] == map[p2.x][p2.y]) { if (linkD(p1, p2)) { //如果两点可直连 path.add(p1); path.add(p2); return true; } /** * 检查这两个点的连线转折点p * 看p是否能与他们直连 */ Point p = new Point(p1.x, p2.y); if (map[p.x][p.y] == 0) { if (linkD(p1, p) && linkD(p, p2)) { path.add(p1); path.add(p); path.add(p2); return true; } } p = new Point(p2.x, p1.y); if (map[p.x][p.y] == 0) { if (linkD(p1, p) && linkD(p, p2)) { path.add(p1); path.add(p); path.add(p2); return true; } } /** * 检查这两个点的可延长连通点(即为空的可扩展点list1/list2) * 判断两个list上是否存在两点pt1和pt2可直连 */ expandX(p1, p1E); expandX(p2, p2E); for (Point pt1 : p1E) { for (Point pt2 : p2E) { if (pt1.x == pt2.x) { if (linkD(pt1, pt2)) { path.add(p1); path.add(pt1); path.add(pt2); path.add(p2); return true; } } } } expandY(p1, p1E); expandY(p2, p2E); for (Point pt1 : p1E) { for (Point pt2 : p2E) { if (pt1.y == pt2.y) { if (linkD(pt1, pt2)) { path.add(p1); path.add(pt1); path.add(pt2); path.add(p2); return true; } } } } return false; } return false; } //判断是否可直连 private boolean linkD(Point p1, Point p2) { if (p1.x == p2.x) { int y1 = Math.min(p1.y, p2.y); int y2 = Math.max(p1.y, p2.y); boolean flag = true; for (int y = y1 + 1; y < y2; y++) { if (map[p1.x][y] != 0) { flag = false; break; } } if (flag) { return true; } } if (p1.y == p2.y) { int x1 = Math.min(p1.x, p2.x); int x2 = Math.max(p1.x, p2.x); boolean flag = true; for (int x = x1 + 1; x < x2; x++) { if (map[x][p1.y] != 0) { flag = false; break; } } if (flag) { return true; } } return false; } //该方向上可扩展延伸的点 private void expandX(Point p, List<Point> l) { l.clear(); for (int x = p.x + 1; x < xCount; x++) { if (map[x][p.y] != 0) { break; } l.add(new Point(x, p.y)); } for (int x = p.x - 1; x >= 0; x--) { if (map[x][p.y] != 0) { break; } l.add(new Point(x, p.y)); } } private void expandY(Point p, List<Point> l) { l.clear(); for (int y = p.y + 1; y < yCount; y++) { if (map[p.x][y] != 0) { break; } l.add(new Point(p.x, y)); } for (int y = p.y - 1; y >= 0; y--) { if (map[p.x][y] != 0) { break; } l.add(new Point(p.x, y)); } }
/** * 用户点击事件 * 判断是否可点击,点击选中后声音 * 选中前后点可连通判断 */ @Override public boolean onTouchEvent(MotionEvent event) { int x = (int) event.getX(); int y = (int) event.getY(); Point p = screenToindex(x, y); if (map[p.x][p.y] > 0) { if (selected.size() == 1) { if (link(selected.get(0), p)) { selected.add(p); drawLine(path.toArray(new Point[] {})); soundPlay.play(ID_SOUND_DISAPEAR, 0); refreshHandler.sleep(500); } else { selected.clear(); selected.add(p); soundPlay.play(ID_SOUND_CHOOSE, 0); GameView.this.invalidate(); } } else { selected.add(p); soundPlay.play(ID_SOUND_CHOOSE, 0); GameView.this.invalidate(); } } return super.onTouchEvent(event); }
private boolean die() { for (int y = 1; y < yCount - 1; y++) { for (int x = 1; x < xCount - 1; x++) { if (map[x][y] != 0) { for (int j = y; j < yCount - 1; j++) { if (j == y) { for (int i = x + 1; i < xCount - 1; i++) { if (map[i][j] == map[x][y] && link(new Point(x, y), new Point(i, j))) { return false; } } } else { for (int i = 1; i < xCount - 1; i++) { if (map[i][j] == map[x][y] && link(new Point(x, y), new Point(i, j))) { return false; } } } } } } } return true; }
//自动消除 public void autoClear() { if (Help == 0) { soundPlay.play(ID_SOUND_ERROR, 0); }else{ soundPlay.play(ID_SOUND_TIP, 0); Help--; toolsChangedListener.onTipChanged(Help); drawLine(path.toArray(new Point[] {})); refreshHandler.sleep(500); } } //重置map布局 public void refreshChange(){ if(Refresh == 0){ soundPlay.play(ID_SOUND_ERROR, 0); return; }else{ soundPlay.play(ID_SOUND_REFRESH, 0); Refresh--; toolsChangedListener.onRefreshChanged(Refresh); change(); } }