您的位置:首页 > 移动开发 > Android开发

android开发 自定义view实现黑白棋子游戏

2016-11-14 15:13 501 查看
1.最近写了个棋盘游戏,大致实现如下功能:棋盘设定(n子棋,m*m棋盘)、重玩、后退(悔棋)、前进、保存、加载保存的棋盘状态。

2.先上最终效果图:


 


3.思路:第一步先画棋盘

int width = getWidth();
int height = getHeight();
mChildWidth = width / Max;
mChildHeight = height / Max;

//竖
for (int i = 1; i < Max; i++) {
canvas.drawLine(mChildWidth * i, 0, mChildWidth * i, height, mLinePaint);
}
//横
for (int i = 1; i < Max; i++) {
canvas.drawLine(0, mChildHeight * i, width, mChildHeight * i, mLinePaint);
}

第二步,画黑白棋子,此时必须监听onTouch事件,将棋手所点的坐标转化为二维数组(比如第一行第一列即为0,0位置。。。以此类推)

/**
* 获取下棋子的位置(数组下标)
*
* @param event
*/
private Point getPoint(MotionEvent event) {
float fx = event.getX();
float fy = event.getY();
int x = 0, y = 0;
for (int i = 0; i < Max; i++) {
if (fx < mChildWidth * (i + 1)) {
x = i;
break;
}
}
for (int i = 0; i < Max; i++) {
if (fy < mChildHeight * (i + 1)) {
y = i;
break;
}
}

Point point = new Point(x, y);
return point;
}


/**
* 获取下棋子的位置(坐标)
*
* @param point
*/
private Position getPosition(Point point) {
float x = 0, y = 0;

for (int i = 0; i < Max; i++) {
if (point.getX() == i) {
x = i * mChildWidth + mChildWidth / 2;
}
}

for (int i = 0; i < Max; i++) {
if (point.getY() == i) {
y = i * mChildHeight + mChildHeight / 2;
}
}
Position position = null;
if (mChessPieces == -1) {
position = new Position(x, y, Color.BLACK, mChessPieces, point);
} else {
position = new Position(x, y, Color.WHITE, mChessPieces, point);
}

return position;
}


public class Point implements Serializable {
public int x;
public int y;

public Point(int x, int y) {
this.x = x;
this.y = y;
}

public int getX() {
return x;
}

public Point setX(int x) {
this.x = x;
return this;
}

public int getY() {
return y;
}

public Point setY(int y) {
this.y = y;
return this;
}

// @Override
// public int hashCode() {
//    return x + y;
// }

@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
Point other = (Point) obj;
if (x != other.x)
return false;
if (y != other.y)
return false;
return true;
}

}


@Override
public boolean onTouchEvent(MotionEvent event) {
if (canTouch && event.getAction() == MotionEvent.ACTION_DOWN) {
mPositionUndoList.clear();//一旦重新下棋子,不能redo
Point point = getPoint(event);
if (mScore[point.getY()][point.getX()].getScore() == 0) {
Position position = getPosition(point);
mPositionList.add(position);
mScore[point.getY()][point.getX()] = position;
if (mChessPieces == -1) {
mBlackPositionList.add(position);
calculator(mBlackPositionList, "黑子");
} else if (mChessPieces == 1) {
mWhitePositionList.add(position);
calculator(mWhitePositionList, "白子");
}
postInvalidate();
exchangeChess();
event.setAction(MotionEvent.ACTION_CANCEL);
} else {
//有棋子
onResultListener.onError("当前位置有棋子,换个位置!");
}
}

return super.onTouchEvent(event);
}

/**
* 换棋手
*/
private void exchangeChess() {
if (mChessPieces == -1) {
mChessPieces = 1;
mCirclePaint.setColor(Color.WHITE);
if (onCurrentColorListener != null)
onCurrentColorListener.onCurrentColor("白子");
} else {
mChessPieces = -1;
mCirclePaint.setColor(Color.BLACK);
if (onCurrentColorListener != null)
onCurrentColorListener.onCurrentColor("黑子");
}
}


第三步,也就是本游戏的核心,计算输赢的算法。基本思想就是每次棋手下棋子后,就去计算横、竖、斜杠、反斜杠四个方向同一颜色的棋子的个数是否到达n子棋,若到达,即为相应的棋手方获胜,反之继续,直至棋子总数==棋盘m*m数时,平手。

