坦克大战

项目来自 B站 Up主 韩顺平教育,作为java初学综合练习项目使用

视频链接:01_韩顺平坦克大战_介绍_哔哩哔哩_bilibili

文章目录

  • 坦克大战
    • TankGame 主方法
    • MyPanel 视图
    • Bomb 爆炸类
    • Hero 我方坦克类
    • EnemyTank 敌方坦克类
    • Node 记录敌方坦克类
    • Recoder 记录游戏数据类
    • Shot 子弹类
    • Tank 坦克父类
    • AePlayWave 播放器背景音乐类

TankGame 主方法

package com.liner.tankGame;import javax.swing.*;
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.Scanner;/*** 坦克大战1.0版本** @author 一条淡水鱼 ゆ* on 2023-03-07*/
public class TankGame01 extends JFrame {static Scanner scanner = new Scanner(System.in);private MyPanel panel = null;public TankGame01() {System.out.println("请输入选择:1:启动新游戏:2:继续上一局");String key = scanner.next();panel = new MyPanel(key);this.add(panel);this.setSize(1300,750);this.setVisible(true);this.addKeyListener(panel);//在 JFrame 中增加相应的关闭窗口处理this.addWindowListener(new WindowAdapter(){@Overridepublic void windowClosing(WindowEvent e) {Recorder.keepRecord();System.exit(0);}});Thread thread = new Thread(panel);thread.start();this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);}public static void main(String[] args) {new TankGame01();}}

MyPanel 视图

package com.liner.tankGame;import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.File;
import java.util.Vector;/*** 画板类 坦克大战绘图区** @author 一条淡水鱼 ゆ* on 2023-03-07*/
public class MyPanel extends JPanel implements KeyListener, Runnable {/*** 我方坦克*/Hero hero = null;/*** 敌方坦克 存入 Vector集合中*/Vector<EnemyTank> enemyTanks = new Vector<>();public Vector<EnemyTank> getEnemyTanks() {return enemyTanks;}public void setEnemyTanks(Vector<EnemyTank> enemyTanks) {this.enemyTanks = enemyTanks;}/*** 定义一个 存放Node 对象 的Vector 用于恢复敌人坦克的位置信息*/Vector<Node> nodes = new Vector<>();/*** 定义爆炸模型* 当子弹击中坦克 加入Bomb 对象 bombs*/Vector<Bomb> bombs = new Vector<>();/*** 定义三张爆炸模型图片*/Image image1 = null;Image image2 = null;Image image3 = null;/*** 定义敌方坦克数量*/int enemyTanksSize = 4;public MyPanel(String key) {//先判断记录的文件是否存在File file = new File(Recorder.getRecordFile());if (file.exists()) {nodes = Recorder.getNodesAndTanks();}else {System.out.println("文件不存在,只能开启新游戏");key = "1";}//将 MyPanel 对象的 enemyTanks 设置给 Recorder 的 enemyTanksRecorder.setEnemyTanks(enemyTanks);//初始化我方坦克hero = new Hero(500, 100);/*** 选择 1 则开始新游戏,选择 2 则继续上一局*/switch (key) {case "1"://初始化敌方坦克for (int i = 0; i < enemyTanksSize; i++) {//创建敌方坦克EnemyTank enemyTank = new EnemyTank((100 * (i + 1)), 0);//设置敌方坦克方向enemyTank.setDirection(2);//将 enemyTanks 设置给 EnemyTank !!!enemyTank.setEnemyTanks(enemyTanks);enemyTank.setSpeed(2);//启动敌方坦克线程new Thread(enemyTank).start();//创建敌方子弹Shot shot = new Shot(enemyTank.getX() + 20, enemyTank.getY() + 60, enemyTank.getDirection());//加入 enemyTank 的 Vector 成员enemyTank.shots.add(shot);//启动 shot 对象new Thread(shot).start();//加入enemyTanks.add(enemyTank);}break;case "2"://初始化敌方坦克for (int i = 0; i < nodes.size(); i++) {Node node = nodes.get(i);//创建敌方坦克EnemyTank enemyTank = new EnemyTank(node.getX(),node.getY());//设置敌方坦克方向enemyTank.setDirection(node.getDirection());//将 enemyTanks 设置给 EnemyTank !!!enemyTank.setEnemyTanks(enemyTanks);enemyTank.setSpeed(2);//启动敌方坦克线程new Thread(enemyTank).start();//创建敌方子弹Shot shot = new Shot(enemyTank.getX() + 20, enemyTank.getY() + 60, enemyTank.getDirection());//加入 enemyTank 的 Vector 成员enemyTank.shots.add(shot);//启动 shot 对象new Thread(shot).start();//加入enemyTanks.add(enemyTank);}break;default:System.out.println("输入有误,请重新输入");break;}//初始化图片对象image1 = Toolkit.getDefaultToolkit().getImage(Panel.class.getResource("/bomb_1.gif"));image2 = Toolkit.getDefaultToolkit().getImage(Panel.class.getResource("/bomb_2.gif"));image3 = Toolkit.getDefaultToolkit().getImage(Panel.class.getResource("/bomb_3.gif"));//初始化背景音乐new AePlayWave("E:\\TeduWork\\Bootcamp\\Tank\\src\\111.wav").start();}/*** 编写方法 显示我方击毁敌方坦克信息** @param g*/public void showInfo(Graphics g) {//画出玩家总成绩g.setColor(Color.BLACK);Font font = new Font("宋体", Font.BOLD, 25);g.setFont(font);g.drawString("您累计击毁敌方坦克", 1020, 30);drawTank(1020, 60, g, 0, 2);g.setColor(Color.BLACK);g.drawString(Recorder.getAllEnemyTankTotal() + "", 1080, 100);}@Overridepublic void paint(Graphics g) {super.paint(g);//背景颜色g.fillRect(0, 0, 1000, 750);showInfo(g);//画出我方坦克 封装方法if (hero != null && hero.isLive) {drawTank(hero.getX(), hero.getY(), g, hero.getDirection(), 1);}//画出我方坦克 发射出的子弹// 将 hero 的子弹集合 shots 遍历取出绘制for (int i = 0; i < hero.shots.size(); i++) {Shot shot = hero.shots.get(i);if (shot != null && shot.isLive) {g.draw3DRect(shot.x, shot.y, 2, 2, false);} else {//如果 shot 对象已经失效,从 shots 集合中拿掉hero.shots.remove(shot);}}//画出炸弹爆炸后的效果  如果 bombs 集合中有对象,就画出for (int i = 0; i < bombs.size(); i++) {//取出炸弹Bomb bomb = bombs.get(i);//根据当前的 bomb对象的life去画if (bomb.life > 6) {g.drawImage(image1, bomb.x, bomb.y, 60, 60, this);} else if (bomb.life > 3) {g.drawImage(image2, bomb.x, bomb.y, 60, 60, this);} else {g.drawImage(image3, bomb.x, bomb.y, 60, 60, this);}//让 bomb 的生命周期减少bomb.lifeDown();if (bomb.life == 0) {bombs.remove(bomb);}}//画出敌方坦克,遍历Vectorfor (int i = 0; i < enemyTanks.size(); i++) {//取出坦克EnemyTank enemyTank = enemyTanks.get(i);//判断坦克是否存活if (enemyTank.isLive) {drawTank(enemyTank.getX(), enemyTank.getY(), g, enemyTank.getDirection(), 2);//画出 敌方坦克的子弹for (int j = 0; j < enemyTank.shots.size(); j++) {//取出子弹Shot shot = enemyTank.shots.get(j);//绘制子弹if (shot.isLive) {g.draw3DRect(shot.x, shot.y, 2, 2, false);} else {enemyTank.shots.remove(shot);}}}}}/*** @param x         x坐标* @param y         y坐标* @param g         画笔* @param direction 方向 上右下左 0,1,2,3* @param type      类型 1.我方,2 敌方*/public void drawTank(int x, int y, Graphics g, int direction, int type) {//坦克类型switch (type) {case 1://我方坦克g.setColor(Color.CYAN);break;case 2://敌方坦克g.setColor(Color.ORANGE);break;default:}//坦克方向switch (direction) {//向上case 0://绘制坦克//左边履带g.fill3DRect(x, y, 10, 60, false);//右边履带g.fill3DRect(x + 30, y, 10, 60, false);//坦克机体g.fill3DRect(x + 10, y + 10, 20, 40, false);//坦克机身g.fillOval(x + 10, y + 20, 20, 20);//坦克炮管g.drawLine(x + 20, y + 30, x + 20, y);break;//向右case 1:g.fill3DRect(x, y, 60, 10, false);g.fill3DRect(x, y + 30, 60, 10, false);g.fill3DRect(x + 10, y + 10, 40, 20, false);g.fillOval(x + 20, y + 10, 20, 20);g.drawLine(x + 30, y + 20, x + 60, y + 20);break;//向下case 2:g.fill3DRect(x, y, 10, 60, false);g.fill3DRect(x + 30, y, 10, 60, false);g.fill3DRect(x + 10, y + 10, 20, 40, false);g.fillOval(x + 10, y + 20, 20, 20);g.drawLine(x + 20, y + 30, x + 20, y + 60);break;//向左case 3:g.fill3DRect(x, y, 60, 10, false);g.fill3DRect(x, y + 30, 60, 10, false);g.fill3DRect(x + 10, y + 10, 40, 20, false);g.fillOval(x + 20, y + 10, 20, 20);g.drawLine(x + 30, y + 20, x, y + 20);break;default:}}/*** 如果我方坦克可发射多颗子弹* 在判断我方子弹是否击中敌人坦克,就需要把子弹集合中的子弹 都取出和所有坦克继续判断*/public void hitEnemyTank() {//遍历我们的子弹/* for (int i = 0; i < hero.shots.size(); i++) {Shot shot = hero.shots.get(i);//判断是否击中了敌方坦克if (shot != null && shot.isLive) {//子弹存活状态下遍历敌方所有坦克for (EnemyTank enemyTank : enemyTanks) {hitTank(shot, enemyTank);}}}*/if (hero.shot != null && hero.shot.isLive) {//子弹存活状态下遍历敌方所有坦克for (int i = 0; i < enemyTanks.size(); i++) {EnemyTank enemyTank = enemyTanks.get(i);hitTank(hero.shot, enemyTank);}}}/*** 敌方坦克是否击中我方坦克*/public void hitHero() {//遍历所有敌方坦克for (int i = 0; i < enemyTanks.size(); i++) {EnemyTank enemyTank = enemyTanks.get(i);//遍历 enemyTank 对象的所有子弹for (int j = 0; j < enemyTank.shots.size(); j++) {//取出子弹Shot shot = enemyTank.shots.get(j);//判断是否击中了我方坦克if (shot.isLive && hero.isLive) {//子弹存活状态下遍历敌方所有坦克hitTank(shot, hero);}}}}/*** 判断是否击中了坦克** @param shot 子弹* @param tank 坦克*/public void hitTank(Shot shot, Tank tank) {//判断 shot 是否 击中敌方坦克的区域switch (tank.getDirection()) {case 0:case 2:if (shot.x > tank.getX() && shot.y > tank.getY()&& shot.x < tank.getX() + 40 && shot.y < tank.getY() + 60) {shot.isLive = false;tank.isLive = false;enemyTanks.remove(tank);//我方击毁一个敌方坦克,就会对 allEnemyTankTotal 自增if (tank instanceof EnemyTank) {Recorder.addAllEnemyTankTotal();}//创建Bomb对象,加入bombs集合Bomb bomb = new Bomb(tank.getX(), tank.getY());bombs.add(bomb);}break;case 1:case 3:if (shot.x > tank.getX() && shot.y > tank.getY()&& shot.x < tank.getX() + 60 && shot.y < tank.getY() + 40) {shot.isLive = false;tank.isLive = false;enemyTanks.remove(tank);//我方击毁一个敌方坦克,就会对 allEnemyTankTotal 自增if (tank instanceof EnemyTank) {Recorder.addAllEnemyTankTotal();}//创建Bomb对象,加入bombs集合Bomb bomb = new Bomb(tank.getX(), tank.getY());bombs.add(bomb);}break;default:break;}}@Overridepublic void keyTyped(KeyEvent e) {}/*** 监听按键按下** @param e*/@Overridepublic void keyPressed(KeyEvent e) {if (e.getKeyCode() == KeyEvent.VK_UP) {hero.setDirection(0);if (hero.getY() > 0) {hero.moveUp();}} else if (e.getKeyCode() == KeyEvent.VK_RIGHT) {hero.setDirection(1);if (hero.getX() + 60 < 1000) {hero.moveRight();}} else if (e.getKeyCode() == KeyEvent.VK_DOWN) {hero.setDirection(2);if (hero.getY() + 110 < 750) {hero.moveDown();}} else if (e.getKeyCode() == KeyEvent.VK_LEFT) {hero.setDirection(3);if (hero.getX() > 0) {hero.moveLeft();}}//用户按下 J 发射子弹if (e.getKeyCode() == KeyEvent.VK_J) {//判断 hero 的子弹是否消亡 发射1颗子弹/*if (hero.shot == null || !hero.shot.isLive) {hero.shotEnemyTank();}*///发射多颗子弹hero.shotEnemyTank();}this.repaint();}/*** 监听按键释放** @param e*/@Overridepublic void keyReleased(KeyEvent e) {}@Overridepublic void run() {//每隔100ms,重绘区域while (true) {try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}//判断是否击中了敌人的坦克hitEnemyTank();//判断是否敌人击中了我方坦克hitHero();this.repaint();}}
}

Bomb 爆炸类

package com.liner.tankGame;/*** 爆炸效果** @author 一条淡水鱼 ゆ* on 2023-03-08*/
public class Bomb {int x, y;/*** 生命周期*/int life = 9;/*** 是否还存活*/boolean isLive = true;public Bomb(int x, int y) {this.x = x;this.y = y;}/*** 减少生命值* 配合出现图片的爆炸效果*/public void lifeDown() {if (life > 0){life--;}else {isLive = false;}}}

Hero 我方坦克类

package com.liner.tankGame;import java.util.Vector;/*** 主角坦克** @author 一条淡水鱼 ゆ* on 2023-03-07*/
public class Hero extends Tank {/*** 创建子弹对象*/Shot shot = null;/*** 可以定义发射多颗子弹*/Vector<Shot> shots = new Vector<>();public Hero(int x, int y) {super(x, y);}/*** 射击*/public void shotEnemyTank() {//控制 发射子弹if (shots.size() == 5) {return;}switch (getDirection()) {case 0:shot = new Shot(getX() + 20, getY(), 0);break;case 1:shot = new Shot(getX() + 60, getY() + 20, 1);break;case 2:shot = new Shot(getX() + 20, getY() + 60, 2);break;case 3:shot = new Shot(getX(), getY() + 20, 3);break;default:break;}//把新创建的shot 放入 shots 中shots.add(shot);//启动Shot线程new Thread(shot).start();}}

EnemyTank 敌方坦克类

package com.liner.tankGame;import java.util.Vector;/*** 敌方坦克** @author 一条淡水鱼 ゆ* on 2023-03-07*/
public class EnemyTank extends Tank implements Runnable {/*** 在敌人坦克类中 存放多个Shot*/Vector<Shot> shots = new Vector<>();/*** EnemyTank 可以得到敌人坦克的 Vector*/Vector<EnemyTank> enemyTanks = new Vector<>();boolean isLive = true;public EnemyTank(int x, int y) {super(x, y);}public Vector<EnemyTank> getEnemyTanks() {return enemyTanks;}/*** 提供一个方法 可以将 MyPanel的成员  Vector<EnemyTank> enemyTanks = new Vector<>();* 设置到 EnemyTank 的成员 enemyTanks** @param enemyTanks 敌人坦克集合*/public void setEnemyTanks(Vector<EnemyTank> enemyTanks) {this.enemyTanks = enemyTanks;}/*** 编写方法 判断当前敌人坦克是否和 enemyTanks 的其他坦克发生 重叠 或者 碰撞*/public boolean isTouchEnemyTank() {//判断当前敌人坦克(this)的方向switch (this.getDirection()) {case 0://让当前敌人坦克和其他所有坦克进行比较for (int i = 0; i < enemyTanks.size(); i++) {//从 Vector 中 取出一个敌人坦克EnemyTank enemyTank = enemyTanks.get(i);//不和自己比较if (enemyTank != this) {//如果敌人坦克是 上/下//敌人是上/下 x的范围:[enemyTank.getX(),enemyTank.getX() + 40]//          y的范围:[enemyTank.getY(),enemyTank.getY() + 60]if (enemyTank.getDirection() == 0 || enemyTank.getDirection() == 2) {//当前坦克 左上角坐标 [this.getX(), this.getY()]if (this.getX() >= enemyTank.getX() && this.getX() <= enemyTank.getX() + 40&& this.getY() >= enemyTank.getY() && this.getY() <= enemyTank.getY() + 60) {return true;}//当前坦克 右上角坐标 [this.getX() + 40, this.getY()]if (this.getX() + 40 >= enemyTank.getX() && this.getX() + 40 <= enemyTank.getX() + 40&& this.getY() >= enemyTank.getY() && this.getY() <= enemyTank.getY() + 60) {return true;}}//如果敌人坦克是 左/右//敌人是左/右 x的范围:[enemyTank.getX(),enemyTank.getX() + 60]//          y的范围:[enemyTank.getY(),enemyTank.getY() + 40]if (enemyTank.getDirection() == 1 || enemyTank.getDirection() == 3) {//当前坦克 左上角坐标 [this.getX(), this.getY()]if (this.getX() >= enemyTank.getX() && this.getX() <= enemyTank.getX() + 60&& this.getY() >= enemyTank.getY() && this.getY() <= enemyTank.getY() + 40) {return true;}//当前坦克 右上角坐标 [this.getX() + 40, this.getY()]if (this.getX() + 40 >= enemyTank.getX() && this.getX() + 40 <= enemyTank.getX() + 60&& this.getY() >= enemyTank.getY() && this.getY() <= enemyTank.getY() + 40) {return true;}}}}break;case 1://让当前敌人坦克和其他所有坦克进行比较for (int i = 0; i < enemyTanks.size(); i++) {//从 Vector 中 取出一个敌人坦克EnemyTank enemyTank = enemyTanks.get(i);//不和自己比较if (enemyTank != this) {//如果敌人坦克是 上/下//敌人是上/下 x的范围:[enemyTank.getX(),enemyTank.getX() + 40]//          y的范围:[enemyTank.getY(),enemyTank.getY() + 60]if (enemyTank.getDirection() == 0 || enemyTank.getDirection() == 2) {//当前坦克 右上角坐标 [this.getX() + 60, this.getY()]if (this.getX() + 60 >= enemyTank.getX() && this.getX() + 60 <= enemyTank.getX() + 40&& this.getY() >= enemyTank.getY() && this.getY() <= enemyTank.getY() + 60) {return true;}//当前坦克 右下角坐标 [this.getX() + 60, this.getY() + 40]if (this.getX() + 60 >= enemyTank.getX() && this.getX() + 60 <= enemyTank.getX() + 40&& this.getY() + 40 >= enemyTank.getY() && this.getY() + 40 <= enemyTank.getY() + 60) {return true;}}//如果敌人坦克是 左/右//敌人是左/右 x的范围:[enemyTank.getX(),enemyTank.getX() + 60]//          y的范围:[enemyTank.getY(),enemyTank.getY() + 40]if (enemyTank.getDirection() == 1 || enemyTank.getDirection() == 3) {//当前坦克 右上角坐标 [this.getX() + 60, this.getY()]if (this.getX() + 60 >= enemyTank.getX() && this.getX() + 60 <= enemyTank.getX() + 60&& this.getY() >= enemyTank.getY() && this.getY() <= enemyTank.getY() + 40) {return true;}//当前坦克 右下角坐标 [this.getX() + 60, this.getY() + 40]if (this.getX() + 60 >= enemyTank.getX() && this.getX() + 60 <= enemyTank.getX() + 60&& this.getY() + 40 >= enemyTank.getY() && this.getY() + 40 <= enemyTank.getY() + 40) {return true;}}}}break;case 2://让当前敌人坦克和其他所有坦克进行比较for (int i = 0; i < enemyTanks.size(); i++) {//从 Vector 中 取出一个敌人坦克EnemyTank enemyTank = enemyTanks.get(i);//不和自己比较if (enemyTank != this) {//如果敌人坦克是 上/下//敌人是上/下 x的范围:[enemyTank.getX(),enemyTank.getX() + 40]//          y的范围:[enemyTank.getY(),enemyTank.getY() + 60]if (enemyTank.getDirection() == 0 || enemyTank.getDirection() == 2) {//当前坦克 左下角坐标 [this.getX(), this.getY() + 60]if (this.getX() >= enemyTank.getX() && this.getX() <= enemyTank.getX() + 40&& this.getY() + 60 >= enemyTank.getY() && this.getY() + 60 <= enemyTank.getY() + 60) {return true;}//当前坦克 右下角坐标 [this.getX() + 40, this.getY() + 60]if (this.getX() + 40 >= enemyTank.getX() && this.getX() + 40 <= enemyTank.getX() + 40&& this.getY() + 60 >= enemyTank.getY() && this.getY() + 60 <= enemyTank.getY() + 60) {return true;}}//如果敌人坦克是 左/右//敌人是左/右 x的范围:[enemyTank.getX(),enemyTank.getX() + 60]//          y的范围:[enemyTank.getY(),enemyTank.getY() + 40]if (enemyTank.getDirection() == 1 || enemyTank.getDirection() == 3) {//当前坦克 左下角坐标 [this.getX(), this.getY() + 60]if (this.getX() >= enemyTank.getX() && this.getX() <= enemyTank.getX() + 60&& this.getY() + 60 >= enemyTank.getY() && this.getY() + 60 <= enemyTank.getY() + 40) {return true;}//当前坦克 右下角坐标 [this.getX() + 40, this.getY() + 60]if (this.getX() + 40 >= enemyTank.getX() && this.getX() + 40 <= enemyTank.getX() + 60&& this.getY() + 60 >= enemyTank.getY() && this.getY() + 60 <= enemyTank.getY() + 40) {return true;}}}}break;case 3://让当前敌人坦克和其他所有坦克进行比较for (int i = 0; i < enemyTanks.size(); i++) {//从 Vector 中 取出一个敌人坦克EnemyTank enemyTank = enemyTanks.get(i);//不和自己比较if (enemyTank != this) {//如果敌人坦克是 上/下//敌人是上/下 x的范围:[enemyTank.getX(),enemyTank.getX() + 40]//          y的范围:[enemyTank.getY(),enemyTank.getY() + 60]if (enemyTank.getDirection() == 0 || enemyTank.getDirection() == 2) {//当前坦克 左上角坐标 [this.getX(), this.getY()]if (this.getX() >= enemyTank.getX() && this.getX() <= enemyTank.getX() + 40&& this.getY() >= enemyTank.getY() && this.getY() <= enemyTank.getY() + 60) {return true;}//当前坦克 左下角坐标 [this.getX(), this.getY() + 40]if (this.getX() >= enemyTank.getX() && this.getX() <= enemyTank.getX() + 40&& this.getY() + 40 >= enemyTank.getY() && this.getY() + 40 <= enemyTank.getY() + 60) {return true;}}//如果敌人坦克是 左/右//敌人是左/右 x的范围:[enemyTank.getX(),enemyTank.getX() + 60]//          y的范围:[enemyTank.getY(),enemyTank.getY() + 40]if (enemyTank.getDirection() == 1 || enemyTank.getDirection() == 3) {//当前坦克 左上角坐标 [this.getX(), this.getY()]if (this.getX() >= enemyTank.getX() && this.getX() <= enemyTank.getX() + 60&& this.getY() >= enemyTank.getY() && this.getY() <= enemyTank.getY() + 40) {return true;}//当前坦克 左下角坐标 [this.getX(), this.getY() + 40]if (this.getX() >= enemyTank.getX() && this.getX() <= enemyTank.getX() + 60&& this.getY() + 40 >= enemyTank.getY() && this.getY() + 40 <= enemyTank.getY() + 40) {return true;}}}}break;default:break;}return false;}/*** 让敌方坦克可以自由移动*/@Overridepublic void run() {while (true) {//判断 如果 shots.size() == 0 说明集合中没子弹了if (isLive && shots.size() < 5) {//判断 敌方坦克的方向 创建对应子弹位置Shot shot = null;switch (getDirection()) {case 0:shot = new Shot(getX() + 20, getY(), 0);break;case 1:shot = new Shot(getX() + 60, getY() + 20, 1);break;case 2:shot = new Shot(getX() + 20, getY() + 60, 2);break;case 3:shot = new Shot(getX(), getY() + 20, 3);break;default:break;}//把新创建的shot 放入 shots 中shots.add(shot);//启动Shot线程new Thread(shot).start();}//根据坦克方向进行移动switch (getDirection()) {case 0:for (int i = 0; i < 30; i++) {if (getY() > 0 && !isTouchEnemyTank()) {moveUp();}try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}}break;case 1:for (int i = 0; i < 30; i++) {if (getX() + 60 < 1000 && !isTouchEnemyTank()) {moveRight();}try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}}break;case 2:for (int i = 0; i < 30; i++) {if (getY() + 110 < 750 && !isTouchEnemyTank()) {moveDown();}try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}}break;case 3:for (int i = 0; i < 30; i++) {if (getX() > 0 && !isTouchEnemyTank()) {moveLeft();}try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}}break;default:break;}//休眠50mstry {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}//随机返回坦克方向  [0,4)   Math.random() 取随机数,范围[0,1)setDirection((int) (Math.random() * 4));//写并发程序时一定注意,线程什么时候能结束//当敌方坦克不再存活,则退出线程if (!isLive) {break;}}}
}

Node 记录敌方坦克类

package com.liner.tankGame;/*** 一个Node对象 表示一个敌人坦克的信息** @author 一条淡水鱼 ゆ* on 2023-03-08*/
public class Node {private int x;private int y;private int direction;public Node(int x, int y, int direction) {this.x = x;this.y = y;this.direction = direction;}public int getX() {return x;}public void setX(int x) {this.x = x;}public int getY() {return y;}public void setY(int y) {this.y = y;}public int getDirection() {return direction;}public void setDirection(int direction) {this.direction = direction;}}

Recoder 记录游戏数据类

package com.liner.tankGame;import java.io.*;
import java.util.Vector;/*** 记录游戏数据类** @author 一条淡水鱼 ゆ* on 2023-03-08*/
public class Recorder {/*** 定义变量,记录我方击毁敌人坦克数量*/private static int allEnemyTankTotal = 0;/*** 定义IO 对象,准备写数据到文件中*/private static BufferedWriter bufferedWriter = null;private static BufferedReader bufferedReader = null;private static String recordFile = "E:\\TeduWork\\Bootcamp\\Tank\\src\\com\\liner\\tankGame\\record.txt";/*** 存储敌人坦克*/private static Vector<EnemyTank> enemyTanks = null;/*** 定义一个Node 的Vector ,用于保存敌人的信息node*/private static Vector<Node> nodes = new Vector<>();/*** 该方法在继续上局时调用* 用于读取record.txt 文件,恢复相关信息** @return 敌人坦克信息*/public static Vector<Node> getNodesAndTanks() {try {bufferedReader = new BufferedReader(new FileReader(recordFile));//击毁数量allEnemyTankTotal = Integer.parseInt(bufferedReader.readLine());//获取敌人坦克信息String dataLine = "";while ((dataLine = bufferedReader.readLine()) != null) {String[] split = dataLine.split(" ");if (split.length == 3) {Node node = new Node(Integer.parseInt(split[0]), Integer.parseInt(split[1]), Integer.parseInt(split[2]));nodes.add(node);}}} catch (Exception e) {e.printStackTrace();} finally {if (bufferedReader != null) {try {bufferedReader.close();} catch (IOException e) {e.printStackTrace();}}}return nodes;}public static void setEnemyTanks(Vector<EnemyTank> enemyTanks) {Recorder.enemyTanks = enemyTanks;}public static int getAllEnemyTankTotal() {return allEnemyTankTotal;}public static void setAllEnemyTankTotal(int allEnemyTankTotal) {Recorder.allEnemyTankTotal = allEnemyTankTotal;}/*** 当我方坦克击毁一辆敌人坦克,就应当对这个值++*/public static void addAllEnemyTankTotal() {Recorder.allEnemyTankTotal++;}/*** 当游戏退出时,我们将 allEnemyTankTotal 保存到*/public static void keepRecord() {try {bufferedWriter = new BufferedWriter(new FileWriter(recordFile));bufferedWriter.write(allEnemyTankTotal + "\r\n");//遍历敌人坦克集合,然后根据情况保存//OOP 编程思想,定义一个属性,通过SET 方法得到敌人的坦克集合if (enemyTanks.size() > 0) {for (int i = 0; i < enemyTanks.size(); i++) {EnemyTank enemyTank = enemyTanks.get(i);//为了保险,判断一下是否存活if (enemyTank.isLive) {//保存enemy坦克信息String record = enemyTank.getX() + " " + enemyTank.getY() + " " + enemyTank.getDirection();bufferedWriter.write(record);bufferedWriter.newLine();}}}} catch (Exception e) {e.printStackTrace();} finally {if (bufferedWriter != null) {try {bufferedWriter.close();} catch (IOException e) {e.printStackTrace();}}}}public static String getRecordFile() {return recordFile;}public static void setRecordFile(String recordFile) {Recorder.recordFile = recordFile;}
}

Shot 子弹类

package com.liner.tankGame;/*** 绘制子弹模型** @author 一条淡水鱼 ゆ* on 2023-03-07*/
public class Shot implements Runnable {int x, y;private int direction = 0;private int speed = 2;boolean isLive = true;public Shot(int x, int y, int direction) {this.x = x;this.y = y;this.direction = direction;}@Overridepublic void run() {while (true) {//休眠50mstry {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}//根据方向改变x,y坐标switch (direction) {case 0:y -= speed;break;case 1:x += speed;break;case 2:y += speed;break;case 3:x -= speed;break;default:break;}//当子弹移动到面板边界爆炸if (!(x >= 0 && y >= 0 && x <= 1000 && y <= 750 && isLive)) {isLive = false;break;}}}
}

Tank 坦克父类

package com.liner.tankGame;/*** 绘制坦克模型** @author 一条淡水鱼 ゆ* on 2023-03-07*/
public class Tank {/*** 横纵坐标*/private int x, y;/*** 方向*/private int direction = 0;/*** 速度*/private int speed = 3;/*** 存活状态*/boolean isLive = true;/*** 上下左右移动的方法*/public void moveUp() {y -= speed;}/*** 上下左右移动的方法*/public void moveDown() {y += speed;}/*** 上下左右移动的方法*/public void moveLeft() {x -= speed;}/*** 上下左右移动的方法*/public void moveRight() {x += speed;}public Tank(int x, int y) {this.x = x;this.y = y;}public int getSpeed() {return speed;}public void setSpeed(int speed) {this.speed = speed;}public int getDirection() {return direction;}public void setDirection(int direction) {this.direction = direction;}public int getX() {return x;}public void setX(int x) {this.x = x;}public int getY() {return y;}public void setY(int y) {this.y = y;}
}

AePlayWave 播放器背景音乐类

package com.liner.tankGame;import javax.sound.sampled.*;
import java.io.File;
import java.io.IOException;/*** @author 韩顺平* @version 1.0*/
public class AePlayWave extends Thread {private String filename;public AePlayWave(String wavfile) {filename = wavfile;}public void run() {File soundFile = new File(filename);AudioInputStream audioInputStream = null;try {audioInputStream = AudioSystem.getAudioInputStream(soundFile);} catch (Exception e1) {e1.printStackTrace();return;}AudioFormat format = audioInputStream.getFormat();SourceDataLine auline = null;DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);try {auline = (SourceDataLine) AudioSystem.getLine(info);auline.open(format);} catch (Exception e) {e.printStackTrace();return;}auline.start();int nBytesRead = 0;//这是缓冲byte[] abData = new byte[512];try {while (nBytesRead != -1) {nBytesRead = audioInputStream.read(abData, 0, abData.length);if (nBytesRead >= 0)auline.write(abData, 0, nBytesRead);}} catch (IOException e) {e.printStackTrace();return;} finally {auline.drain();auline.close();}}
}

坦克大战 —— 韩顺平相关推荐

