移动平台开发综合实践 安卓android大作业-雷net在线对战

news/2024/10/3 10:34:20

转自我的安卓课程作业
图片应该是没了,懒得搞了

目录
  • 移动平台开发综合实践 大作业-雷net在线对战
    • 一、实验目的
    • 二、实验环境
    • 三、实验内容与实验要求
      • 3.1实验内容:雷net在线对战
        • 3.1.1棋盘
        • 3.1.2棋子
        • 3.1.3终端卡
      • 3.2原理分析
      • 3.3具体实验要求
    • 四、实验过程与分析
      • 4.1实验记录
        • 4.1.1 Socket连接
        • 4.1.2初始化和Chess类
        • 4.1.3回合
        • 4.1.4技能
        • 4.1.5点击逻辑
      • 4.2运行结果
        • 运行视频
      • 4.3发生的故障和问题

移动平台开发综合实践 大作业-雷net在线对战

img

一、实验目的

完成雷net在线对战的开发

一切都是命运石之门的选择

• 用户界面设计:

  • 使用Android Studio中的布局编辑器设计游戏客户端的用户界面。
  • 熟悉常见的布局管理器(如LinearLayout、RelativeLayout、ConstraintLayout等)。
  • 使用自定义View或SurfaceView实现游戏画面的绘制和交互。

• 多媒体和图形处理:

  • 加载和显示游戏资源,如图像、音频等。
  • 使用Android提供的多媒体类库(如MediaPlayer)管理游戏中的音效和背景音乐。
  • 使用Canvas绘制游戏中的复杂图形和动画效果。

• 网络通信:

  • 使用Java中的Socket编程实现客户端与服务器的通信。
  • 处理网络请求和响应,包括数据的发送、接收和解析。

• 并发和多线程编程:

  • 使用Thread等机制处理后台任务和异步操作。
  • 确保在主线程以外的任务不会阻塞UI线程。

