Android:实现井字棋⼩游戏
井字棋实现⽅式有许多,最简单的⽅法是将9个imagView组成棋盘,然后通过⼀些逻辑设计进⾏游戏。本⽂采⽤的是⾃定义View的⽅式进⾏游戏设计,通过继承View进⾏棋盘,选中状态绘制,效果如下:
1.棋盘绘制
通过选取设置宽⾼中最⼩值作为控件宽⾼,并平均分为3段作为每⼩格的长度,在onDraw()⽅法中绘制棋盘,代码如下:
//重写onMeasure()设置宽⾼
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int size = Math.Size(widthMeasureSpec),Size(heightMeasureSpec));
setMeasuredDimension(size,size);
}
//棋盘画笔
private Paint mPaint;
@Override
protected void onDraw(Canvas canvas) {
//每⼩格长度
length = getWidth()/3;
//棋盘绘制
for(int i = 0;i < 4;i++){
canvas.drawLine(length*i,0,length*i,3*length,mPaint);
canvas.drawLine(0,length*i,length*3,length*i,mPaint);
}
}
2.选中状态绘制
为了区分选中操作的玩家,新建枚举类型:
/
/代表不同玩家(NONE⽤来表⽰平局情况获胜玩家)
public enum Player{
USER_ONE,USER_TWO,NONE
}
当玩家点击屏幕时,我们需要知道他所选的格⼦是哪⼀个,通过实现 View.OnTouchListener 接⼝进⾏监听,代码如下(其中的判断是避免滑动情况):
// down 事件坐标
private float lastX;
private float lastY;
@Override
public boolean onTouch(View v, MotionEvent event) {
float x = X();
float y = Y();
switch (Action()){
case MotionEvent.ACTION_DOWN:
lastX = x;
recycle是什么意思lastY = y;
break;
case MotionEvent.ACTION_UP:
// UP 事件坐标与 Down事件坐标距离不能太远
if(Math.abs(lastX-x)<length/2 && Math.abs(lastY-y)<length/2){
//通过UP事件坐标计算选中格⼦
calculateTouchItem(x,y);
}
break;
}
return true;
}
其中calculateTouchItem⽅法功能为计算选中格⼦,代码如下:
//被选格⼦(玩家选择前先通过此数组判断是否可选,选择后将对应格⼦值设为⾮0)
private int[] locations = new int[9];
//每个格⼦对应字母编号,将通过字母组合判断是否获胜
private String[] items = new String[9];
//玩家所选格⼦对应字母集合
private List<String> user1Selected = new ArrayList<>();
private List<String> user2Selected = new ArrayList<>();
//已选格⼦信息集合(格⼦所选玩家,格⼦中⼼点坐标)
private List<ItemInformation> mList = new ArrayList<>();
//当前回合玩家
private Player currentPlayer;
private void calculateTouchItem(float x, float y) {
//判断所在⾏列
int j = (int)x/length;
int i = (int)y/length;
//判断是否在棋盘内
if(i < 3 && j < 3){
//判断是否可选
if(locations[i*3+j] == 0){
//创建选中格⼦信息并添加到选中格⼦list中
ItemInformation itemInformation = new ItemInformation(items[i*3+j],currentPlayer,i,j);                mList.add(itemInformation);
//将格⼦设为已选状态
locations[i*3+j] = 1;
//将选中格⼦字母编号添加到当前玩家选中格⼦list中
if(currentPlayer == Player.USER_ONE){
user1Selected.add(items[i*3+j]);
}else {
user2Selected.add(items[i*3+j]);
}
//重绘
invalidate();
}
}
}
其中ItemInformation保存选中格⼦相关信息,具体如下:
//存储选中格⼦信息
private class ItemInformation{
private int i;
private int j;
//选中格⼦字母编号
private String location;
private Player player;
public ItemInformation(String location, Player player,int i,int j) {
this.location = location;
this.player = player;
this.i = i;
this.j = j;
}
public String getLocation() {
return location;
}
public Player getPlayer() {
return player;
}
public int getI() {
return i;
}
public int getJ() {
return j;
}
}
九个格⼦字母编号和数字编号如下:
A(0)B(1)C(2)
D(3)E(4)F(5)
G(6)H(7)I(8)计算好选中格⼦后调⽤invalidate()⽅法进⾏重绘,修改onDraw()⽅法,代码如下:
//是否第⼀次加载
private boolean isFirst = true;
//玩家图案对应颜⾊
private int userColorOne;
private int userColorTwo;
@Override
protected void onDraw(Canvas canvas) {
length = Math.min(getWidth(),getHeight())/3;
//棋盘绘制
for(int i = 0;i < 4;i++){
canvas.drawLine(length*i,0,length*i,3*length,mPaint);
canvas.drawLine(0,length*i,length*3,length*i,mPaint);
}
//选中格⼦绘制
if(!isFirst){
for(int i = 0;i < mList.size();i++){
switch ((i).getPlayer()){
case USER_ONE:
userPaint.setColor(userColorOne);
drawUserSelected((i));
break;
case USER_TWO:
userPaint.setColor(userColorTwo);
drawUserSelected((i));
break;
}
}
//查看游戏状态是否结束
checkStatus();
}
if(isFirst){
isFirst = false;
}
}
遍历所有选中格⼦,通过对应ItemInformation信息知道所选玩家,设置对应颜⾊,再调⽤drawUserSelected()⽅法绘制,具体代码如下:
//玩家选择图案画笔
private Paint userPaint;
//绘制选中格⼦
private void drawUserSelected(Canvas canvas, ItemInformation itemInformation) {
//计算格⼦中⼼坐标
int centerX = J() * length + length/2;
int centerY = I() * length + length/2;
userPaint.setStrokeWidth(5f);
//玩家⼀绘制 × 图案
Player() == Player.USER_ONE){
float delta = (float) Math.sqrt(0.08*length*length);
canvas.drawLine(centerX-delta,centerY-delta,centerX+delta,centerY+delta,userPaint);
canvas.drawLine(centerX+delta,centerY-delta,centerX-delta,centerY+delta,userPaint);
}else {
//玩家⼆绘制○图案
float radius =  0.4f * length;
canvas.drawCircle(centerX,centerY,radius,userPaint);
}
}