坦克大战 —— 韩顺平
坦克大战
项目来自 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();}}
}
坦克大战 —— 韩顺平相关推荐
- 韩顺平 java坦克大战_坦克大战完整版(韩顺平java)
[实例简介] 坦克大战完整源代码(韩顺平java视频配套) [实例截图] [核心代码] 5i86q5 └── 源码 └── Class14 ├── 111.wav ├── bin │ ├── bo ...
- 韩顺平老师坦克大战项目总结
韩顺平老师讲的坦克大战项目,用代码进行了复现,有几个自己的总结 1 有个别功能没有实现,EnemyTank中敌人坦克向四周移动功能没有实现,只是实现了随机转向,但一直停在原地不动,没有找到bug所在. ...
- JavaStudy7(18章-坦克大战2)—B站韩顺平
JavaStudy7(18章-坦克大战2)-B站韩顺平 1.坦克大战 1.1线程-应用到坦克大战 1.1.1 坦克大战 0.3 代码演示: //为了监听 键盘事件, 实现 KeyListener pu ...
- JavaStudy5(坦克大战)—B站韩顺平
JavaStudy5(坦克大战01)-B站韩顺平 跳转坦克大战02: 跳转坦克大战03: 1. 坦克大战 1.1坦克大战游戏演示 1.1.1游戏演示 1.1.2 为什么写这个项目 1.1.3 写项目前 ...
- Java坦克大战 跟学韩顺平老师视频开发
这里写目录标题 TankBigWarGame 介绍 界面展示 项目架构 安装教程 游戏说明 项目涉及技术功能 游戏结束判断 项目不足与优化空间 相关代码展示 主方法Main 绘图界面 MyPanelF ...
- 韩顺平老师坦克大战优化版
一.项目介绍 1.前言 基于韩顺平老师坦克大战的框架和思路,进行了一些优化.编码上尽量按照阿里的代码规约:有非常详尽的注释:引入了线程池,线程安全集合类,原子类等:通过这个小项目的学习,可以深入地理解 ...
- 韩顺平java基础——坦克大战(含有线程、I\O流的讲解)
写在最前边: 研究生一枚,为后端实习和未来工作打基础.无意间发现韩顺平老师的课程,细心细致,讲课和吴恩达老师一样,都是保姆式讲解,各种基础知识都会补充,爱了. 韩顺平老师课程地址:https://ww ...
- b站韩顺平老师的坦克大战
一.主要的几个类 Mypanel WwyTankGame01 AnemyTank //写代码时候把单词拼错了哈哈不好意思 Bomb Recorder Node Shot Tank Hero 二.功能实 ...
- 韩老师坦克大战2.0版本
本博文源于对b站视频韩老师(韩顺平)的java学习,本章学习坦克大战2.0版本,用多线程实现,本章内容还是比较多的,先看内容效果 内容效果 开局 被打死(黄色是hero) 打死别人 源码 Bomb.j ...
最新文章
- 使用Apache CXF进行Web服务学习
- fail2ban封IP之Http
- 修改TFS与本地源代码映射路径
- python实现冒泡排序算法的非递归版本_冒泡排序以及python代码实现(递归+非递归)...
- 学习Numpy,看这篇文章就够啦
- cookie工作流程
- 查看、修改linux系统的最大链接数限制、文件描述符限制、端口范围限制、虚拟内存等
- mysql 减去_MySql进阶面试题
- android theme错误,关于android:您需要在此活动中使用Theme.AppCompat主题(或后代)。 更改为Theme.AppCompat会导致其他错误...
- VS Code中适用于任何中文字体的中英文混合等宽显示的配置方案
- gitlab hook declined错误
- 计算机没有autoCAD_《AutoCAD三维设计环境》
- 今年的金德值得期待的人物_原水_新浪博客
- Educoder---Java继承与接口、文件
- 微信小程序下载二进制流图片并转base64位图为png格式
- 计算机优化英语课堂教学,巧用平板,让课堂不平凡———平板电脑在小学中年级段英语课堂教学中的应用...
- python %d, %f, %s占位符的使用(学习笔记)
- 【SpringCloud】微服务笔记
- Tita: 在教育科技公司成功实施 OKR
- 2021.1山科马原大题
热门文章
- 音频工程,语音识别,语音学,机器学习相关网站和资料
- myql 查询树形表结果:说说、说说的评论、评论的回复
- ubuntu连接xp的共享打印机
- [SVA]SystemVerilog Assertion常用操作符总结及案例
- 基于 next.js + mdx 搭建组件库文档项目(一) -- 开发环境搭建
- 黑鲨鸿蒙系统手机,黑鲨4代参数_黑鲨4代手机参数配置
- 清华系激光雷达公司,成了量产元年最大的黑马
- 2021年在全球及中国卫星发射数量、在轨卫星及市场规模分析[图]
- 使用Oracle Enterprise Manager波折记录
- Dokuwiki模版Vector使用总结