  1. 韩顺平 java坦克大战_坦克大战完整版(韩顺平java)

    [实例简介] 坦克大战完整源代码(韩顺平java视频配套) [实例截图] [核心代码] 5i86q5 └── 源码 └── Class14 ├── 111.wav ├── bin │   ├── bo ...

  2. 韩顺平老师坦克大战项目总结

    韩顺平老师讲的坦克大战项目,用代码进行了复现,有几个自己的总结 1 有个别功能没有实现,EnemyTank中敌人坦克向四周移动功能没有实现,只是实现了随机转向,但一直停在原地不动,没有找到bug所在. ...

  3. JavaStudy7(18章-坦克大战2)—B站韩顺平

    JavaStudy7(18章-坦克大战2)-B站韩顺平 1.坦克大战 1.1线程-应用到坦克大战 1.1.1 坦克大战 0.3 代码演示: //为了监听 键盘事件, 实现 KeyListener pu ...

  4. JavaStudy5(坦克大战)—B站韩顺平

    JavaStudy5(坦克大战01)-B站韩顺平 跳转坦克大战02: 跳转坦克大战03: 1. 坦克大战 1.1坦克大战游戏演示 1.1.1游戏演示 1.1.2 为什么写这个项目 1.1.3 写项目前 ...

  5. Java坦克大战 跟学韩顺平老师视频开发

