JAVA安卓植物大战僵尸主题四子棋游戏

JAVA安卓植物大战僵尸主题四子棋游戏前言这里使用安卓最基本的 API 实现双人四子棋游戏 无 AI 开发语言为 java 开发环境为 AndroidStudi 1 2 目标 SDK 版本为 24 最低为 15 界面采用植物大战僵尸主题 图片资源来源于网络 进行了 PS 加工 非原创 游戏界面基本可以适配所有安卓手机分辨率 不过在分辨率太大或太小的手机上整体效果会有影响 Github 源码 https github com jiang

@前言

  1. 这里使用安卓最基本的API实现双人四子棋游戏(无AI),开发语言为java,开发环境为Android Studio 2.1.2,目标SDK版本为24,最低为15;
  2. 界面采用植物大战僵尸主题,图片资源来源于网络,进行了PS加工,非原创;
  3. 游戏界面基本可以适配所有安卓手机分辨率,不过在分辨率太大或太小的手机上整体效果会有影响;
    Github源码: https://github.com/jiangxh1992/FourInRowGame
    视频演示: https://vimeo.com/





@更新:


1.游戏规则功能目标和界面预览

四子棋的游戏规则和五子棋不同,虽然都是横向纵向或对角线方向上有五个或四个相同的棋子即胜利,但四子棋落子有限制,必须要从棋盘底部往上堆叠,不是可以下在任意位置,就相当于将棋盘竖立起来一样,同时四子棋的棋盘是6×7宫格,横向7个,纵向6个,因此出现平局的现象很正常。

这里游戏首先有一个开始界面,点击开始界面的开始游戏按钮进入游戏界面,游戏界面需要实现提示玩家轮流下子,以及胜利平局等状态。
这里写图片描述

这里写图片描述

这里写图片描述

2.UI界面布局设计

基本的静态界面使用xml来布局,开始界面整体使用绝对布局(为了方便实现小动画),放一张背景图片,开始按钮按照sin函数上下浮动,天空中几朵云按照不同的速度来回飘动:

这里写图片描述

游戏界面主要分三部分,头部,棋盘和底部,背景图片被PS分割成三张图片作为三部分的背景,三部分按照权重高度比例为1:5:2,这样棋盘高度占屏幕高度的5/8,手机屏幕宽高比最大一般就是10:16了,这种情况下棋盘高度刚好和宽度相等,而棋盘实际宽高为6:7,可以保证棋盘足以放下所有棋子了。布局上头部使用相对布局,主要放一些按钮;棋盘因为需要获取点击的坐标进行精确定位,所以要使用绝对布局;底部布局都可以只要将剩余的空间填满就好。

这里写图片描述

3.开始界面逻辑实现(动画)

为了实现开始界面的小动画,单独开一个线程,线程放一个while循环结合sleep函数制造一个update定时更新环境:

对于开始按钮,使其按照sin正弦函数上下摆动,通过振幅参数控制上下摆动的幅度,以及每次更新增长的步幅参数来控制上下摆动的速度;

乌云动画是在界面上布置三个ImageView,然后在每次更新中按照速度参数水平移动云彩的位置,通过速度参数控制云移动的速度和方向,当云超出屏幕足够远时将其重置回合适的位置,调整让三朵云的移动速度不同从而制造一种交错运动的自然效果。

4.游戏界面逻辑实现

1.棋盘的绘制更新

这里棋盘中棋子的更换采用图片资源替换的方式,即游戏初始化时将棋盘每个棋子的位置都放置一个ImageView,图片为一张透明图片,当需要放置棋子或者更换更换棋子时,只要给出指定坐标位置,然后根据该坐标对应的棋子状态替换相应的图片资源即可。

整个棋盘的数据模型是一个二维数组,数组元素的类型是一个自定义的数据结构(包含棋子状态值和对应ImageView的引用):