• 用户输入和事件处理:

  • 处理触摸事件和用户输入,实现游戏中的交互操作。
  • setOnTouchListener(new OnTouchListener(){
    @Override
    public boolean onTouch(View v, MotionEvent event) {…

• 游戏逻辑和状态管理:

  • 设计和实现游戏的规则和逻辑,包括游戏的状态转换、动作解析和胜负判定。
  • 管理游戏中的各种状态和数据,确保游戏运行的一致性和正确性。

二、实验环境

实验所使用的设备名称及规格,网络管理工具简介、版本等。

  • 设备名称:华硕天选4
  • 软件工具:android studio lguana 2023
  • 运行设备:

img

三、实验内容与实验要求

3.1实验内容:雷net在线对战

什么是雷net?
雷net是命运石之门游戏及动画中架空的桌游,但是实际上真的存在,是一个心理博弈类的暗棋。下面介绍一下雷net:

3.1.1棋盘

雷net的棋盘为8×8的正方形组成。

img

棋盘分为普通格子与exit(其实叫入口可能更合适)玩家可以在靠近自己一侧的普通格子上随意摆放棋子(不可以在入口上放)
棋子可以在对方exit格子上或者经过exit格子都可以突破棋盘的边界进入对方的server区域,此时棋子重新回到自己手上,其作用到胜利条件再说。

3.1.2棋子

在雷net中有两种棋子,分别为link(链接)与virus(病毒),后简称l与v。每个棋子正常情况下只能一次走一格(不包括斜着走)。

img

这两种棋子可以在规定范围内随意摆放,比如这样:

img

这个游戏的胜利条件非常单纯:

吃掉对方link数量+进入对方server的link数量=4,胜利

吃virus+进virus=4,失败(一般不会把自己virus进对面server里)

3.1.3终端卡

终端卡类似于装备和技能的合称,一共有4种(原作)分别为:link boost、Firewall、virus cherker与404 not found。

1、link boost

img

link boost可以说是雷net中最核心的技能,它的效果朴实无华,就是让你的一个棋子可以一次走两格,或者可以斜着走一格(本质上是拐弯走两格)
一局游戏只有一个,但可以循环使用,可以看做装备。给一个棋子装上花费一回合,卸下了也花费一回合。如果装有link boost的棋子被吃了,link boost则会回到自己手上,可以在自己回合再次使用。

2、firewall

img

Firewall,防火墙,可以放在任何一个没有棋子的普通格子上(在新版中可以放在任何一个没有对方棋子的普通格子上,且自己棋子可以进入),然后谁都无法进入或结果此格子

与boost一样,一局游戏只有一个,但可以循环使用,可以看做装备。给一个普通格子装上花费一回合,卸下了也花费一回合。

3、virus cherker
virus cherker,使对方一个棋子翻面,从而能知道是virus还是link。

img

一次性技能,使用花费一个回合。

4、404 not found

img

404 not found 简称404,可以自己场上两个棋子交换或者不交换位置(不交换也同样使用404,且会有404动画,主要起一个迷惑作用)若这两个棋子中有翻面的棋子,则重新盖好。
一次性技能,使用花费一个回合。

3.2原理分析

Socket:
首先要对战的话,就要web连接一下,这次我选socket内网连接,比较简单方便,也是我们课程学习过的内容。Server一个机子,client一个机子,然后进行通信,两边都有一个棋盘,棋子都是单独的,然后我这边进行一个操作,需要对面看到的时候,就传消息给对面,对面同步一下即可。

初始化和Chess类:
棋盘需要初始化一下,列好八个棋子的初始位置,然后让玩家决定是link还是virus,棋子使用一个chess类统一管理一下。刚开始就是决定自己的link和virus,都是四个,并且要等待对面的选择完毕,才能开始游戏。注意自己是看不见对面的选择的,就是自己安排好了,看对面还是一片空白的。

回合逻辑:
每个棋子都是横竖走一格,轮流下。然后技能也占用一回合,这是回合制。注意下棋是要监听触屏动作的,要定位一下触屏的地方,然后标注一下代表选中了,保存第一个操作,点第二下棋子才进行移动。注意我这边移动棋子那边也要看得见,所以需要通信同步。然后最重要的棋盘里面需要坐标定位,棋盘布置好之后,用绝对位置太麻烦了,就是数格子的相对位置就行。标注格子里有没有棋子什么的就是要用一个数组去存。

技能逻辑:
使用技能的话,就是第一个是boost,改变棋子的移动方式,这个需要标注出来,自己和对面都能看见是哪个棋子有boost。第二个是check,本来看不见对面棋子是link还是virus的,check一下就能看见了,就是加载一下对面棋子的图片。第三个是firewall,就是设置一个格子不让棋子进来,这个if一下就行。第四个是notfound,就是选择是否交换自己的两个棋子,可以交换也可以不交换,但是对面不知道你到底换没换,还要注意本来被check的棋子交换之后也是看不见了的。

其他优化:
另外就是放个音乐,加强游戏氛围。

3.3具体实验要求

写个像这个一样的:雷net Access Battle
(我本来想抄一下的,但是他这个用cocos搞的,和安卓基本上没啥关系,只能自己写了一个,刚开始看了看csdn上一个象棋对战的代码,非常有用。)

四、实验过程与分析

4.1实验记录

4.1.1 Socket连接

写的界面就是this:

img

主要是让mainactivity去管理一下server和client的连接。

img

按钮逻辑,一个sever一个client。
// 根据按钮来判断作为主机还是客户端
final ViewGroup.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
serverBtn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {ServerView serverView = new ServerView(MainActivity.this, ip, MainActivity.this);addContentView(serverView, params);serverView.startConn();// 将当前控件隐藏掉viewGone();}
});
clientBtn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {if (ipText.getText().toString().isEmpty()) {Toast.makeText(MainActivity.this, "IP 不能为空!", Toast.LENGTH_SHORT).show();return;}ClientView clientView = new ClientView(MainActivity.this, ipText.getText().toString(), ip, MainActivity.this);addContentView(clientView, params);clientView.startJoin();// 将当前控件隐藏掉viewGone();}
});
然后server里写启动服务器:
// 开启服务器
public void startConn() {// 只能在线程(异步)中执行 172.30.4.74new Timer().schedule(new TimerTask() {@Overridepublic void run() {try {serverSocket = new ServerSocket(port);// 获取客户端信息,若无客户端连接则会一直暂停在这socket = serverSocket.accept();setTip("连接成功!");// 发送已连接给客户端sendMes("conn|");// 开启接受消息的线程new MessageThread().start();// 更新视图updateOnUI();} catch (IOException e) {e.printStackTrace();}}}, 0);
}
Client里写连接:
public void startJoin() {new Timer().schedule(new TimerTask() {@Overridepublic void run() {try {socket = new Socket(ip, port);setTip("已连接");// 存储当前输入的 ipmainActivity.setMyIp();sendMes("join|");new MessageThread().start();} catch (IOException e) {e.printStackTrace();}}}, 0);
}
想要通信的话,创建线程,两边都一样:
// 接受信息的线程
class MessageThread extends Thread {@Overridepublic void run() {BufferedReader br = null;InputStreamReader isr = null;try {String t;while (true) {isr = new InputStreamReader(socket.getInputStream());br = new BufferedReader(isr);if (br.ready()) {String cmd = br.readLine();String[] array = cmd.split("\\|");switch (array[0]) {
然后有发信息的函数,两边都一样:
private void sendMes(final String s) {new Thread(new Runnable() {@Overridepublic void run() {try {pw = new PrintWriter(socket.getOutputStream());pw.println(s);pw.flush();} catch (IOException e) {e.printStackTrace();}}}).start();
}

4.1.2初始化和Chess类

这个主要是改的象棋棋盘。

初始化代码,主要是列一下棋子,然后标注一下位置和哪一边的。

private void initMapAndChess() {// 将编号全置空for (int i = 0; i < ROW; i++) {for (int j = 0; j < COL; j++) {map[i][j] = NULL;}}// 16 个棋子在地图上的 x 坐标,红棋先// 前8个棋的 x 坐标int[] mapX = {0, 1, 2, 3, 4, 5, 6, 7};// 前8个棋的 y 坐标int[] mapY = {0, 0, 0, 1, 1, 0, 0, 0};// 前8个棋的棋名String[] strings = {"none", "none", "none", "none", "none", "none", "none", "none","none", "none", "none", "none", "none", "none", "none", "none"};// 临时存储行和列int row, col;for (int i = 0; i < allChess.length; i++) {// 小于8为红旗if (i < 8) {row = mapY[i];col = mapX[i];// 初始化棋子allChess[i] = new Chess(BLACK, strings[i], i);// 给相应的棋盘位置安排编号map[row][col] = i;// 设置棋子在棋盘中的初始位置allChess[i].setPos(row, col);} else {row = ROW - mapY[i - 8] - 1;col = COL - mapX[i - 8] - 1;allChess[i] = new Chess(RED, strings[i - 8], i);map[row][col] = i;allChess[i].setPos(row, col);}}}

要画一下棋盘和棋子,还有技能什么的,这里用canvas画:

// 每次调用 updateOnUI 就会执行这个方法
@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.header), 1080, 350), 0, 0, paint);canvas.drawBitmap(getBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.qipan1), 1080, 1285), 0, MARGINTOP, paint);canvas.drawBitmap(getBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.boost2), W, W), MARGINLEFT+2*W, 1825, paint);canvas.drawBitmap(getBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.check2), W, W), MARGINLEFT+3*W, 1825, paint);canvas.drawBitmap(getBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.wall2), W, W), MARGINLEFT+4*W, 1825, paint);canvas.drawBitmap(getBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.notfound2), W, W), MARGINLEFT+5*W, 1825, paint);// 画棋
for (Chess allChes : allChess) {// 若没有被吃掉if (allChes != null) {// x 坐标为列坐标乘以格子的宽度然后减去一半的格子宽度,让棋子的中心对齐坐标顶点int x = allChes.getPosY() * W + MARGINLEFT;int y = allChes.getPosX() * W + MARGINTOP + MARGINLEFT + 100;canvas.drawBitmap(getBitmap(BitmapFactory.decodeResource(getResources(), allChes.getImageId()), W, W), x, y, paint);Paint paint_x = new Paint();paint_x.setAlpha(150);if(allChes.getBoost()!=0){canvas.drawBitmap(getBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.boost), W, W), x, y, paint_x);}if(allChes.getCheck()!=0){canvas.drawBitmap(getBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.check), W, W), x, y, paint_x);}if(allChes.getnotfound()!=0){canvas.drawBitmap(getBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.notfound), W, W), x, y, paint_x);}}
}