    这里写目录标题 TankBigWarGame 介绍 界面展示 项目架构 安装教程 游戏说明 项目涉及技术功能 游戏结束判断 项目不足与优化空间 相关代码展示 主方法Main 绘图界面 MyPanelF ...

  6. 韩顺平老师坦克大战优化版

    一.项目介绍 1.前言 基于韩顺平老师坦克大战的框架和思路,进行了一些优化.编码上尽量按照阿里的代码规约:有非常详尽的注释:引入了线程池,线程安全集合类,原子类等:通过这个小项目的学习,可以深入地理解 ...

  7. 韩顺平java基础——坦克大战(含有线程、I\O流的讲解)

    写在最前边: 研究生一枚,为后端实习和未来工作打基础.无意间发现韩顺平老师的课程,细心细致,讲课和吴恩达老师一样,都是保姆式讲解,各种基础知识都会补充,爱了. 韩顺平老师课程地址:https://ww ...

  8. b站韩顺平老师的坦克大战

    一.主要的几个类 Mypanel WwyTankGame01 AnemyTank //写代码时候把单词拼错了哈哈不好意思 Bomb Recorder Node Shot Tank Hero 二.功能实 ...

  9. 韩老师坦克大战2.0版本

    本博文源于对b站视频韩老师(韩顺平)的java学习,本章学习坦克大战2.0版本,用多线程实现,本章内容还是比较多的,先看内容效果 内容效果 开局 被打死(黄色是hero) 打死别人 源码 Bomb.j ...

最新文章

