本文实例为大家分享了Android实现中国象棋游戏的具体代码,供大家参考,具体内容如下
实现环境: android studio 3.2.1, 手机分辨率为: 1920 * 1080
局域网 UDP 连接
分主活动类,棋类,主机类
代码如下:
清单文件要添加的权限:
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
主活动:
package chinachess;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Enumeration;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private TextView tvMyIp;
private EditText editIp;
private EditText editReceiverPort;
private EditText editSendrPort;
private Button btnConn;
private TextView tvTitle;
private TextView tvTitle2;
private TextView tvTitle3;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
private void initView() {
tvMyIp = (TextView) findViewById(R.id.tvMyIp);
editIp = (EditText) findViewById(R.id.editIp);
editReceiverPort = (EditText) findViewById(R.id.editReceiverPort);
editSendrPort = (EditText) findViewById(R.id.editSendrPort);
btnConn = (Button) findViewById(R.id.btnConn);
btnConn.setOnClickListener(this);
tvTitle = (TextView) findViewById(R.id.tvTitle);
tvTitle2 = (TextView) findViewById(R.id.tvTitle2);
tvTitle3 = (TextView) findViewById(R.id.tvTitle3);
getIp();
}
// 将用于连接的控件隐藏掉
public void uiGone() {
tvMyIp.setVisibility(View.GONE);
editIp.setVisibility(View.GONE);
editReceiverPort.setVisibility(View.GONE);
editSendrPort.setVisibility(View.GONE);
btnConn.setVisibility(View.GONE);
btnConn.setVisibility(View.GONE);
tvTitle.setVisibility(View.GONE);
tvTitle2.setVisibility(View.GONE);
tvTitle3.setVisibility(View.GONE);
}
// 获取局域网 ip 的方法
private void getIp() {
String s;
try {
for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements(); ) {
NetworkInterface face = en.nextElement();
for (Enumeration<InetAddress> enAddr = face.getInetAddresses(); enAddr.hasMoreElements(); ){
InetAddress addr = enAddr.nextElement();
if (!addr.isLoopbackAddress()) {
s = addr.getHostAddress();
// 只获取区域网 ip 地址
if ("192".equals(s.substring(0, 3))) {
tvMyIp.setText("IP: " + s);
}
}
}
}
} catch (SocketException e) {
e.printStackTrace();
}
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btnConn:
submit();
break;
}
}
private void submit() {
// validate
String ip = editIp.getText().toString().trim();
if (TextUtils.isEmpty(ip)) {
Toast.makeText(this, "IP不可为空!", Toast.LENGTH_SHORT).show();
return;
}
String receiverPort = editReceiverPort.getText().toString().trim();
if (TextUtils.isEmpty(receiverPort)) {
Toast.makeText(this, "接收端口不可为空!", Toast.LENGTH_SHORT).show();
return;
}
String sendPort = editSendrPort.getText().toString().trim();
if (TextUtils.isEmpty(sendPort)) {
Toast.makeText(this, "发送端口不可为空!", Toast.LENGTH_SHORT).show();
return;
}
// TODO validate success, do something
// 开启服务器或客户端,并添加到主活动中
ServerView server = new ServerView(this, Integer.valueOf(receiverPort), Integer.valueOf(sendPort), ip);
ViewGroup.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
addContentView(server, params);
server.startServer();
}
}
布局:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="5dp"
tools:context=".MainActivity">
<TextView
android:id="@+id/tvTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="UDP"
android:textColor="#000"
android:textSize="22dp" />
<TextView
android:id="@+id/tvMyIp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="IP"
android:textColor="#000"
android:textSize="18sp" />
<EditText
android:id="@+id/editIp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="IP"
android:text="192.168."
android:textColor="#000" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center">
<TextView
android:id="@+id/tvTitle2"
android:textSize="18sp"
android:textColor="#000"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="接收端口: " />
<EditText
android:id="@+id/editReceiverPort"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:hint="IP"
android:inputType="number"
android:text="10001"
android:textColor="#000" />
<TextView
android:id="@+id/tvTitle3"
android:textSize="18sp"
android:textColor="#000"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="发送端口: " />
<EditText
android:id="@+id/editSendrPort"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:hint="IP"
android:inputType="number"
android:text="10000"
android:textColor="#000" />
</LinearLayout>
<Button
android:id="@+id/btnConn"
android:textSize="18sp"
android:textStyle="bold"
android:textColor="#FFF5C3"
android:text="连接"
android:background="@drawable/btn_blue"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
btn_blue.xml:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<corners android:radius="5dp" />
<gradient android:startColor="#0000a1" android:centerColor="#1f6ed4"
android:angle="315"
android:endColor="#39BAE8" />
</shape>
棋类:
package chinachess;
public class Chess {
// 标记当前棋的颜色是红棋还是黑棋
public static final int BLACK = 1;
public static final int RED = 2;
// 存储当前棋子是红棋还是黑棋
private int player;
// 当前棋子的名字
private String name;
// 图片 id
private int imageId;
// 图片编号
// 0-15 红色,16-31 黑色
// 0-帅
// 1,2-士
// 3,4-相
// 5,6-马
// 7,8-车
// 9,10-炮
// 11-15-卒
// 16-黑帅
// ...
private int num;
// 当前棋在棋盘中的位置,posX 为行,posY 为列
private int posX, posY;
public Chess(int player, String name, int num) {
this.player = player;
this.name = name;
this.num = num;
// 红旗的图片 id
int[] redId = {R.drawable.shuai, R.drawable.shi, R.drawable.xiang, R.drawable.ma, R.drawable.che,
R.drawable.pao, R.drawable.bing};
// 黑旗的图片 id
int[] blackId = {R.drawable.shuai1, R.drawable.shi1, R.drawable.xiang1, R.drawable.ma1, R.drawable.che1,
R.drawable.pao1, R.drawable.bing1};
// 所有的棋的种类
String[] names = {"帅", "士", "相", "马", "车", "炮", "卒"};
// 根据当前棋的颜色来匹配不同的图片
if (player == RED) {
for (int i = 0; i < names.length; i++) {
if (names[i].equals(name)) {
imageId = redId[i];
break;
}
}
} else {
for (int i = 0; i < names.length; i++) {
if (names[i].equals(name)) {
imageId = blackId[i];
break;
}
}
}
}
// 获取棋编号
public int getNum() {
return num;
}
// 获取棋的颜色
public int getPlayer() {
return player;
}
// 获取棋名
public String getName() {
return name;
}
// 获取棋的图片id
public int getImageId() {
return imageId;
}
// 设置棋的行列坐标
public void setPos(int posX, int posY) {
this.posX = posX;
this.posY = posY;
}
// 设置棋的航坐标
public int getPosX() {
return posX;
}
// 设置棋的列坐标
public int getPosY() {
return posY;
}
// 将当前的棋坐标水平翻转
public void reverse() {
posX = 9 - posX;
}
}
主机类:
package chinachess;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;
import chinachess.Chess;
import chinachess.MainActivity;
import com.example.l_b.chinachess.R;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class ServerView extends View {
// private static final String TAG = "qaq";
// 棋的颜色
public static final int BLACK = 1;
public static final int RED = 2;
// 设置棋盘的位置,视情况而定
public static final int MARGINTOP = 150;
public static final int MARGINLEFT = 83;
// 每个格子的宽度
public static final int W = 114;
// 棋的总数
public static final int ALLCHESS = 32;
// 棋盘的行
public static final int ROW = 10;
// 棋盘的列
public static final int COL = 9;
// 没有棋的棋盘坐标的标记
public static final int NULL = -1;
// 接受消息端口
private int receiverPort;
// 发送消息端口
private int sendPort;
// 对方 ip
private String ip;
// 主活动
private MainActivity context;
// 所有的棋
private Chess[] allChess = new Chess[ALLCHESS];
// 棋盘
private int[][] map = new int[ROW][COL];
// 当前是否可以点击
private boolean canPlay;
// 判断是否移动了,只可处理点击事件
private boolean isMove;
// 设置我方的棋的颜色
private int player;
// 记录第一次选择的棋
private Chess firstSelect;
// 用于提示消息
private TextView tvTip;
// 判断当前是否赢了
private boolean isWin;
private Button btnNewGame;
// 通过构造方法将一些重要参数传入进来
public ServerView(Context context, int receiverPort, int sendPort, String ip) {
super(context);
this.receiverPort = receiverPort;
this.sendPort = sendPort;
this.ip = ip;
this.context = (MainActivity) context;
// 添加一个可以重新开始的按钮
ViewGroup.LayoutParams param = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, 120);
btnNewGame = new Button(context);
// 开始游戏后才可以点击
btnNewGame。setEnabled(false);
btnNewGame.setX(10);
btnNewGame.setY(10);
btnNewGame.setBackgroundResource(R.drawable.btn_blue);
btnNewGame.setText("重新开始");
btnNewGame.setTextColor(Color.WHITE);
btnNewGame.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// 重新开始游戏
restartGame();
sendMes("restart|");
}
});
this.context.addContentView(btnNewGame, param);
// 添加用于提示的文本框
tvTip = new TextView(context);
tvTip.setX(300);
tvTip.setY(10);
this.context.addContentView(tvTip, param);
// 初始化棋盘
initMapAndChess();
// 设置触屏事件
setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
// 若当前不可以点击则不执行点击事件
if (!canPlay) {
return false;
}
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
isMove = false;
break;
case MotionEvent.ACTION_MOVE:
// 若有滑动事件则会执行
isMove = true;
break;
case MotionEvent.ACTION_UP:
if (!isMove) {
// 获取点击的 x 坐标
int x = ((int) event.getX() - MARGINLEFT);
// 获取点击的 y 坐标
int y = ((int) event.getY() - MARGINTOP - MARGINLEFT);
// 转化为棋盘的 col 列坐标
// x % W > W / 2 ? 1 : 0 为当前的位置的求模后是否满足大于一半的宽度,
// 若大于则把它安排到下一个位置,否则不变
x = x / W + (x % W > W / 2 ? 1 : 0);
// 转化为棋盘的 row 行坐标
y = y / W + (y % W > W / 2 ? 1 : 0);
// 若超出棋盘边界则不执行
if (x < 0 || x >= COL || y < 0 || y >= ROW) {
break;
}
// 如果为第一次点击
if (firstSelect == null) {
// 若当前点击的位置是空的
if (map[y][x] == NULL) {
break;
}
// 创建一个临时变量来存储当前位置上的棋
Chess temp = allChess[map[y][x]];
// 若点击的是对方的棋
if (temp.getPlayer() != player) {
break;
}
// 存起来
firstSelect = temp;
// 更新视图
invalidate();
} else {
// 已选择第一个棋后
// 若当前位置为空棋时
if (map[y][x] == NULL) {
// 若能移动
if (canMove(y, x)) {
// 获取第一次选择的棋的编号, 范围为 0,1,2,3...31;
int pos = map[firstSelect.getPosX()][firstSelect.getPosY()];
// 将第一次选择的棋编号给第二次选择的位置
map[y][x] = pos;
// 将第一次选择的棋编号置空
map[firstSelect.getPosX()][firstSelect.getPosY()] = NULL;
// 将第一次选择的棋的位置改变为当前位置
firstSelect.setPos(y, x);
// 轮到对方下
canPlay = false;
// 将存储的第一个棋置空
firstSelect = null;
// 发送我方移动信息给客户单,“|” 为分隔符,用于分割信息,
// 最后要用 "|" 结尾,不然最后一个信息个出错
sendMes("move|" + pos + "|" + y + "|" + x + "|");
// 设置提示消息
tvTip.setText("对方下");
// 更新视图
invalidate();
}
} else {
// 若当前的位置不为空棋
// 获取当前的棋编号
int pos = map[y][x];
// 若当前的棋为我方棋时,则把第一次选择的棋替换为当前棋
if (allChess[pos].getPlayer() == player) {
firstSelect = allChess[pos];
invalidate();
} else {
// 是否可以移动
if (canMove(y, x)) {
// 将第一次选择的棋编号置空
map[firstSelect.getPosX()][firstSelect.getPosY()] = NULL;
// 将第一次选择的棋编号给第二次选择的位置
map[y][x] = firstSelect.getNum();
// 将第一次选择的棋的位置改变为当前位置
firstSelect.setPos(y, x);
// 发送我方移动信息给客户单
sendMes("move|" + firstSelect.getNum() + "|" + y + "|" + x + "|");
// 若当前吃掉的棋为帅时
if ("帅".equals(allChess[pos].getName())) {
sendMes("winner|");
tvTip.setText("我方获胜");
} else {
tvTip.setText("对方下");
}
// 将存储的第一个棋置空
firstSelect = null;
// 将吃掉得棋置空
allChess[pos] = null;
// 轮到对方下
canPlay = false;
invalidate();
}
}
}
}
}
}
return true;
}
});
}
// 判断是否可以移动
private boolean canMove(int r2, int c2) {
// 要移动的棋名
String name = firstSelect.getName();
// 存储第一次的行坐标
int r1 = firstSelect.getPosX();
// 存储第一次的列坐标
int c1 = firstSelect.getPosY();
if ("帅".equals(name)) {
// 只能直线移动
if (r1 != r2 && c1 != c2) {
return false;
}
// 判断是否可以将军
if (map[r2][c2] != NULL && "帅".equals(allChess[map[r2][c2]].getName())) {
// 保持 r1 一定小于 r2
// c1 一定等于 c2
if (r1 > r2) {
int t = r1;
r1 = r2;
r2 = t;
}
// 标记两个帅之间是否有棋子,若有,则不可以移动
boolean flag = true;
for (int i = r1 + 1; i < r2 && flag; i++) {
if (map[i][c1] != NULL) {
flag = false;
}
}
return flag;
// 只可移动一格
} else if (Math.abs(c1 - c2) != 1 && Math.abs(r2 - r1) != 1) {
return false;
}
// 只可在田字中移动
return r2 >= 7 && c2 >= 3 && c2 <= 5;
} else if ("士".equals(name)) {
// 不能直线移动
if (r1 == r2 || c1 == c2) {
return false;
}
// 只能移动一格
if (Math.abs(r1 - r2) != 1 || Math.abs(c1 - c2) != 1) {
return false;
}
// 只可在田字中移动
return r2 >= 7 && c2 >= 3 && c2 <= 5;
} else if ("相".equals(name)) {
// 不可以过河,越界
if (r2 <= 4) {
return false;
}
// 只能走田字
if (Math.abs(r1 - r2) != 2 || Math.abs(c1 - c2) != 2) {
return false;
}
// 是否被挡住了
return map[(r1 + r2) / 2][(c1 + c2) / 2] == NULL;
} else if ("马".equals(name)) {
// 只能走 日 字
if (Math.abs(r1 - r2) * Math.abs(r1 - r2) + Math.abs(c1 - c2) * Math.abs(c1 - c2) != 5) {
return false;
}
// 向下走时
if (r2 - r1 == 2) {
// 是否被挡住了
if (map[r1 + 1][c1] != NULL) {
return false;
}
// 向上走时
} else if (r2 - r1 == -2) {
if (map[r1 - 1][c1] != NULL) {
return false;
}
// 向左走时
} else if (c2 - c1 == 2) {
if (map[r1][c1 + 1] != NULL) {
return false;
}
// 向右走时
} else if (c2 - c1 == -2) {
if (map[r1][c1 - 1] != NULL) {
return false;
}
}
} else if ("车".equals(name)) {
// 只能直线移动
if (r2 != r1 && c2 != c1) {
return false;
}
// 一个临时变量
int t;
// 左右走
if (r2 == r1) {
// 确保 c1 一定 小于 c2
if (c1 > c2) {
t = c1;
c1 = c2;
c2 = t;
}
// 之间是否被挡住了
for (int i = c1 + 1; i < c2; i++) {
if (map[r1][i] != NULL) {
return false;
}
}
} else {
// 上下走
// 确保 r1 一定 小于 r2
if (r1 > r2) {
t = r1;
r1 = r2;
r2 = t;
}
for (int i = r1 + 1; i < r2; i++) {
if (map[i][c1] != NULL) {
return false;
}
}
}
} else if ("炮".equals(name)) {
// 只能走直线
if (r1 != r2 && c1 != c2) {
return false;
}
int t;
// 平常走时,跟车一样
if (map[r2][c2] == NULL) {
if (r2 == r1) {
// 确保 c1 一定在 c2 的上面
if (c1 > c2) {
t = c1;
c1 = c2;
c2 = t;
}
for (int i = c1 + 1; i < c2; i++) {
if (map[r1][i] != NULL) {
return false;
}
}
} else {
if (r1 > r2) {
t = r1;
r1 = r2;
r2 = t;
}
for (int i = r1 + 1; i < r2; i++) {
if (map[i][c1] != NULL) {
return false;
}
}
}
// 可以吃子时
} else {
// 用于记录之间有几个棋子,只能为一
int count = 0;
if (r2 == r1) {
// 确保 c1 一定在 c2 的上面
if (c1 > c2) {
t = c1;
c1 = c2;
c2 = t;
}
for (int i = c1 + 1; i < c2; i++) {
if (map[r1][i] != NULL) {
count++;
if (count > 1) {
return false;
}
}
}
} else {
if (r1 > r2) {
t = r1;
r1 = r2;
r2 = t;
}
for (int i = r1 + 1; i < r2; i++) {
if (map[i][c1] != NULL) {
count++;
if (count > 1) {
return false;
}
}
}
}
if (count != 1) {
return false;
}
}
} else if ("卒".equals(name)) {
// 只能往前走
if (r2 > r1) {
return false;
}
// 若过河了
if (r1 <= 4) {
// 只能走直线
if (r2 != r1 && c2 != c1) {
return false;
}
// 只能走一格
if (Math.abs(c1 - c2) != 1 && r1 - r2 != 1) {
return false;
}
} else {
// 若没有过河,则只能前走一格
if (c2 != c1 || r1 - r2 != 1) {
return false;
}
}
}
return true;
}
private void initMapAndChess() {
// 将编号全置空
for (int i = 0; i < ROW; i++) {
for (int j = 0; j < COL; j++) {
map[i][j] = NULL;
}
}
// 将,两士,两相,两马,两车,两炮,五卒
// 32 个棋子在地图上的 x 坐标,红棋先
// 前16个棋的 x 坐标
int[] mapX = {4, 3, 5, 2, 6, 1, 7, 0, 8, 1, 7, 0, 2, 4, 6, 8};
// 前16个棋的 y 坐标
int[] mapY = {0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 3, 3, 3, 3, 3};
// 前16个棋的棋名
String[] strings = {"帅", "士", "士", "相", "相", "马", "马", "车", "车", "炮", "炮", "卒", "卒", "卒", "卒", "卒"};
// 临时存储行和列
int row, col;
for (int i = 0; i < allChess.length; i++) {
// 小于16为红旗
if (i < 16) {
row = mapY[i];
col = mapX[i];
// 初始化棋子
allChess[i] = new Chess(RED, strings[i], i);
// 给相应的棋盘位置安排编号
map[row][col] = i;
// 设置棋子在棋盘中的初始位置
allChess[i].setPos(row, col);
} else {
row = ROW - mapY[i - 16] - 1;
col = COL - mapX[i - 16] - 1;
allChess[i] = new Chess(BLACK, strings[i - 16], i);
map[row][col] = i;
allChess[i].setPos(row, col);
}
}
// showChess();
}
// private void showChess() {
// String s;
// for (int i = 0; i < ROW; i++) {
// s = "";
// for (int j = 0; j < COL; j++) {
// s += map[i][j] + " ";
// }
// Log.d(TAG, "showChess: " + s);
// }
// for (int i = 0; i < allChess.length; i++) {
// Log.d(TAG, "showChess: " + allChess[i].getName() + "-" + allChess[i].getNum() + "-" + allChess[i].getPosX() + "-" + allChess[i].getPosY());
// }
// }
// 翻转棋盘
private void reverseMap() {
int t;
// 默认为黑下红上
// 主机为黑下红上
// 客户端为黑上红下,所以是客户端时将双方棋的位置换一下
for (int i = 0; i < ROW / 2; i++) {
for (int j = 0; j < COL; j++) {
t = map[i][j];
map[i][j] = map[ROW - i - 1][j];
map[ROW - i - 1][j] = t;
}
}
for (Chess c : allChess) {
c.reverse();
}
// showChess();
}
public void startServer() {
// 将主活动的辅助控件隐藏掉
context.uiGone();
tvTip.setText("等待连接...");
// 开启接收信息的线程
new MessageThread().start();
}
public void sendMes(final String s) {
// 发送信息,要在线程里执行(异步执行)
new Thread(new Runnable() {
@Override
public void run() {
DatagramSocket ds = null;
try {
ds = new DatagramSocket();
byte[] buffer;
buffer = s.getBytes();
InetAddress ia = InetAddress.getByName(ip);
DatagramPacket dp = new DatagramPacket(buffer, buffer.length, ia, sendPort);
ds.send(dp);
} catch (IOException e) {
e.printStackTrace();
} finally {
if (ds != null) {
ds.close();
}
}
}
}).start();
}
// 每次调用 invalidate 就会执行这个方法
@Override
protected void onDraw(Canvas canvas) {
// 画笔,用于设置线条样式
Paint paint = new Paint();
paint.setStrokeWidth(5);
paint.setStyle(Paint.Style.STROKE);
// 设置棋盘图片,宽高视手机分辨率而定
canvas.drawBitmap(getBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.bg), 1080, 1195), 0, MARGINTOP, paint);
// 画棋
for (Chess allChes : allChess) {
// 若没有被吃掉
if (allChes != null) {
// x 坐标为列坐标乘以格子的宽度然后减去一半的格子宽度,让棋子的中心对齐坐标顶点
int x = allChes.getPosY() * W + MARGINLEFT - W / 2;
int y = allChes.getPosX() * W + MARGINTOP + MARGINLEFT - W / 2;
canvas.drawBitmap(getBitmap(BitmapFactory.decodeResource(getResources(), allChes.getImageId()), W, W), x, y, paint);
}
}
// 若第一次选择了则画一个矩阵边框来显示已选中
if (firstSelect != null) {
paint.setColor(Color.RED);
int x = firstSelect.getPosY() * W + MARGINLEFT - W / 2;
int y = firstSelect.getPosX() * W + MARGINTOP + MARGINLEFT - W / 2;
// 画线
int[] posX = {x, x + W, x + W, x, x};
int[] posY = {y, y, y + W, y + W, y};
Path path = new Path();
path.moveTo(posX[0], posY[0]);
for (int i = 1; i < posX.length; i++) {
path.lineTo(posX[i], posY[i]);
}
canvas.drawPath(path, paint);
}
}
// 自定义图片宽高
private Bitmap getBitmap(Bitmap rootImg, int w, int h) {
int rW = rootImg.getWidth();
int rH = rootImg.getHeight();
Matrix matrix = new Matrix();
matrix.postScale(w * 1.0f / rW, h * 1.0f / rH);
return Bitmap.createBitmap(rootImg, 0, 0, rW, rH, matrix, true);
}
// 重新开始游戏
private void restartGame() {
// 重新初始化棋盘
initMapAndChess();
// 若是黑棋则先下
canPlay = true;
String tip = "已重新开始游戏,我下";
if (player == RED) {
reverseMap();
canPlay = false;
tip = "已重新开始游戏,对方下";
}
isWin = false;
// 给提示,在线程中更新 UI 时需转到主线程上
setTip(tip);
// 刷新视图
updateOnUI();
}
// 接受信息的线程
class MessageThread extends Thread {
@Override
public void run() {
try {
DatagramSocket ds = new DatagramSocket(receiverPort);
byte[] buffer = new byte[100];
DatagramPacket dp = new DatagramPacket(buffer, buffer.length);
// 发送加入信息
sendMes("join|");
while (true) {
ds.receive(dp);
String s = new String(buffer);
// 指定分割符分割信息
String[] array = s.split("\\|");
switch (array[0]) {
// 只有主机才会接收到
case "join":
player = BLACK;
canPlay = true;
sendMes("conn|");
setTip("我是黑棋,我下");
context.runOnUiThread(new Runnable() {
@Override
public void run() {
btnNewGame.setEnabled(true);
}
});
break;
// 只有客户端才会接收到
case "conn":
player = RED;
// 要翻转棋盘
reverseMap();
updateOnUI();
canPlay = false;
setTip("我是红棋,对方下");
context.runOnUiThread(new Runnable() {
@Override
public void run() {
btnNewGame.setEnabled(true);
}
});
break;
// 接受到了移动信息
case "move":
// 判断是否赢了,若赢了则后面的不执行
if (isWin) {
continue;
}
// 对方走的棋编号
int originalPos = Integer.valueOf(array[1]);
// 要走的行坐标
int y2 = ROW - Integer.valueOf(array[2]) - 1;
// 要走的列坐标
int x2 = Integer.valueOf(array[3]);
// 我方当前的对方要走的棋行列坐标
int y1 = allChess[originalPos].getPosX();
int x1 = allChess[originalPos].getPosY();
// 存储要走向的坐标在棋盘的编号
int movePos = map[y2][x2];
// 将原来的位置置空
map[y1][x1] = NULL;
// 要走的位置设置为对方的棋编号
map[y2][x2] = originalPos;
// 更新其坐标
allChess[originalPos].setPos(y2, x2);
// 判断要走的位置是否有棋,若有,则置空
if (movePos != NULL && allChess[movePos] != null) {
allChess[movePos] = null;
}
// 更新视图
updateOnUI();
// 我方可以下棋
canPlay = true;
setTip("我下");
break;
// 对方赢了
case "winner":
isWin = true;
whoWin();
break;
// 重新开始游戏
case "restart":
restartGame();
break;
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
// 有赢家后
private void whoWin() {
canPlay = false;
setTip("对方获胜");
}
// 更新视图
private void updateOnUI() {
context.runOnUiThread(new Runnable() {
@Override
public void run() {
invalidate();
}
});
}
// 设置提示信息
private void setTip(final String s) {
context.runOnUiThread(new Runnable() {
@Override
public void run() {
tvTip.setText(s);
}
});
}
}
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程网。