这个效果:

img

4.1.3回合

回合制的逻辑就是两边都有一个canplay参数,自己下完了就canplay=false,对面棋子移动了或者用技能了,就是发信息给这边,这边canplay=true。
简要代码逻辑:

我:

// 若能移动
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 + "|");// 设置提示消息setTip("对方下");// 更新视图updateOnUI();
}

对面:

// 接受到了移动信息
case "move":// 对方走的棋编号int originalPos = Integer.valueOf(array[1])-8;// 要走的行坐标int y2 = ROW - Integer.valueOf(array[2]) - 1;// 要走的列坐标int x2 = COL - Integer.valueOf(array[3]) - 1;// 我方当前的对方要走的棋行列坐标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;}// 我方可以下棋canPlay = true;setTip("我下");whoWin();updateOnUI();break;

要是进行吃的操作,还要更新记分牌(代码略)

img

if (allChess[pos].getName().equals("link")) {eat_link2 += 1;} else if (allChess[pos].getName().equals("virus")) {eat_virus2 += 1;}if(allChess[pos].getBoost()==1){boost_num2=-1;}newdatatip();sendMes("eat|" + firstSelect.getNum() + "|" + y + "|" + x + "|"+ eat_link1 + "|" + eat_link2 + "|" +eat_virus1 + "|" + eat_virus2 + "|");updateOnUI();