/**
* 计算输赢
*/
private void calculator(List<Position> myChessPosition, String color) {
mSuccessPointList.clear();
if (myChessPosition.size() < COUNT) {
return;
}
if (color.equals("黑子")) {
mColor = Color.BLACK;
} else {
mColor = Color.WHITE;
}
List<Point> myPointList = new ArrayList<>();
Point temPoint = new Point(0, 0);
for (int i = 0; i < myChessPosition.size(); i++) {
myPointList.add(myChessPosition.get(i).getPoint());
}
int count = 0;
Point point = myPointList.get(myPointList.size() - 1);//获取最后下的棋子的位置
int x = point.getX();
int y = point.getY();
temPoint.setX(x).setY(y);
//横
while (myPointList.contains(temPoint)) {
mSuccessPointList.add(new Point(temPoint.getX(), temPoint.getY()));
count++;
int tempX = temPoint.getX();
if (!(tempX < Max) || count >= COUNT) {
break;
}
temPoint.setX(tempX + 1);
}
if (count == COUNT) {
resultMsg = "本局结束," + color + "胜!!!";
new Thread(new CircleThread()).start();
return;
}
temPoint.setX(x).setY(y);
mSuccessPointList.remove(0);
count--;//重复算了x,y这点
while (myPointList.contains(temPoint)) {
mSuccessPointList.add(new Point(temPoint.getX(), temPoint.getY()));
count++;
int tempX = temPoint.getX();
if (tempX < 1 || count >= COUNT) {
break;
}
temPoint.setX(tempX - 1);
}
if (count == COUNT) {
resultMsg = "本局结束," + color + "胜!!!";
new Thread(new CircleThread()).start();
return;
}
//竖
mSuccessPointList.clear();
count = 0;
temPoint.setX(x).setY(y);
while (myPointList.contains(temPoint)) {
mSuccessPointList.add(new Point(temPoint.getX(), temPoint.getY()));
count++;
int tempY = temPoint.getY();
Log.d("+", "count=" + count + ",tempY=" + tempY);
if (!(tempY < Max) || count >= COUNT) {
break;
}
temPoint.setY(tempY + 1);
}
if (count == COUNT) {
resultMsg = "本局结束," + color + "胜!!!";
new Thread(new CircleThread()).start();
return;
}
mSuccessPointList.remove(0);
temPoint.setX(x).setY(y);
count--;//重复算了x,y这点
while (myPointList.contains(temPoint)) {
mSuccessPointList.add(new Point(temPoint.getX(), temPoint.getY()));
count++;
int tempY = temPoint.getY();
Log.d("-", "count=" + count + ",tempY=" + tempY);
if (tempY < 1 || count >= COUNT) {
break;
}
temPoint.setY(tempY - 1);
}
if (count == COUNT) {
resultMsg = "本局结束," + color + "胜!!!";
new Thread(new CircleThread()).start();
return;
}
//正斜向 /
mSuccessPointList.clear();
count = 0;
temPoint.setX(x).setY(y);
while (myPointList.contains(temPoint)) {
mSuccessPointList.add(new Point(temPoint.getX(), temPoint.getY()));
count++;
int tempX = temPoint.getX();
int tempY = temPoint.getY();
Log.d("+", "count=" + count + ",tempY=" + tempY);
if (tempY < 1 || !(tempX < Max) || count >= COUNT) {
break;
}
temPoint.setX(tempX + 1).setY(tempY - 1);
}
if (count == COUNT) {
resultMsg = "本局结束," + color + "胜!!!";
new Thread(new CircleThread()).start();
return;
}
mSuccessPointList.remove(0);
temPoint.setX(x).setY(y);
count--;
while (myPointList.contains(temPoint)) {
mSuccessPointList.add(new Point(temPoint.getX(), temPoint.getY()));
count++;
int tempX = temPoint.getX();
int tempY = temPoint.getY();
Log.d("+", "count=" + count + ",tempY=" + tempY);
if (tempX < 1 || !(tempY < Max) || count >= COUNT) {
break;
}
temPoint.setX(tempX - 1).setY(tempY + 1);
}
if (count == COUNT) {
resultMsg = "本局结束," + color + "胜!!!";
new Thread(new CircleThread()).start();
return;
}
//反斜向 \
mSuccessPointList.clear();
count = 0;
temPoint.setX(x).setY(y);
while (myPointList.contains(temPoint)) {
mSuccessPointList.add(new Point(temPoint.getX(), temPoint.getY()));
count++;
int tempX = temPoint.getX();
int tempY = temPoint.getY();
Log.d("+", "count=" + count + ",tempY=" + tempY);
if (!(tempY < Max) || !(tempX < Max) || count >= COUNT) {
break;
}
temPoint.setX(tempX + 1).setY(tempY + 1);
}
if (count == COUNT) {
resultMsg = "本局结束," + color + "胜!!!";
new Thread(new CircleThread()).start();
return;
}
mSuccessPointList.remove(0);
temPoint.setX(x).setY(y);
count--;
while (myPointList.contains(temPoint)) {
mSuccessPointList.add(new Point(temPoint.getX(), temPoint.getY()));
count++;
int tempX = temPoint.getX();
int tempY = temPoint.getY();
Log.d("+", "count=" + count + ",tempY=" + tempY);
if (tempX < 1 || tempY < 1 || count >= COUNT) {
break;
}
temPoint.setX(tempX - 1).setY(tempY - 1);
}
if (count == COUNT) {
resultMsg = "本局结束," + color + "胜!!!";
new Thread(new CircleThread()).start();
return;
}
if (mPositionList.size() == Max * Max) {
resultMsg = "本局结束,平局!!!";
mSuccessPointList.clear();
onResultListener.onComplete(resultMsg);
}
}