/* 棋子节点数据结构 */ class Piece{ int value; // 0:空 1:玩家1的棋子 2:玩家2的棋子 ImageView image; // 棋子图片 // 构造 Piece(){ value = 0; image = null; } // 重置 void Reset(){ value = 0; image.setImageResource(R.drawable.empty); }

棋盘模型:

// 棋盘 private Piece[][] ChessBord = null;

棋盘初始化时:

 / * 绘制棋盘 */ public void DrawChessBoard(){ // 绘制棋子洞和空棋子 for(int i = 0 ; i 
    
      for ( 
     int j = 
     0 ; j 
     
       // 土壤 ImageView view = 
      new ImageView( 
      this); view.setImageResource(R.drawable.chess_bg); view.setMaxHeight(CellWidth); view.setMaxWidth(CellWidth); view.setX(CellWidth*j+LEFT_GAP); view.setY(CellWidth*i); 
      // 绘制到棋盘中 CBLayout.addView(view); 
      // 空棋子 ImageView piece = 
      new ImageView( 
      this); piece.setImageResource(R.drawable.empty); piece.setMaxHeight(CellWidth); piece.setMaxWidth(CellWidth); piece.setX(CellWidth*j + LEFT_GAP); piece.setY(CellWidth*(V_NUM-i- 
      1)); 
      // 棋子图片引用添加到棋盘数据 ChessBord[j][i].image = piece; 
      // 绘制棋子到棋盘 CBLayout.addView(piece); } } } 
      
    

更新棋子图片的方法:

ChessBord[point.x][point.y].image.setImageResource(R.drawable.chess_p1_win);

2.玩家下子事件

首先是获取在棋盘中玩家触点的坐标,坐标系原点在绝对布局的棋盘的左上角,根据坐标可以计算玩家选择的是哪一列:然后根据当前期盼状态可以定位到某个棋子,然后可以更新棋盘状态和棋盘界面:

// 开始游戏监听,其中CBLayout为棋盘的绝对布局引用,LEFT_GAP是让左边空出一部分,因为背景图片左右两边有部分墙体内容 CBLayout.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { // 选用点击事件 if (event.getAction() == MotionEvent.ACTION_DOWN){ // 横坐标 float touchX = event.getX() - LEFT_GAP; // 列数 int column = (int)(touchX/CellWidth); // 计算并落子 SetPiece(CalCoord(column)); } return false; } });

3.判断是否有人赢

每当有人下棋时都要进行一次是否有人胜利检查,这里定义一个数据结构来记录以当前棋子位置为中心在横向、纵向、两个对角线四个方向上的相同棋子的个数,初始值都为1因为已经中心位置已经有一个棋子了,统计结束后如果四个方向上有数量大于4的则当前玩家胜利:

/* 记录双方棋局状态数据结构 */ class CheckNode{ int Horizontal; // 水平方向上相同棋子的个数 int Vertical; // 竖直方向... int MDiagonal; // 主对角线... int ADiagonal; // 辅对角线... // 构造 CheckNode(){ Horizontal = 1; Vertical = 1; MDiagonal = 1; ADiagonal = 1; } // 重置 void Reset(){ Horizontal = 1; Vertical = 1; MDiagonal = 1; ADiagonal = 1; } }

具体统计过程通过一个循环即可实现,以当前点为中心向八个方向扩散,遇到对方棋子则停止,当八个方向都遇到对方棋子时循环终止:

 / * 检查某个棋子处各个方向上相同棋子的个数,用于判断游戏胜负(返回0表示游戏继续,1表示玩家1赢,2表示玩家2赢) */ public int CheckResult(Point point) { // 检查水平和竖直方向 int stopCount = 0; // 8个方向到边界停止的个数 int[] stopDir = new int[8];// 八个方向是否已经终止 int counter = 0; while (stopCount < 8) { stopCount = 0; ++counter; // 上 if ((stopDir[0]==1) || (point.y + counter >= V_NUM) || ChessBord[point.x][point.y + counter].value != gameResult) { stopDir[0]=1;//向上超出棋盘或遇到非同色棋子终止 } else { checkNode[gameResult - 1].Vertical++;//纵向+1 } // 下 if ((stopDir[1]==1) || (point.y - counter < 0) || ChessBord[point.x][point.y - counter].value != gameResult) { stopDir[1]=1; } else { checkNode[gameResult - 1].Vertical++; } // 左 if ((stopDir[2]==1) || (point.x - counter < 0) || ChessBord[point.x - counter][point.y].value != gameResult) { stopDir[2]=1; } else { checkNode[gameResult - 1].Horizontal++; } // 右 if ((stopDir[3]==1) || (point.x + counter >= H_NUM) || ChessBord[point.x + counter][point.y].value != gameResult) { stopDir[3]=1; } else { checkNode[gameResult - 1].Horizontal++; } // 左上 if ((stopDir[4]==1) || (point.x - counter < 0) || (point.y + counter >= V_NUM) || (ChessBord[point.x - counter][point.y + counter].value != gameResult)) { stopDir[4]=1; } else { checkNode[gameResult - 1].ADiagonal++; } // 右下 if ((stopDir[5]==1) || (point.x + counter >= H_NUM) || (point.y - counter < 0) || (ChessBord[point.x + counter][point.y - counter].value != gameResult)) { stopDir[5]=1; } else { checkNode[gameResult - 1].ADiagonal++; } // 右上 if ((stopDir[6]==1) || (point.x + counter >= H_NUM) || (point.y + counter >= V_NUM) || (ChessBord[point.x + counter][point.y + counter].value != gameResult)) { stopDir[6]=1; } else { checkNode[gameResult - 1].MDiagonal++; } // 左下 if ((stopDir[7]==1) || (point.x - counter < 0) || (point.y - counter < 0) || (ChessBord[point.x - counter][point.y - counter].value != gameResult)) { stopDir[7]=1; } else { checkNode[gameResult - 1].MDiagonal++; } // 终止循环搜索 for(int i =0 ; i<8 ;i++){ stopCount += stopDir[i]; } } // 判断是否有人赢 if (checkNode[gameResult-1].MDiagonal>=4 || checkNode[gameResult-1].ADiagonal>=4 || checkNode[gameResult-1].Horizontal>=4 || checkNode[gameResult-1].Vertical>=4){ return gameResult; }else { return 0; } }

4.悔棋功能

悔棋的实现很简单,只要每次下棋都将所下的棋子的位置入栈即可,悔棋依次将节点从栈取出然后根据节点信息更新UI,更新棋盘数据等相关状态,当所有棋子都取出即栈为空时停止悔棋响应:

// 用一个可变数组实现堆栈依次保存所下棋子的顺序 ArrayList 
    
      PieceStack = 
     null; 
     // 初始化栈 PieceStack = 
     new ArrayList 
     
       (); 
      // 入栈 PieceStack.add(point); 
      / * 悔棋一步 */ 
      public 
      void 
      WithDraw(){ 
      // 异常检测 
      if (PieceStack == 
      null || PieceStack.size() == 
      0) 
      return; 
      // 取出最后一个坐标并出栈 Point point = PieceStack.remove(PieceStack.size()- 
      1); 
      // 棋盘移除最后一步棋 ChessBord[point.x][point.y].Reset(); 
      // 换人 
      if (gameResult == 
      1){ gameResult = 
      2; UpdateUI(gameResult); } 
      else { gameResult = 
      1; UpdateUI(gameResult); } 
      // 计数-1 --pieceCount; } 
      
    

5.特殊显示获胜棋子功能

要特殊显示获胜棋子难点在于要找到同一个方向上个数大于4的棋子,来对其更换图片。当然可以在当时判断是否有人赢时将可能获胜的棋子保存起来,但每次下棋都要判断都要保存,因此操作冗余太大。这里是在确定有人赢之后再根据计算得到的各方向相同棋子个数重新搜索大于4个棋子的行列来确定获胜的棋子:

这里写图片描述

 / * 显示获胜的棋子 */ public void SearchWonPieces(Point point){ // 判断是哪个玩家赢了 int winimg = 0; if (gameResult == 1) winimg = R.drawable.chess_p1_win; else if (gameResult == 2) winimg = R.drawable.chess_p2_win; else{ System.out.print("error!"); return; } // 当前下的一个棋子直接特殊显示 ChessBord[point.x][point.y].image.setImageResource(winimg); // 某个方向上最多的相同棋子个数肯定不会比最大宽度或者高度棋子数多 int maxStep = H_NUM > V_NUM ? H_NUM : V_NUM; for (int i=1 ; i 
      // 上 if (checkNode[gameResult-1].Vertical >= 4 && (point.y + i < V_NUM) && ChessBord[point.x][point.y + i].value == gameResult) { // 满足不越棋盘的界,并且是当前获胜玩家的棋子 UpdateWinImage(new Point(point.x, point.y+i), new Point(point.x, point.y+i-1), winimg); } // 下 if (checkNode[gameResult-1].Vertical >= 4 && (point.y - i >= 0) && ChessBord[point.x][point.y - i].value == gameResult) { UpdateWinImage(new Point(point.x, point.y-i), new Point(point.x, point.y-i+1), winimg); } // 左 if (checkNode[gameResult-1].Horizontal >= 4 && (point.x - i >= 0) && ChessBord[point.x - i][point.y].value == gameResult) { UpdateWinImage(new Point(point.x-i, point.y), new Point(point.x-i+1, point.y), winimg); } // 右 if (checkNode[gameResult-1].Horizontal >= 4 && (point.x + i < H_NUM) && ChessBord[point.x + i][point.y].value == gameResult) { UpdateWinImage(new Point(point.x+i, point.y), new Point(point.x+i-1, point.y), winimg); } // 左上 if (checkNode[gameResult-1].ADiagonal >= 4 && (point.x - i >= 0) && (point.y + i < V_NUM) && (ChessBord[point.x - i][point.y + i].value == gameResult)) { UpdateWinImage(new Point(point.x-i, point.y+i), new Point(point.x-i+1, point.y+i-1), winimg); } // 右下 if (checkNode[gameResult-1].ADiagonal >= 4 && (point.x + i < H_NUM) && (point.y - i >= 0) && (ChessBord[point.x + i][point.y - i].value == gameResult)) { UpdateWinImage(new Point(point.x+i, point.y-i), new Point(point.x+i-1, point.y-i+1), winimg); } // 右上 if (checkNode[gameResult-1].MDiagonal >= 4 && (point.x + i < H_NUM) && (point.y + i < V_NUM) && (ChessBord[point.x + i][point.y + i].value == gameResult)) { UpdateWinImage(new Point(point.x+i, point.y+i), new Point(point.x+i-1, point.y+i-1), winimg); } // 左下 if (checkNode[gameResult-1].MDiagonal >= 4 && (point.x - i >= 0) && (point.y - i >= 0) && (ChessBord[point.x - i][point.y - i].value == gameResult)) { UpdateWinImage(new Point(point.x-i, point.y-i), new Point(point.x-i+1, point.y-i+1), winimg); } } } / * 替换获胜棋子图片(这里要同时检验当前获胜棋子是否和上一个连续,如果中间有对方棋子间隔那么当前这个获胜玩家的棋子并不是真的获胜棋子) */ public void UpdateWinImage(Point curPoint, Point prePoint, int winimg){ if (ChessBord[curPoint.x][curPoint.y].value == ChessBord[prePoint.x][prePoint.y].value){ ChessBord[curPoint.x][curPoint.y].image.setImageResource(winimg); }else { // 出现不连续获胜棋子则将这一排剩下的所有获胜玩家的棋子全部排除掉(事实上顶多出现两个不连续的获胜玩家棋子,因为H_NUM为7) int delX = curPoint.x - prePoint.x; int delY = curPoint.y - prePoint.y; Point nextPoint = new Point(curPoint.x+delX, curPoint.y+delY); while (nextPoint.x>=0 && nextPoint.x 
    
      .y>= 
     0 && nextPoint 
     .y 
     
       .x][nextPoint 
      .y] 
      .value = 
      0 
      ; nextPoint 
      .x += delX 
      ; nextPoint 
      .y += delY 
      ; } } } 
      
    

5.声音特效的添加(MediaPlayer & SoundPool)

  1. 安卓中基本的声音组件是MediaPlayer,通过create函数初始化之后就可以调用start等函数很简单的控制声音播放暂停等等,另外可以为MediaPlayer对象添加监听事件,监听试音播放结束从而进行其他操作,比如这里开始界面在点击开始游戏按钮后播放僵尸笑的音效,然后需要在声音播放结束后再进入游戏界面,这就需要用到这个监听了,具体用法示例如下:
// 创建并初始化MeidaPlayer对象 MediaPlayer media_start = MediaPlayer.create(this, R.raw.zombiesmile); //播放音效 media_start.start(); // 监听音效结束事件 media_start.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { @Override public void onCompletion(MediaPlayer mp) { // 跳转到游戏界面 // ... } });

另外可以通过监听播放结束实现背景音乐的循环播放,即在播放结束时再调用start函数重新播放该音乐。

  1. MediaPlayer虽然容易操作,但只能管理一个音乐,延迟较大,不支持多个音乐同时播放,且消耗资源较大,对于游戏中反复使用的多个短促音效通常使用SoundPool来进行管理操作,这里游戏界面用到的音效都使用SoundPool来管理了,背景音乐仍然采用MediaPlayer单独管理,具体用法如下:
// 定义音效池。第一个参数是管理的音乐片段的最大数量,系统会根据这个参数分配适当的缓存空间;第二个参数表示将音效定义为系统音效;最后一个参数是音效的品质,品质越高相应对系统消耗越大 SoundPool soundPool = new SoundPool(4, AudioManager.STREAM_SYSTEM,5); // 这里依次添加四段音效,最后一个参数指的是播放冲突时的播放优先级,加载的先后顺序决定了每段音效的ID号(从1开始),之后播放是通过ID判断播放哪一段音效 soundPool.load(this, R.raw.game_bg, 1); // 背景音效(弃用) soundPool.load(this, R.raw.peng, 2); // 落子音效 soundPool.load(this, R.raw.dingdong, 3); // 玩家胜利音效 soundPool.load(this, R.raw.dingdong, 4); // 平局音效 // 播放:第一个参数是音效的ID,也就是第4个加载的音效(平局音效);第23个参数分别表示左右声道的音量;第四个参数表示播放优先级,数值越大优先级越高;第五个参数表示是否循环播放,0为不循环,-1为循环;最后一个参数指定播放的比率,数值可从0.521为正常比率 soundPool.play(4,1,1,0,0,1); 

6.简单游戏数据的存储

这里简单存储两个玩家各自获胜的次数两个数字,使用sharedpreferance保存维护两个键值对,sharedpreferance的基本用法如下,其中获取的时候第二个参数是在数据不存在时的默认值,正好实现当第一次获取时两个键值对还不存在,返回默认的0同时创建了该键值对,然后进行存储以及后面的数据获取,也就是默认的0有且只有使用到依次来进行初始化:

 / * 更新数据 */ public void setData(int player){ // 简单数据存储 SharedPreferences sharedPreferences = getSharedPreferences(PREFS_NAME,0); // 数据存储编辑器 SharedPreferences.Editor editor = sharedPreferences.edit(); // 获取旧数据,如果没有存储过返回默认的0 int dataP1 = sharedPreferences.getInt("data_player1",0); int dataP2 = sharedPreferences.getInt("data_player2",0); // 更新数据 if (player == 1){ editor.putInt("data_player1", dataP1+1); }else if (player == 2){ editor.putInt("data_player2", dataP2+1); }else { return; } // 提交数据 editor.commit(); }

这里写图片描述

7.java源码预览

MainActivity.java

这里写图片描述

package com.example.albeeert.fourinrowgame; import android.app.Dialog; import android.content.Intent; import android.content.SharedPreferences; import android.media.MediaPlayer; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.util.DisplayMetrics; import android.view.LayoutInflater; import android.view.View; import android.widget.Button; import android.widget.ImageView; import android.widget.TextView; public class MainActivity extends AppCompatActivity { 
      // 数据存储 public final String PREFS_NAME = "JXHFile"; // 云朵 private ImageView cloud1 = null; private ImageView cloud2 = null; private ImageView cloud3 = null; // 云朵移动速度(值不可太大否则看上去不流畅) private final float cloudspeed1 = 8.0f; private final float cloudspeed2 = 15.0f; private final float cloudspeed3 = 12.0f; // 游戏准备图片 private ImageView ready = null; // 开始游戏按钮和玩家数据按钮 private Button startGameBtn = null; private Button dataButton = null; // 对话框 private View dialogView; // 弹出窗口 private Dialog dialog; // 按钮浮动幅度 private final float range = 10.0f; // 计时间隔 private final int Interval = 100; // sin角度 private double sinAngle = 0; // 开始按钮的Y坐标 private float initY = 0; // 屏幕宽高 private float ScreenW = 0; private float ScreenH = 0; // 动画线程 private MyThread animationThread = null; // 当前页面是否活跃 private boolean isActive = true; // 音乐播放器 private static MediaPlayer media_bg; // 背景音乐 private static MediaPlayer media_start; // 游戏开始音乐 private static MediaPlayer media_button; // 按钮音效 / * Activity life cycle */ @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 界面初始化 UIInit(); // 音效设置 AudioInit(); // 事件监听 setListener(); // 开始按钮浮动动画 animationThread = new MyThread(); new Thread(animationThread).start(); } // 离开当前mainactivity @Override protected void onPause() { super.onPause(); // 暂停背景音乐 media_bg.pause(); // 隐藏准备图片 ready.setVisibility(View.INVISIBLE); isActive = false; } // 回到mainactivity @Override protected void onRestart() { super.onRestart(); isActive = true; // 继续背景音乐 media_bg.start(); // 开始按钮浮动动画 new Thread(animationThread).start(); } // 返回键 @Override public void onBackPressed(){ System.exit(0);// 退出程序 } / * 界面初始化 */ public void UIInit(){ // 基本静态界面 setContentView(R.layout.activity_main); // 获取开始游戏按钮 startGameBtn = (Button)findViewById(R.id.startbutton); // 玩家数据按钮 dataButton = (Button)findViewById(R.id.databutton); // 云朵 cloud1 = (ImageView) findViewById(R.id.cloud1); cloud2 = (ImageView) findViewById(R.id.cloud2); cloud3 = (ImageView) findViewById(R.id.cloud3); // 游戏准备图片 ready = (ImageView) findViewById(R.id.start_ready); // 对话框 dialogView= LayoutInflater.from(this).inflate( R.layout.data_dialog, null); dialog = new Dialog(MainActivity.this); dialog.setTitle("Player Data"); dialog.setContentView(dialogView); dialog.setCanceledOnTouchOutside(true); // 屏幕尺寸 DisplayMetrics dm = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(dm); ScreenH = dm.heightPixels; ScreenW = dm.widthPixels; // 开始按钮起始Y坐标 initY = ScreenH*2/3; } / * 音效设置 */ public void AudioInit(){ // 1.背景音乐 media_bg = MediaPlayer.create(this, R.raw.menu_bg); media_bg.start(); // 实现循环播放 media_bg.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { @Override public void onCompletion(MediaPlayer mp) { media_bg.start(); } }); // 2.开始按钮音效 media_start = MediaPlayer.create(this, R.raw.zombiesmile); // 监听音效结束事件 media_start.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { @Override public void onCompletion(MediaPlayer mp) { // 跳转到游戏界面 Intent intent = new Intent(getBaseContext(),GameActivity.class); startActivity(intent); } }); // 3.普通按钮音效 media_button = MediaPlayer.create(this, R.raw.yoho); } / * 事件监听 */ public void setListener(){ // 开始游戏按钮点击事件 startGameBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // 播放音效 media_start.start(); // 显示准备图片 ready.setVisibility(View.VISIBLE); // 停止动画 isActive = false; } } ); // 玩家数据按钮点击事件 dataButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // 播放音效 media_button.start(); // 获取本地数据 SharedPreferences sharedPreferences = getSharedPreferences(PREFS_NAME,0); int dataP1 = sharedPreferences.getInt("data_player1",0); int dataP2 = sharedPreferences.getInt("data_player2",0); //System.out.print("datap1:"+dataP1+"; "+"datap2:"+dataP2+"\n"); // 更新对话框文字数据 TextView player1DataShow = (TextView) dialogView.findViewById(R.id.player1datashow); TextView player2DataShow = (TextView) dialogView.findViewById(R.id.player2datashow); player1DataShow.setText(String.valueOf(dataP1)); player2DataShow.setText(String.valueOf(dataP2)); // 弹出窗口 dialog.show(); } }); } / * 线程类 */ class MyThread implements Runnable { @Override public void run() { // 开始按钮起始位置 //startGameBtn.setX(ScreenW*3/8); //startGameBtn.setY(initY); // 玩家数据按钮起始位置 //dataButton.setX(ScreenW-170); //dataButton.setY(ScreenH-150); // update while (isActive) { try { Thread.sleep(Interval); // 1.按钮浮动 sinAngle += 0.3f; startGameBtn.setY(initY + (float)(range*Math.sin(sinAngle))); dataButton.setX((float)(range/3*Math.sin(sinAngle))); // 3.云朵移动 if (cloud1.getX() < -500) cloud1.setX(ScreenW + 10.0f); cloud1.setX(cloud1.getX() - cloudspeed1); if (cloud2.getX() > ScreenW) cloud2.setX(-1000.0f); cloud2.setX(cloud2.getX()+cloudspeed2); if (cloud3.getX() > ScreenW) cloud3.setX(-1200.0f); cloud3.setX(cloud3.getX()+cloudspeed3); }catch (Exception e) { e.printStackTrace(); System.out.print("thread error!"); } } } } } 

GameActivity.java

package com.example.albeeert.fourinrowgame; import android.content.SharedPreferences; import android.graphics.Point; import android.media.AudioManager; import android.media.MediaPlayer; import android.media.SoundPool; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.util.DisplayMetrics; import android.view.MotionEvent; import android.view.View; import android.widget.AbsoluteLayout; import android.widget.Button; import android.widget.ImageView; import android.widget.TextView; import java.util.ArrayList; /* 1.记录双方棋局状态数据结构 */ class CheckNode{ int Horizontal; // 水平方向上相同棋子的个数 int Vertical; // 竖直方向... int MDiagonal; // 主对角线... int ADiagonal; // 辅对角线... // 构造 CheckNode(){ Horizontal = 1; Vertical = 1; MDiagonal = 1; ADiagonal = 1; } // 重置 void Reset(){ Horizontal = 1; Vertical = 1; MDiagonal = 1; ADiagonal = 1; } } /* 2.棋子节点数据结构 */ class Piece{ int value; // 0:空 1:玩家1的棋子 2:玩家2的棋子 ImageView image; // 棋子图片 // 构造 Piece(){ value = 0; image = null; } // 重置 void Reset(){ value = 0; image.setImageResource(R.drawable.empty); } } /* 游戏界面 */ public class GameActivity extends AppCompatActivity { 
      // 数据存储 public final String PREFS_NAME = "JXHFile"; // 棋盘横竖棋子个数 public static final int H_NUM = 7; public static final int V_NUM = 6; // 左部间隙 private int LEFT_GAP = 10; // 至少10 // 棋盘宽度(屏幕宽度) private float CBWidth = 0; // 棋盘单位宽度 private int CellWidth = 0; // 获取xml的UI组件引用 private Button ReStartButton = null; private Button WithDrawButton = null; private TextView StatusTop = null; private TextView StatusLeft = null; private TextView StatusRight = null; private ImageView IconLeft = null; private ImageView IconRight = null; private AbsoluteLayout CBLayout = null; // 玩家1和玩家2的棋局状态 private CheckNode[] checkNode = null; // 当前游戏状态(0:平局 1:玩家1下棋 2:玩家2下棋 11:玩家1胜利 22:玩家2胜利) private int gameResult = 0; // 棋盘 private Piece[][] ChessBord = null; // 用一个可变数组实现堆栈依次保存所下棋子的顺序 ArrayList 
    
      PieceStack = 
     null; 
     // 落子计数器 
     private 
     int pieceCount = 
     0; 
     // 音效池 
     private SoundPool soundPool = 
     null; 
     // 背景音乐播放器 
     private MediaPlayer media_bg = 
     null; 
     / * 游戏界面初始化入口 */ 
     @Override 
     protected 
     void 
     onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     // 基础页面 setContentView(R.layout.activity_game); 
     // 全局初始化 ActivityInit(); 
     // 游戏初始化 GameInit(); } 
     / * 返回键监听 */ 
     @Override 
     public 
     void 
     onBackPressed(){ 
     // 关闭背景音乐 media_bg.stop(); 
     this.finish(); } 
     / * 全局初始化(只初始化一次) */ 
     public 
     void 
     ActivityInit(){ 
     // UI 初始化 ReStartButton = (Button)findViewById(R.id.button_restart); WithDrawButton = (Button)findViewById(R.id.button_withdraw); StatusTop = (TextView)findViewById(R.id.topStatus); StatusLeft = (TextView)findViewById(R.id.status_left); StatusRight = (TextView)findViewById(R.id.status_right); IconLeft = (ImageView)findViewById(R.id.icon_left); IconRight = (ImageView)findViewById(R.id.icon_right); CBLayout = (AbsoluteLayout) findViewById(R.id.layout_chessboard); 
     // 音效初始化 soundPool = 
     new SoundPool( 
     4, AudioManager.STREAM_SYSTEM, 
     5); soundPool.load( 
     this, R.raw.game_bg, 
     1); 
     // 背景音效(弃用) soundPool.load( 
     this, R.raw.peng, 
     2); 
     // 落子音效 soundPool.load( 
     this, R.raw.dingdong, 
     3); 
     // 玩家胜利音效 soundPool.load( 
     this, R.raw.dingdong, 
     4); 
     // 平局音效 
     // 背景音乐 media_bg = MediaPlayer.create( 
     this, R.raw.game_bg); media_bg.start(); 
     // 循环播放 media_bg.setOnCompletionListener( 
     new MediaPlayer.OnCompletionListener() { 
     @Override 
     public 
     void 
     onCompletion(MediaPlayer mp) { media_bg.start(); } }); 
     // 棋盘宽高 DisplayMetrics dm = 
     new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(dm); 
     int ScreenW = dm.widthPixels; 
     //int ScreenH = dm.heightPixels; CBWidth = ScreenW - 
     2*LEFT_GAP; CellWidth = ( 
     int)(CBWidth/H_NUM); 
     // 棋盘二维数组 ChessBord = 
     new Piece[H_NUM][V_NUM]; 
     for ( 
     int h= 
     0; h 
     
       for ( 
      int v= 
      0; v 
      
        new Piece(); } } 
       // 检测状态初始化 checkNode = 
       new CheckNode[ 
       2]; checkNode[ 
       0] = 
       new CheckNode(); checkNode[ 
       1] = 
       new CheckNode(); 
       // 绘制棋盘 DrawChessBoard(); 
       // 监听重新开始游戏 ReStartButton.setOnClickListener( 
       new View.OnClickListener() { 
       @Override 
       public 
       void 
       onClick(View v) { RestartGame(); } }); 
       // 开启悔棋监听 WithDrawButton.setOnClickListener( 
       new View.OnClickListener() { 
       @Override 
       public 
       void 
       onClick(View v) { 
       // 悔棋一步 WithDraw(); } }); } 
       / * 游戏初始化(每次重新游戏都要初始化) */ 
       public 
       void 
       GameInit(){ 
       // 开始游戏监听 CBLayout.setOnTouchListener( 
       new View.OnTouchListener() { 
       @Override 
       public 
       boolean 
       onTouch(View v, MotionEvent event) { 
       // 选用点击事件 
       if (event.getAction() == MotionEvent.ACTION_DOWN){ 
       // 横坐标 
       float touchX = event.getX() - LEFT_GAP; 
       // 列数 
       int column = ( 
       int)(touchX/CellWidth); 
       // 计算并落子 SetPiece(CalCoord(column)); } 
       return 
       false; } }); 
       // 默认玩家1先手 gameResult = 
       1; UpdateUI( 
       1); 
       // 保证隐藏draw StatusTop.setText( 
       ""); 
       // 落子计数器 pieceCount = 
       0; 
       // 初始化栈 PieceStack = 
       new ArrayList 
       
         (); } 
        / * 游戏结束 */ 
        public 
        void 
        GameOver(){ 
        // 停止游戏棋盘交互 CBLayout.setOnTouchListener( 
        null); 
        // 清空栈 PieceStack = 
        null; } 
        / * 重新开始游戏 */ 
        public 
        void 
        RestartGame(){ 
        // 重置棋盘 
        for ( 
        int h= 
        0; h 
        
          for ( 
         int v= 
         0; v 
         
           // 重新初始化游戏 GameInit(); } 
          / * 绘制棋盘 */ 
          public 
          void 
          DrawChessBoard(){ 
          // 绘制棋子洞和空棋子 
          for( 
          int i = 
          0 ; i 
          
            for ( 
           int j = 
           0 ; j 
           
             // 土壤 ImageView view = 
            new ImageView( 
            this); view.setImageResource(R.drawable.chess_bg); view.setMaxHeight(CellWidth); view.setMaxWidth(CellWidth); view.setX(CellWidth*j+LEFT_GAP); view.setY(CellWidth*i); 
            // 绘制到棋盘中 CBLayout.addView(view); 
            // 空棋子 ImageView piece = 
            new ImageView( 
            this); piece.setImageResource(R.drawable.empty); piece.setMaxHeight(CellWidth); piece.setMaxWidth(CellWidth); piece.setX(CellWidth*j + LEFT_GAP); piece.setY(CellWidth*(V_NUM-i- 
            1)); 
            // 棋子图片引用添加到棋盘数据 ChessBord[j][i].image = piece; 
            // 绘制棋子到棋盘 CBLayout.addView(piece); } } } 
            / * 计算落子坐标 */ 
            public Point 
            CalCoord( 
            int column){ 
            // 如果超出棋盘右边界视为最右边的一列 
            if (column >= H_NUM) column = H_NUM- 
            1; 
            // 计算落子坐标 
            for ( 
            int i = 
            0 ; i 
            
              if (ChessBord[column][i].value == 
             0){ Point point = 
             new Point(column,i); 
             return point; } 
             else { 
             continue; } } 
             return 
             null; } 
             / * 落子并计算更新游戏状态 */ 
             public 
             void 
             SetPiece(Point point){ 
             // 该列棋子已落满或者程序出错 
             if (point == 
             null) 
             return; 
             // 入栈 PieceStack.add(point); 
             // 计数器+1 ++pieceCount; 
             // 界面落子 DrawPiece(point); 
             // 游戏状态更新 ChessBord[point.x][point.y].value = gameResult; 
             // 检查输赢情况 
             // 是否已平局 
             if (pieceCount == V_NUM*H_NUM){ 
             // 平局 UpdateUI( 
             0); 
             // 游戏结束 GameOver(); 
             // 终止 
             return; } 
             // 是否有人赢 
             int result = CheckResult(point); 
             if (result == 
             0){ 
             // 换人继续 
             if (gameResult == 
             1){ gameResult = 
             2; UpdateUI(gameResult); } 
             else { gameResult = 
             1; UpdateUI(gameResult); } } 
             else { 
             / 已经有人赢了 / 
             // 显示获胜的棋子 SearchWonPieces(point); 
             // 更新数据 setData(gameResult); 
             // 更新UI 
             if (gameResult == 
             1){ 
             // 玩家1赢 UpdateUI( 
             11); } 
             else { 
             // 玩家2赢 UpdateUI( 
             22); } 
             // 游戏结束 GameOver(); } 
             // 重置检测状态 checkNode[ 
             0].Reset(); checkNode[ 
             1].Reset(); } 
             / * 显示获胜的棋子 */ 
             public 
             void 
             SearchWonPieces(Point point){ 
             // 判断是哪个玩家赢了 
             int winimg = 
             0; 
             if (gameResult == 
             1) winimg = R.drawable.chess_p1_win; 
             else 
             if (gameResult == 
             2) winimg = R.drawable.chess_p2_win; 
             else{ System.out.print( 
             "error!"); 
             return; } 
             // 当前下的一个棋子直接特殊显示 ChessBord[point.x][point.y].image.setImageResource(winimg); 
             // 某个方向上最多的相同棋子个数肯定不会比最大宽度或者高度棋子数多 
             int maxStep = H_NUM > V_NUM ? H_NUM : V_NUM; 
             for ( 
             int i= 
             1 ; i 
             
               // 上 
              if (checkNode[gameResult- 
              1].Vertical >= 
              4 && (point.y + i < V_NUM) && ChessBord[point.x][point.y + i].value == gameResult) { 
              // 满足不越棋盘的界,并且是当前获胜玩家的棋子 UpdateWinImage( 
              new Point(point.x, point.y+i), 
              new Point(point.x, point.y+i- 
              1), winimg); } 
              // 下 
              if (checkNode[gameResult- 
              1].Vertical >= 
              4 && (point.y - i >= 
              0) && ChessBord[point.x][point.y - i].value == gameResult) { UpdateWinImage( 
              new Point(point.x, point.y-i), 
              new Point(point.x, point.y-i+ 
              1), winimg); } 
              // 左 
              if (checkNode[gameResult- 
              1].Horizontal >= 
              4 && (point.x - i >= 
              0) && ChessBord[point.x - i][point.y].value == gameResult) { UpdateWinImage( 
              new Point(point.x-i, point.y), 
              new Point(point.x-i+ 
              1, point.y), winimg); } 
              // 右 
              if (checkNode[gameResult- 
              1].Horizontal >= 
              4 && (point.x + i < H_NUM) && ChessBord[point.x + i][point.y].value == gameResult) { UpdateWinImage( 
              new Point(point.x+i, point.y), 
              new Point(point.x+i- 
              1, point.y), winimg); } 
              // 左上 
              if (checkNode[gameResult- 
              1].ADiagonal >= 
              4 && (point.x - i >= 
              0) && (point.y + i < V_NUM) && (ChessBord[point.x - i][point.y + i].value == gameResult)) { UpdateWinImage( 
              new Point(point.x-i, point.y+i), 
              new Point(point.x-i+ 
              1, point.y+i- 
              1), winimg); } 
              // 右下 
              if (checkNode[gameResult- 
              1].ADiagonal >= 
              4 && (point.x + i < H_NUM) && (point.y - i >= 
              0) && (ChessBord[point.x + i][point.y - i].value == gameResult)) { UpdateWinImage( 
              new Point(point.x+i, point.y-i), 
              new Point(point.x+i- 
              1, point.y-i+ 
              1), winimg); } 
              // 右上 
              if (checkNode[gameResult- 
              1].MDiagonal >= 
              4 && (point.x + i < H_NUM) && (point.y + i < V_NUM) && (ChessBord[point.x + i][point.y + i].value == gameResult)) { UpdateWinImage( 
              new Point(point.x+i, point.y+i), 
              new Point(point.x+i- 
              1, point.y+i- 
              1), winimg); } 
              // 左下 
              if (checkNode[gameResult- 
              1].MDiagonal >= 
              4 && (point.x - i >= 
              0) && (point.y - i >= 
              0) && (ChessBord[point.x - i][point.y - i].value == gameResult)) { UpdateWinImage( 
              new Point(point.x-i, point.y-i), 
              new Point(point.x-i+ 
              1, point.y-i+ 
              1), winimg); } } } 
              / * 替换获胜棋子图片(这里要同时检验当前获胜棋子是否和上一个连续,如果中间有对方棋子间隔那么当前这个获胜玩家的棋子并不是真的获胜棋子) */ 
              public 
              void 
              UpdateWinImage(Point curPoint, Point prePoint, 
              int winimg){ 
              if (ChessBord[curPoint.x][curPoint.y].value == ChessBord[prePoint.x][prePoint.y].value){ ChessBord[curPoint.x][curPoint.y].image.setImageResource(winimg); } 
              else { 
              // 出现不连续获胜棋子则将这一排剩下的所有获胜玩家的棋子全部排除掉(事实上顶多出现两个不连续的获胜玩家棋子,因为H_NUM为7) 
              int delX = curPoint.x - prePoint.x; 
              int delY = curPoint.y - prePoint.y; Point nextPoint = 
              new Point(curPoint.x+delX, curPoint.y+delY); 
              while (nextPoint.x>= 
              0 && nextPoint.x 
              
                = 
               0 && nextPoint.y 
               
                 0; nextPoint.x += delX; nextPoint.y += delY; } } } 
                / * 更新UI显示状态 */ 
                public 
                void 
                UpdateUI( 
                int gameResult){ 
                if (gameResult == 
                0){ 
                // 平局 StatusTop.setText( 
                "Draw"); StatusLeft.setText( 
                ""); StatusRight.setText( 
                ""); 
                // 两个玩家都高亮 IconLeft.setImageResource(R.drawable.chess_p1_win); IconRight.setImageResource(R.drawable.chess_p2_win); 
                // 平局音效 soundPool.play( 
                4, 
                1, 
                1, 
                0, 
                0, 
                1); } 
                else 
                if (gameResult == 
                1){ 
                // 玩家1下棋 StatusLeft.setText( 
                " !"); StatusRight.setText( 
                ""); 
                // 玩家1高亮 IconLeft.setImageResource(R.drawable.chess_p1_win); IconRight.setImageResource(R.drawable.chess_p2); } 
                else 
                if (gameResult == 
                2){ 
                // 玩家2下棋 StatusLeft.setText( 
                ""); StatusRight.setText( 
                "! "); 
                // 玩家2高亮 IconLeft.setImageResource(R.drawable.chess_p1); IconRight.setImageResource(R.drawable.chess_p2_win); } 
                else 
                if(gameResult == 
                11){ 
                // 玩家1赢 StatusLeft.setText( 
                "Win!"); StatusRight.setText( 
                ""); 
                // 胜利音效 soundPool.play( 
                3, 
                1, 
                1, 
                2, 
                0, 
                1); } 
                else 
                if (gameResult == 
                22){ 
                // 玩家2赢 StatusLeft.setText( 
                ""); StatusRight.setText( 
                "Win!"); 
                // 胜利音效 soundPool.play( 
                3, 
                1, 
                1, 
                2, 
                0, 
                1); } 
                else { 
                return; } } 
                / * 绘制指定棋子 */ 
                public 
                void 
                DrawPiece(Point point){ 
                // 播放音效 soundPool.play( 
                2, 
                1, 
                1, 
                1, 
                0, 
                1); 
                // 绘制 ImageView piece = ChessBord[point.x][point.y].image; 
                if (gameResult == 
                1){ piece.setImageResource(R.drawable.chess_p1); } 
                else { piece.setImageResource(R.drawable.chess_p2); } } 
                / * 检查某个棋子处各个方向上相同棋子的个数,用于判断游戏胜负(返回0表示游戏继续,1表示玩家1赢,2表示玩家2赢) */ 
                public 
                int 
                CheckResult(Point point) { 
                // 检查水平和竖直方向 
                int stopCount = 
                0; 
                // 8个方向到边界停止的个数 
                int[] stopDir = 
                new 
                int[ 
                8]; 
                // 八个方向是否已经终止 
                int counter = 
                0; 
                while (stopCount < 
                8) { stopCount = 
                0; ++counter; 
                // 上 
                if ((stopDir[ 
                0]== 
                1) || (point.y + counter >= V_NUM) || ChessBord[point.x][point.y + counter].value != gameResult) { stopDir[ 
                0]= 
                1; 
                //向上超出棋盘或遇到非同色棋子终止 } 
                else { checkNode[gameResult - 
                1].Vertical++; 
                //纵向+1 } 
                // 下 
                if ((stopDir[ 
                1]== 
                1) || (point.y - counter < 
                0) || ChessBord[point.x][point.y - counter].value != gameResult) { stopDir[ 
                1]= 
                1; } 
                else { checkNode[gameResult - 
                1].Vertical++; } 
                // 左 
                if ((stopDir[ 
                2]== 
                1) || (point.x - counter < 
                0) || ChessBord[point.x - counter][point.y].value != gameResult) { stopDir[ 
                2]= 
                1; } 
                else { checkNode[gameResult - 
                1].Horizontal++; } 
                // 右 
                if ((stopDir[ 
                3]== 
                1) || (point.x + counter >= H_NUM) || ChessBord[point.x + counter][point.y].value != gameResult) { stopDir[ 
                3]= 
                1; } 
                else { checkNode[gameResult - 
                1].Horizontal++; } 
                // 左上 
                if ((stopDir[ 
                4]== 
                1) || (point.x - counter < 
                0) || (point.y + counter >= V_NUM) || (ChessBord[point.x - counter][point.y + counter].value != gameResult)) { stopDir[ 
                4]= 
                1; } 
                else { checkNode[gameResult - 
                1].ADiagonal++; } 
                // 右下 
                if ((stopDir[ 
                5]== 
                1) || (point.x + counter >= H_NUM) || (point.y - counter < 
                0) || (ChessBord[point.x + counter][point.y - counter].value != gameResult)) { stopDir[ 
                5]= 
                1; } 
                else { checkNode[gameResult - 
                1].ADiagonal++; } 
                // 右上 
                if ((stopDir[ 
                6]== 
                1) || (point.x + counter >= H_NUM) || (point.y + counter >= V_NUM) || (ChessBord[point.x + counter][point.y + counter].value != gameResult)) { stopDir[ 
                6]= 
                1; } 
                else { checkNode[gameResult - 
                1].MDiagonal++; } 
                // 左下 
                if ((stopDir[ 
                7]== 
                1) || (point.x - counter < 
                0) || (point.y - counter < 
                0) || (ChessBord[point.x - counter][point.y - counter].value != gameResult)) { stopDir[ 
                7]= 
                1; } 
                else { checkNode[gameResult - 
                1].MDiagonal++; } 
                // 终止循环搜索 
                for( 
                int i = 
                0 ; i< 
                8 ;i++){ stopCount += stopDir[i]; } } 
                // 判断是否有人赢 
                if (checkNode[gameResult- 
                1].MDiagonal>= 
                4 || checkNode[gameResult- 
                1].ADiagonal>= 
                4 || checkNode[gameResult- 
                1].Horizontal>= 
                4 || checkNode[gameResult- 
                1].Vertical>= 
                4){ 
                return gameResult; } 
                else { 
                return 
                0; } } 
                / * 悔棋一步 */ 
                public 
                void 
                WithDraw(){ 
                // 异常检测 
                if (PieceStack == 
                null || PieceStack.size() == 
                0) 
                return; 
                // 取出最后一个坐标并出栈 Point point = PieceStack.remove(PieceStack.size()- 
                1); 
                // 棋盘移除最后一步棋 ChessBord[point.x][point.y].Reset(); 
                // 换人 
                if (gameResult == 
                1){ gameResult = 
                2; UpdateUI(gameResult); } 
                else { gameResult = 
                1; UpdateUI(gameResult); } 
                // 计数-1 --pieceCount; } 
                / * 更新数据 */ 
                public 
                void 
                setData( 
                int player){ 
                // 简单数据存储 SharedPreferences sharedPreferences = getSharedPreferences(PREFS_NAME, 
                0); 
                // 数据存储编辑器 SharedPreferences.Editor editor = sharedPreferences.edit(); 
                // 获取旧数据,如果没有存储过返回默认的0 
                int dataP1 = sharedPreferences.getInt( 
                "data_player1", 
                0); 
                int dataP2 = sharedPreferences.getInt( 
                "data_player2", 
                0); 
                // 更新数据 
                if (player == 
                1){ editor.putInt( 
                "data_player1", dataP1+ 
                1); } 
                else 
                if (player == 
                2){ editor.putInt( 
                "data_player2", dataP2+ 
                1); } 
                else { 
                return; } 
                // 提交数据 editor.commit(); } } 
                
               
              
             
            
           
          
         
        
       
      
    

orz……有问题吐槽请留言,帮到您烦请帮顶一下,谢谢^_^

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/229302.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月16日 下午5:00
下一篇 2026年3月16日 下午5:01


相关推荐

  • linux route输出分析,Traceroute原理分析[通俗易懂]

    linux route输出分析,Traceroute原理分析[通俗易懂]traceroute,现代Linux系统上的tracepath,还有Windows系统上的tracert,均是用于同一目的的网络调试工具。它们用于显示数据包在IP网络中经过的路由器的IP地址。原理这些程序是利用IP数据包的存活时间(TTL)值来实现其功能的。当一台计算机发送IP数据包时,会为数据包设置存活时间(TTL)值。每当数据包经过一个路由器,其存活时间值就会减1。当存活时间减到…

    2022年7月21日
    13
  • Java链表删除节点操作

    Java链表删除节点操作1、创建节点类Node/***程序目的:建立一组学生成绩的单向链表程序,包含学号、姓名、和成绩3种数据。只要输入要删除学生的成绩,就可以遍历该链表,并清除学生的节点,*要结束输入时,输入“-1”,则此时会列出该链表未删除的所有学生数据。**@author86176**///构建节点类publicclassNode{ intdata; int…

    2022年5月18日
    42
  • Ubuntu使用bind9配置DNS服务器

    Ubuntu使用bind9配置DNS服务器为了实现负载均衡 扩展服务器带宽 需要自己配置 DNS 服务器解析对应域名 本文记录 Ubuntu 系统配置 DNS 服务的方法 假设域名 www mydomain com 已在阿里云作了解析 现在需要新增一个二级域名 stream mydomain com 做推流服务 需要使用自己配置的 DNS 服务做请求解析分发 1 安装 bind9 使用指令安装 DNS 服务程序 bind9apt getinstallbi 修改 option 配置

    2026年3月17日
    2
  • 自动注册 Cursor Ai ,自动重置机器ID , 免费升级使用Pro功能

    自动注册 Cursor Ai ,自动重置机器ID , 免费升级使用Pro功能

    2026年3月16日
    2
  • websrorm2021.5激活码[在线序列号][通俗易懂]

    websrorm2021.5激活码[在线序列号],https://javaforall.net/100143.html。详细ieda激活码不妨到全栈程序员必看教程网一起来了解一下吧!

    2022年3月18日
    44
  • 【Python 局域网控制】——做一个超简单的局域网指令控制电脑

    【Python 局域网控制】——做一个超简单的局域网指令控制电脑程序分为两部分,一个是客户端也是被操控的端口,另一个是服务端就是用来操作被操控的端口点个赞留个关注吧!!程序很简单,是通过局域网聊天系统改造而成,没有高级的GUI框架,只有简简单单的DOS窗口,这个仅供学习,当然也可以在你的第二台电脑里放入客户端,然后用服务端进行指令操作,也是很不错的。客户端会自动获取你的IPv4地址,并显示出来,需要用客户端给出的IP地址去服务端进行连接。执行指令也很简单,用接收到的数据进行os.system()进行执行。想法多的也可以做一个鼠标定位数据传输,可达到鼠

    2022年6月22日
    35

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号