4.1.4技能

Boost,给个boost_num标记一下:

img


if (map[y][x] != NULL && map[y][x]!=-2 && map[y][x]!=-3) {// 获取当前的棋编号int pos = map[y][x];// 若当前的棋为我方棋时if (allChess[pos].getPlayer() == player) {skill = 0;if(boost_num!=0){allChess[boost_num].setBoost(0);}allChess[pos].setBoost(1);boost_num=pos;// 轮到对方下canPlay = false;sendMes("boost|"+ pos + "|" + y + "|" + x + "|");}
}

Check,显示一下对面的图片:

img

if (map[y][x] != NULL && map[y][x]!=-2 && map[y][x]!=-3) {// 获取当前的棋编号int pos = map[y][x];// 若当前的棋为敌方棋时if (allChess[pos].getPlayer() != player) {allChess[pos].showimage();allChess[pos].setCheck(1);skill = 0;check_chance=false;// 轮到对方下canPlay = false;sendMes("check|"+ pos+"|");}
}

Firewall,地图数组标记一下不能走了:

img

if(map[y][x] != NULL && map[y][x] != -2){setTip("有子,不能使用firewall");updateOnUI();break;
}
else if (wall_chance==true && map[y][x] == NULL) {map[y][x]=-2;skill = 0;wall_chance=false;setTip("使用firewall");sendMes("wall|"+ pos + "|" + y + "|" + x + "|"+0+"|");// 轮到对方下canPlay = false;
}
else if(wall_chance==false && map[y][x]==-2){map[y][x]=NULL;skill = 0;wall_chance=true;setTip("取消使用firewall");sendMes("wall|"+ pos + "|" + y + "|" + x + "|"+1+"|");// 轮到对方下canPlay = false;
}
updateOnUI();