第四步,就是判断胜负出结果后,棋子闪动动画,这里用的是改变圆半径,通过线程控制重绘次数的方法。

private Handler circleHandler = new Handler() {

public void handleMessage(Message msg) {
super.handleMessage(msg);
if (msg.what == 1) {
canTouch = false;
mCircleSize = (Integer) msg.obj;//圆半径
invalidate();//重新绘制
} else if (msg.what == 2) {
onResultListener.onComplete(resultMsg);
}
}
};

private class CircleThread implements Runnable {

@Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
try {
Thread.sleep(200);
m++;
Message msg = new Message();
if (m > 6) {
msg.what = 2;
circleHandler.sendMessage(msg);
return;
}
msg.what = 1;
if (m % 2 == 0) {
msg.obj = 45;
} else {
msg.obj = 40;
}

circleHandler.sendMessage(msg);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

}
}


第五步,如前进、后退(悔棋)、重玩功能,重点是通过List的增删等动作,思路清晰的话应该不难。

private ArrayList<Position> mPositionList = new ArrayList<>();//棋盘共下的子
private ArrayList<Position> mBlackPositionList = new ArrayList<>();//棋盘下的黑子
private ArrayList<Position> mWhitePositionList = new ArrayList<>();//棋盘共下的白子
private ArrayList<Position> mPositionUndoList = new ArrayList<>();//存储悔棋的步骤
// private ArrayList<Position> mSuccessPositionList = new ArrayList<>();
private ArrayList<Point> mSuccessPointList = new ArrayList<>();


上面就是为了实现如上功能所设置的List,虽然有点多。。。

第六步,保存棋盘及加载棋盘状态,利用就是将序列化后的相关数据保存到外存,当需要时再由外存读入。重绘保存的数据信息,即可重现保存棋盘的模样。

/**
* 保存棋盘
*/
public void save() {
if (mPositionList.size() == 0) {
return;
}
Map<String, Object> map = new HashMap<>();
map.put("mScore", mScore);
map.put("mPositionList", mPositionList);
map.put("mBlackPositionList", mBlackPositionList);
map.put("mWhitePositionList", mWhitePositionList);

File filePath = new File(BaseApplication.instance.getCacheDir(), "gameTTT");
FileSaveHandler.saveObject(filePath.getPath(), map);

reset();
}

/**
* 加载保存的棋盘
*/
public void load() {
File filePath = new File(BaseApplication.instance.getCacheDir(), "gameTTT");
Map<String, Object> map = (Map<String, Object>) FileSaveHandler.readObject(filePath.getPath());

mScore = (Position[][]) map.get("mScore");
mPositionList = (ArrayList<Position>) map.get("mPositionList");
mBlackPositionList = (ArrayList<Position>) map.get("mBlackPositionList");
mWhitePositionList = (ArrayList<Position>) map.get("mWhitePositionList");

if (mPositionList.size() == 0) {
return;
}
Position position = mPositionList.get(mPositionList.size() - 1);
if (position.getColor() == Color.WHITE) {
calculator(mWhitePositionList, "白子");
} else {
calculator(mBlackPositionList, "黑子");
}
postInvalidate();
}


最后,已上传代码至github。https://github.com/Selina592732122/GameTTT
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