  1. 使用Apache CXF进行Web服务学习
  2. fail2ban封IP之Http
  3. 修改TFS与本地源代码映射路径
  4. python实现冒泡排序算法的非递归版本_冒泡排序以及python代码实现(递归+非递归)...
  5. 学习Numpy,看这篇文章就够啦
  6. cookie工作流程
  7. 查看、修改linux系统的最大链接数限制、文件描述符限制、端口范围限制、虚拟内存等
  8. mysql 减去_MySql进阶面试题
  9. android theme错误,关于android:您需要在此活动中使用Theme.AppCompat主题(或后代)。 更改为Theme.AppCompat会导致其他错误...
  10. VS Code中适用于任何中文字体的中英文混合等宽显示的配置方案
  11. gitlab hook declined错误
  12. 计算机没有autoCAD_《AutoCAD三维设计环境》
  13. 今年的金德值得期待的人物_原水_新浪博客
  14. Educoder---Java继承与接口、文件
  15. 微信小程序下载二进制流图片并转base64位图为png格式
  16. 计算机优化英语课堂教学,巧用平板,让课堂不平凡———平板电脑在小学中年级段英语课堂教学中的应用...
  17. python %d, %f, %s占位符的使用(学习笔记)
  18. 【SpringCloud】微服务笔记
  19. Tita: 在教育科技公司成功实施 OKR
  20. 2021.1山科马原大题

热门文章

  1. 音频工程,语音识别,语音学,机器学习相关网站和资料
  2. myql 查询树形表结果:说说、说说的评论、评论的回复
  3. ubuntu连接xp的共享打印机
  4. [SVA]SystemVerilog Assertion常用操作符总结及案例
  5. 基于 next.js + mdx 搭建组件库文档项目(一) -- 开发环境搭建
  6. 黑鲨鸿蒙系统手机,黑鲨4代参数_黑鲨4代手机参数配置
  7. 清华系激光雷达公司,成了量产元年最大的黑马
  8. 2021年在全球及中国卫星发射数量、在轨卫星及市场规模分析[图]
  9. 使用Oracle Enterprise Manager波折记录
  10. Dokuwiki模版Vector使用总结