Notfound,替换两个棋子,注意地图数组和allchess都得换一下,但是boost是不换的,然后check得消除掉。

img

另外这里需要一个弹窗来选择到底换不换:

img

if (map[y][x] != NULL && map[y][x]!=-2 && map[y][x]!=-3) {// 获取当前的棋编号int posn = map[y][x];// 若当前的棋为我方棋时,则把第一次选择的棋替换为当前棋if(posn==map[firstSelect.getPosX()][firstSelect.getPosY()]){firstSelect=null;updateOnUI();} else if (allChess[posn].getPlayer() == player) {// 获取第一次选择的棋的编号, 范围为 0,1,2,3...31;int posnn = map[firstSelect.getPosX()][firstSelect.getPosY()];int ynn = firstSelect.getPosX();int xnn = firstSelect.getPosY();int yn = allChess[posn].getPosX();int xn = allChess[posn].getPosY();allChess[posn].benotfound();allChess[posnn].benotfound();allChess[posn].setCheck(0);allChess[posnn].setCheck(0);updateOnUI();//选择换还是不换AlertDialog.Builder builder = new AlertDialog.Builder(context);builder.setTitle("选择一项");builder.setItems(new CharSequence[]{"交换", "不交换"}, new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {switch (which) {case 0:Log.d("server", "换");map[ynn][xnn] = posn;map[yn][xn] = posnn;allChess[posn].setPos(ynn, xnn);allChess[posnn].setPos(yn, xn);if(allChess[posn].getBoost()==1){allChess[posn].setBoost(0);allChess[posnn].setBoost(1);}if(allChess[posnn].getBoost()==1){allChess[posnn].setBoost(0);allChess[posn].setBoost(1);}notfound_chance = false;canPlay = false;// 将存储的第一个棋置空firstSelect = null;skill = 0;sendMes("notfound|" + posn + "|" + posnn + "|");updateOnUI();break;case 1:Log.d("server", "不换");notfound_chance = false;canPlay = false;// 将存储的第一个棋置空firstSelect = null;skill = 0;sendMes("nonotfound|" + posn + "|" + posnn + "|");updateOnUI();break;}}});AlertDialog dialog = builder.create();dialog.show();updateOnUI();}

4.1.5点击逻辑

点击逻辑巨烦。要考虑第一次点击,第二次点击。第一次点如果是棋子,标注并且记录保存一下,第二次如果是一个可以走的格子,那就进行move。如果说你点了一下还想换个棋子或者你忽然想用技能了,还要清空一下保存的第一次点击,然后重新进入整个流程。
这里就简单列一下分支,内容太多了。

img

// 设置触屏事件
setOnTouchListener(new OnTouchListener(){
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
isMove = false;
break;
case MotionEvent.ACTION_UP:
if (!isMove) {
// 获取点击的 x 坐标
int x = ((int) event.getX() - MARGINLEFT);
// 获取点击的 y 坐标
int y = ((int) event.getY() - MARGINTOP - MARGINLEFT - 100);
// 转化为棋盘的 col 列坐标
x = x / W;
// 转化为棋盘的 row 行坐标
y = y / W;
// 如果还没选择完link virus
if (!choice_finish)
{这里就是选棋子,你选完这个choice_finish才会变true,进入下一个环节}
// 若当前不可以点击则不执行点击事件
else if (!canPlay) {
return false;
} else {//第一次点击
可能点的是棋子也可以是技能,这里需要根据点击的位置进行一个判断,点棋子的话要保存一下第一次点击。要是点了别的空白区域就不响应。
而且notfound技能交换的时候,这个比较特殊需要点三下的,所以就让它头一次进来是这里,第二次进来就是选棋子进来也是这里,相当于第二次选棋子也作为了第一次点击。

}
//第二次点击
else {
//若第一次选择了技能
if (skill != 0) {这里switch,执行一下技能,每个技能都需要自己的变量去存储一些信息,注意需要时刻保存和传递信息给对面。
注意中途想换技能或者不想用技能了,想走棋子,还得写一下取消的代码
注意用任何技能都需要给对面发信息,让对面知道。
注意第四个技能需要一个弹窗,来选择到底交换不交换棋子。

}
else {
// 已选择第一个棋后
// 若当前位置为空棋
try {
if (map[y][x] == NULL) {
// 若能移动
if (canMove(y, x)) {这里就move,注意要给对面发一下move信息}
} else if (map[y][x] != -2 && map[y][x] != -3) {
// 若当前的位置不为空棋
// 获取当前的棋编号
// 若当前的棋为我方棋时,则把第一次选择的棋替换为当前棋
if (allChess[pos].getPlayer() == player) {
firstSelect = allChess[pos];
updateOnUI();
} else {
// 是否可以移动
if (canMove(y, x)) {
// 将第一次选择的棋编号置空
这里就eat对面的棋,和move差不多,给对面多发一个eat哪个的信息
(还有个就是eat了带boost的棋子的话,对面也需要知道,但不需要给对面发这个信息,对面自己检查被吃掉的有没有boost就行)

}
}
}
} catch (ArrayIndexOutOfBoundsException e) {
// 若超出棋盘边界则检查是不是进家里了
就是检查可不可以进对面家里,可以的话就给对面发getin信息,然后注意这个棋子需要置空,然后对面家里画个贴图(自己能看到link还是virus,对面看还是看不出来是啥)。}

4.2运行结果

一台服务器,一台客户端,两台机子连接一下:
华为手机:

img

虚拟机:

img

激烈战斗:

img

运行视频

video

4.3发生的故障和问题

(由于bug多到记不清楚了,就随便回忆几个出来写了)

问题1:两边信息不同步,比如我吃了对面的棋子,我自己更新了link和virus的得分数目,但是对面有时候会更新,有时候不更新。
问题1解决:我本来写那个eat,我是先move然后再eat,用sendMes函数连续发了move和eat两个请求。由于间隔时间太短了,接收的线程接收有问题,有时候两个信息都接收到了,有时候有其中一个没有接收到。改一下eat请求,使其包含move的内容,去掉move只剩下eat,然后就正常了。

问题2:我带有boost的棋子进对面的家里,然后新增一个boost给一个新棋子,直接闪退,报错说数组越界。
问题2解决:进对面家里的时候,没有重置boost_num(存储哪个棋子带有boost的变量),导致下一次给boost的时候,下面这段if代码就爆了。

// 获取当前的棋编号
int pos = map[y][x];
// 若当前的棋为我方棋时
if (allChess[pos].getPlayer() == player) {skill = 0;if (boost_num != -1) {allChess[boost_num].setBoost(0);}allChess[pos].setBoost(1);boost_num = pos;// 轮到对方下canPlay = false;sendMes("boost|" + pos + "|" + y + "|" + x + "|");
}

解决方法就是getin的地方加个判断,还原一下boost_num

sendMes("getin|" + getin_link + "|" +getin_virus + "|" +firstSelect.getNum() + "|" +firstSelect.getPosX() + "|" +firstSelect.getPosY() + "|");
getin += 1;
getin_type = firstSelect.getImageId();
**if(allChess[map[firstSelect.getPosX()][firstSelect.getPosY()]].getBoost()==1){boost_num=-1;
}**

问题3:boost的棋子可以走两格,可以直接越过一个棋子。
问题3解决:多写判断就好了,判断一下中间有没有棋子

// 可以斜着一格或者横竖一两格
if (Math.abs(c1 - c2) + Math.abs(r2 - r1) > 2) {return false;
}
if(r1==r2) {if (c1 - c2 == 2 && map[r1][c1 - 1] != NULL) {return false;}if (c2 - c1 == 2 && map[r1][c1 + 1] != NULL) {return false;}
}
if(c1==c2) {if (r1 - r2 == 2 && map[r1 - 1][c1] != NULL) {return false;}if (r2 - r1 == 2 && map[r1 + 1][c1] != NULL) {return false;}
}
if(Math.abs(c1 - c2)==1&&Math.abs(r1 - r2)==1){if(map[r2][c2]==-2||map[r2][c2]==-3){return false;}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.ryyt.cn/news/44620.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈,一经查实,立即删除!

相关文章

解析Html Canvas的卓越性能与高效渲染策略

一、什么是Canvas 想必学习前端的同学们对Canvas 都不陌生,它是 HTML5 新增的“画布”元素,可以使用JavaScript来绘制图形。 Canvas元素是在HTML5中新增的标签用于在网页实时生成图像,并且可以操作图像内容,基本上它是一个可以用JavaScript操作的位图(bitmap)。Canvas 由…

怎么控制多个存储设备的访问权限?数据安全存储方案来了

数据安全存储是指将数据以安全的方式存储在存储系统中,以确保数据的机密性、完整性和可用性。要控制数据安全存储的权限以保障安全,可以采取以下措施:访问控制列表(ACLs):使用ACLs来定义对存储数据的访问权限。ACLs允许你为每个文件或目录指定哪些用户或组有权访问它们,…

GPT-4o 只是对话式 Al 的冰山一角,背后隐藏了哪些新机会?(内含福利) | 编码人声

「编码人声」是由「RTE开发者社区」策划的一档播客节目,关注行业发展变革、开发者职涯发展、技术突破以及创业创新,由开发者来分享开发者眼中的工作与生活。 听友福利 欢迎在小宇宙播客评论区留言,分享你对 GPT-4o 的看法,或者对最有潜力的对话式 AI 场景的预测。我们将抽出…

一个开源的快速准确地将 PDF 转换为 markdown工具

大家好,今天给大家分享的是一个开源的快速准确地将 PDF 转换为 markdown工具。 Marker是一款功能强大的PDF转换工具,它能够将PDF文件快速、准确地转换为Markdown格式。这款工具特别适合处理书籍和科学论文,支持所有语言的转换,并且能够去除页眉、页脚等干扰元素,格式化表格…

简单聊聊Unicode

接下来我们简单讲讲,Unicode 的原理,例如,Unicode 的设计思路,Unicode 和 UTF 的关系等。接下来我们简单讲讲,Unicode 的原理,例如,Unicode 的设计思路,Unicode 和 UTF 的关系等。 ‍ 简单的字符编码模型 一个字符,在计算机中如何存储,是涉及到很多部分的。例如,一个…

有手就行!10分钟上手实现文生图!

Fooocus 一款基于 Gradio 实现的图像生成软件,提供高质量的文本生成图像功能,完全离线、开源、免费。大家好,我是 Java陈序员。 今天,给大家介绍一个文生图工具,无需繁杂的配置,一键安装启动,十分钟就能实现文生图!关注微信公众号:【Java陈序员】,获取开源项目分享、…

盘点常见的内外网文件传输方法 看看哪个最好用!

内外网文件传输在企业里面是很常见的一种业务场景,因为很多企业,包括政府机构、金融、医疗、能源等等行业组织,都会进行网络隔离,来保护内部的数据安全性。常见的内外网文件传输的方法主要包括以下几种: 1、移动介质:通过U盘、移动硬盘等移动存储设备在内外网之间进行文件…

ecs centos 挂载磁盘

# 查找新磁盘 lsblk# 假设新磁盘为/dev/vdb,分区该磁盘,以下为步骤:(# 使用fdisk的指令可以进行分区,这里省略了具体的fdisk命令) # 格式化新分区为ext4文件系统 mkfs.ext4 /dev/vdb1# 创建挂载点 mkdir /mnt# 挂载新分区 mount /dev/vdb1 /mnt# 为了让开机自动挂载,需要…