https://www.bloghut.cn/questionBank

链接: 面试题库

1、说明

  写了14个版本,终于完成了,项目结构如下

2、游戏效果


(1)击中敌人

(2)被敌人击中

3、代码如下

(1)TankGame 主方法

package cn.bloghut;import cn.bloghut.component.MyPanel;
import cn.bloghut.service.Recorder;import javax.swing.*;
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.Scanner;/*** @Classname TankGame* @Description TODO* @Date 2022/5/8 8:25* @Created by 闲言*/
public class TankGame extends JFrame {private MyPanel panel;public static void main(String[] args) {new TankGame();}public TankGame(){System.out.println("请输入选择: 1 表示新游戏,2是继续上局");Scanner scanner = new Scanner(System.in);//将panel放入到thread中this.panel = new MyPanel(scanner.next());scanner.close();new Thread(panel).start();//设置绑定监听器this.addKeyListener(panel);this.add(panel);//设置窗体关闭this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);this.setTitle("闲言-坦克大战");//获取当前屏幕分辨率int width = Toolkit.getDefaultToolkit().getScreenSize().width;int height = Toolkit.getDefaultToolkit().getScreenSize().height;//设置窗体大小不可变this.setResizable(false);//设置窗体位置width = (width - 1300) / 2;height = (height - 750) / 2;this.setBounds(width,height,1300,750);this.setBackground(Color.black);//设置窗体显示this.setVisible(true);//在JFrame 中增加相关关闭窗口的处理this.addWindowListener(new WindowAdapter() {@Overridepublic void windowClosing(WindowEvent e) {Recorder.keepRecord();System.exit(0);}});}
}

(2)MyPanel 视图

package cn.bloghut.component;import cn.bloghut.pojo.*;
import cn.bloghut.service.PlayAudio;
import cn.bloghut.service.Recorder;
import cn.bloghut.service.Shot;import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.File;
import java.util.Vector;/*** @Classname MyPanel* @Description 坦克大战绘图区域* 为了让panel 不停的重绘子弹,需要将MyPanel* @Date 2022/5/8 8:44* @Created by 闲言*/
public class MyPanel extends JPanel implements KeyListener, Runnable {//定义我的坦克Hero hero = null;//定义敌人坦克Vector<EnemyTank> enemyTanks = new Vector<>();//用于存放炸弹//当子弹击中坦克时,就加入一个bomb 对象Vector<Bomb> bombs = new Vector<>();//定义三种图片,用于显示炸弹Image img1 = null;Image img2 = null;Image img3 = null;//定义一个存放Node 对象的Vector,用于恢复敌人坦克的坐标和放向Vector<Node> nodes = null;//敌人坦克数量int enemyTankSize = 3;public MyPanel(String type) {//判断记录文件是否存在//如果存在就正常执行,如果文件不存在,提示只能开启新的游戏File file = new File(Recorder.getRecordFile());if (!file.exists()){type = "1";System.out.println("文件不存在只能开启新游戏");}else {nodes = Recorder.getNodesAndTanks();}//初始化我的坦克hero = new Hero(150, 150);//设置坦克速度hero.setSpeed(5);switch (type) {case "1"://初始化敌人坦克for (int i = 0; i < enemyTankSize; i++) {EnemyTank enemyTank = new EnemyTank(100 * (i + 1), 0);enemyTank.setDirection(2);//启动敌人坦克线程new Thread(enemyTank).start();//给该enemyTank 加入一颗子弹Shot shot = new Shot(enemyTank.getX() + 20, enemyTank.getY() + 60, enemyTank.getDirection());//加入到enemyTank.getShots().add(shot);//为每个坦克,放入所有的敌人对象enemyTank.setEnemyTanks(enemyTanks);//启动shotnew 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());//启动敌人坦克线程new Thread(enemyTank).start();//给该enemyTank 加入一颗子弹Shot shot = new Shot(enemyTank.getX() + 20, enemyTank.getY() + 60, enemyTank.getDirection());//加入到enemyTank.getShots().add(shot);//为每个坦克,放入所有的敌人对象enemyTank.setEnemyTanks(enemyTanks);//启动shotnew Thread(shot).start();enemyTanks.add(enemyTank);}break;default:System.out.println("你的输入有误");}//获取项目路径//1.获取图片资源String parent = System.getProperty("user.dir");parent += "\\";//2.初始化图片img1 = Toolkit.getDefaultToolkit().getImage(parent + "bomb_1.gif");img2 = Toolkit.getDefaultToolkit().getImage(parent + "bomb_2.gif");img3 = Toolkit.getDefaultToolkit().getImage(parent + "bomb_3.gif");//存放敌人坦克信息Recorder.setEnemyTanks(enemyTanks);//播放指定的音乐new PlayAudio("bg.wav").start();}@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);}//画出自己射击的子弹//不为空,且处于发射状态if (hero.getShot() != null && hero.getShot().isLive()) {g.draw3DRect(hero.getShot().getX(), hero.getShot().getY(), 2, 2, false);}if (hero.getShots().size() > 0) {for (int i = 0; i < hero.getShots().size(); i++) {Shot shot = hero.getShots().get(i);if (shot != null && shot.isLive()) {g.draw3DRect(shot.getX(), shot.getY(), 2, 2, false);} else {//如果shot对象已经无效,就从子弹集合中移除hero.getShots().remove(shot);}}}//画敌人坦克for (int i = 0; i < enemyTanks.size(); i++) {EnemyTank enemyTank = enemyTanks.get(i);//判断当前坦克是否还存活,只有存活的时候才去画if (enemyTank.isLive()) {drawTank(enemyTank.getX(), enemyTank.getY(), g, enemyTank.getDirection(), 0);//绘制敌人坦克子弹Vector<Shot> shots = enemyTank.getShots();for (int j = 0; j < shots.size(); j++) {Shot shot = shots.get(j);//子弹存活的时候才绘制if (shot.isLive()) {g.draw3DRect(shot.getX(), shot.getY(), 1, 1, false);} else {//子弹出边界了,移除子弹enemyTank.getShots().remove(shot);}}}}//如果bombs 集合中有对象,就画出for (int i = 0; i < bombs.size(); i++) {Bomb bomb = bombs.get(i);//根据当前炸弹的life值画出对应的图片if (bomb.getLife() > 6) {g.drawImage(img1, bomb.getX(), bomb.getY(), 60, 60, this);} else if (bomb.getLife() > 3) {g.drawImage(img2, bomb.getX(), bomb.getY(), 60, 60, this);} else {g.drawImage(img3, bomb.getX(), bomb.getY(), 60, 60, this);}//让这个炸弹的生命值减少bomb.lifeDown();//如果bomb 生命值为0,就从集合中删除if (bomb.getLife() == 0) {bombs.remove(bomb);}}}/*** 显示 击毁敌方的坦克信息** @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, 0);g.setColor(Color.BLACK);g.drawString(Recorder.getAllEnemyTankTotal() + "", 1080, 100);}/*** 绘制坦克** @param x         坦克的左上角x坐标* @param y         坦克的左上角y坐标* @param g         画笔* @param direction 坦克方向(上下左右)* @param type      坦克类型*/public void drawTank(int x, int y, Graphics g, int direction, int type) {//根据不同类型的坦克设置不同颜色switch (type) {case 0://0 敌人的坦克g.setColor(Color.cyan);break;//case 1://1 我们的坦克g.setColor(Color.yellow);break;}//根据坦克的方向来绘制坦克//direction 0-向上,1-向右,2-向下,3-向左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:System.out.println("暂时没有处理");}}@Overridepublic void keyTyped(KeyEvent e) {}@Overridepublic void keyPressed(KeyEvent e) {int code = e.getKeyCode();//判断用户按下的按键if (KeyEvent.VK_W == code) { //向上//移动时判断不能重叠hero.setDirection(0);hero.moveUp();} else if (KeyEvent.VK_D == code) { //向右hero.setDirection(1);hero.moveRight();} else if (KeyEvent.VK_S == code) { //向下hero.setDirection(2);hero.moveDown();} else if (KeyEvent.VK_A == code) { //向左hero.setDirection(3);hero.moveLeft();}//判断是否是射击if (KeyEvent.VK_J == code) {//如果为空,说明是第一次发射//发送一颗子弹
//            if (hero.getShot() == null || !(hero.getShot().isLive())){//                hero.shotEnemyTank();
//            }//发射多颗子弹hero.shotEnemyTank();}//重绘this.repaint();}//如果我们的坦克可以发射多发子弹//在判断我方子弹是否击中敌人坦克时,就需要把我们的子弹集合所有的子弹取出,都取出和敌人的所有坦克进行判断//编写方法,判断我方的子弹是否击中敌人坦克/*** 判断子弹和坦克** @param shots 子弹集合* @param tank  坦克*/public void hitTank(Vector<Shot> shots, Tank tank) {for (int i = 0; i < shots.size(); i++) {hitTank(shots.get(i), tank);}}/*** 判断子弹和坦克** @param s    子弹* @param tank 坦克*/public void hitTank(Shot s, Tank tank) {switch (tank.getDirection()) {case 0://坦克向上case 2://坦克向下if (s.getX() > tank.getX() && s.getX() < tank.getX() + 40 &&s.getY() > tank.getY() && s.getY() < tank.getY() + 60) {s.setLive(false);tank.setLive(false);//当我的子弹击中敌人坦克后,将enemyTank 坦克从集合中去掉enemyTanks.remove(tank);//当我方击毁一辆敌方坦克时,就对一个值++(前提不是我放坦克)if (!(tank instanceof Hero)) {Recorder.addlEnemyTankTotal();}//创建bomb对象,加入到bombs集合Bomb bomb = new Bomb(tank.getX(), tank.getY());bombs.add(bomb);}break;case 1://坦克向右case 3://坦克向左if (s.getX() > tank.getX() && s.getX() < tank.getX() + 60 &&s.getY() > tank.getY() && s.getY() < tank.getY() + 40) {s.setLive(false);tank.setLive(false);//打我的子弹击中敌人坦克后,将enemyTank 坦克从集合中去掉enemyTanks.remove(tank);//当我方击毁一辆敌方坦克时,就对一个值++(前提不是我放坦克)if (!(tank instanceof Hero)) {Recorder.addlEnemyTankTotal();}//创建bomb对象,加入到bombs集合Bomb bomb = new Bomb(tank.getX(), tank.getY());bombs.add(bomb);}break;}}@Overridepublic void keyReleased(KeyEvent e) {}@Overridepublic void run() {//每隔100毫秒,重绘区域while (true) {try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}//判断是否击中敌人坦克hitEnemy();//判断敌人坦克是否击中我们hitHero();this.repaint();}}/*** 判断是否击中敌人坦克*/public void hitEnemy() {if (hero.getShot() != null && hero.getShot().isLive()) {//遍历敌人所有的坦克for (int i = 0; i < enemyTanks.size(); i++) {EnemyTank enemyTank = enemyTanks.get(i);//发射单个子弹
//                    hitTank(hero.getShot(),enemyTank);//发射多颗子弹hitTank(hero.getShots(), enemyTank);}}}/*** 判断敌人坦克是否击中*/public void hitHero() {if (enemyTanks.size() > 0) {//拿到所有敌人的坦克-下的子弹,判断是否重合如果重合则显示爆炸for (int i = 0; i < enemyTanks.size(); i++) {EnemyTank enemyTank = enemyTanks.get(i);//判断是否击中//敌人的子弹Vector<Shot> shots = enemyTank.getShots();if (shots.size() > 0) {for (int j = 0; j < shots.size(); j++) {Shot shot = shots.get(j);if (hero.isLive() && shot.isLive()) {//判断子弹和坦克是否重合hitTank(shots, hero);}}}}}}
}

(3)Bomb 爆炸类

package cn.bloghut.pojo;/*** @Classname Bomb* @Description TODO* @Date 2022/5/8 16:18* @Created by 闲言*/
public class Bomb {private int x,y;//炸弹坐标private int life = 9;//炸弹生命周期private  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;}}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 getLife() {return life;}public void setLife(int life) {this.life = life;}public boolean isLive() {return isLive;}public void setLive(boolean live) {isLive = live;}
}

(4)EnemyTank 敌方坦克类

package cn.bloghut.pojo;import cn.bloghut.service.Shot;import java.util.Vector;/*** @Classname EnemyTank* @Description TODO* @Date 2022/5/8 11:06* @Created by 闲言*/
@SuppressWarnings("All")
public class EnemyTank extends Tank implements Runnable {//在敌人坦克类,保存多个shotprivate Vector<Shot> shots = new Vector<>();//敌人坦克 可以得到敌人坦克的Vector//1.EnemyTank 在mypanel里面private Vector<EnemyTank> enemyTanks = new Vector<>();public EnemyTank(int x, int y) {super(x, y);}public Vector<Shot> getShots() {return shots;}public void setShots(Vector<Shot> shots) {this.shots = shots;}public Vector<EnemyTank> getEnemyTanks() {return enemyTanks;}/*** 提供一个方法,可以将mypanel 的成员 Vector<EnemyTank> enemyTanks = new Vector<>();* 设置到  private Vector<EnemyTank> enemyTanks = new Vector<>();* @param enemyTanks 敌人坦克集合*/public void setEnemyTanks(Vector<EnemyTank> enemyTanks) {this.enemyTanks = enemyTanks;}//编写方法,判断当前的敌人坦克,是否和 enemyTanks 中2的 其他坦克发生了重叠 或者是碰撞public boolean isTouchEnemyTank(){//判断当前敌人坦克(this) 方向switch (this.getDirection()){case 0: //上//让当前的this 敌人坦克 和 其他所有的敌人坦克比较for (int i = 0;i< enemyTanks.size();i++){//从vector中取出一辆敌人的坦克EnemyTank enemyTank = enemyTanks.get(i);//不和自己比较if (this != enemyTank){/*1.如果敌人坦克是上/下方向   x的范围是什么【enemyTank.getX() ,enemyTank.getX() + 40】y的范围是什么【enemyTank.getY() ,enemyTank.getY() + 60】*/if (enemyTank.getDirection() == 0 || enemyTank.getDirection() == 2){//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;}//3.当前坦克的右上角坐标【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;}}/*1.如果敌人坦克是左/右方向   x的范围是什么【enemyTank.getX() ,enemyTank.getX() + 60】y的范围是什么【enemyTank.getY() ,enemyTank.getY() + 40】*///如果敌人坦克是左/右方向if (enemyTank.getDirection() == 1 || enemyTank.getDirection() == 3){//2.当前坦克的左上角坐标【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;}//3.当前坦克的右上角坐标【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: //右//让当前的this 敌人坦克 和 其他所有的敌人坦克比较for (int i = 0;i< enemyTanks.size();i++){//从vector中取出一辆敌人的坦克EnemyTank enemyTank = enemyTanks.get(i);//不和自己比较if (this != enemyTank){/*1.如果敌人坦克是上/下方向   x的范围是什么【enemyTank.getX() ,enemyTank.getX() + 40】y的范围是什么【enemyTank.getY(),enemyTank.getY()  + 40】*/if (enemyTank.getDirection() == 0 || enemyTank.getDirection() == 2){//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;}//3.当前坦克的右下角坐标【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;}}/*1.如果敌人坦克是左/右方向   x的范围是什么【enemyTank.getX(),enemyTank.getX() + 60】y的范围是什么【enemyTank.getY(),enemyTank.getX() + 40】*///如果敌人坦克是左/右方向if (enemyTank.getDirection() == 1 || enemyTank.getDirection() == 3){//2.当前坦克的右上角坐标【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;}//3.当前坦克的右下角坐标【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: //下//让当前的this 敌人坦克 和 其他所有的敌人坦克比较for (int i = 0;i< enemyTanks.size();i++){//从vector中取出一辆敌人的坦克EnemyTank enemyTank = enemyTanks.get(i);//不和自己比较if (this != enemyTank){/*1.如果敌人坦克是上/下方向   x的范围是什么【enemyTank.getX() ,enemyTank.getX() + 40】y的范围是什么【enemyTank.getY(),enemyTank.getY()  + 60】*/if (enemyTank.getDirection() == 0 || enemyTank.getDirection() == 2){//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;}//3.当前坦克的右下角坐标【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;}}/*1.如果敌人坦克是左/右方向   x的范围是什么【enemyTank.getX(),enemyTank.getX() + 60】y的范围是什么【enemyTank.getY(),enemyTank.getX() + 40】*///如果敌人坦克是左/右方向if (enemyTank.getDirection() == 1 || enemyTank.getDirection() == 3){//2.当前坦克的左下角坐标【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;}//3.当前坦克的右下角坐标【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: //左//让当前的this 敌人坦克 和 其他所有的敌人坦克比较for (int i = 0;i< enemyTanks.size();i++){//从vector中取出一辆敌人的坦克EnemyTank enemyTank = enemyTanks.get(i);//不和自己比较if (this != enemyTank){/*1.如果敌人坦克是上/下方向   x的范围是什么【enemyTank.getX() ,enemyTank.getX() + 40】y的范围是什么【enemyTank.getY(),enemyTank.getY()  + 60】*/if (enemyTank.getDirection() == 0 || enemyTank.getDirection() == 2){//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;}//3.当前坦克的左下角坐标【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;}}/*1.如果敌人坦克是左/右方向   x的范围是什么【enemyTank.getX(),enemyTank.getX() + 60】y的范围是什么【enemyTank.getY(),enemyTank.getX() + 40】*///如果敌人坦克是左/右方向if (enemyTank.getDirection() == 1 || enemyTank.getDirection() == 3){//2.当前坦克的左上角坐标【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;}//3.当前坦克的左下角坐标【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;}return false;}@Overridepublic void run() {while (true) {//这里我们判断如果shots size() == 0,创建一颗子弹,放入到shots集合,并启动if (isLive() && shots.size() < 3) {Shot s = null;//判断坦克的方向,创建对应的子弹switch (getDirection()) {case 0:s = new Shot(getX() + 20, getY(), 0);break;case 1:s = new Shot(getX() + 60, getY() + 20, 1);break;case 2:s = new Shot(getX() + 20, getY() + 60, 2);break;case 3:s = new Shot(getX(), getY() + 20, 3);break;}//添加到容器shots.add(s);//启动线程new Thread(s).start();}//当前坦克的方向来继续移动for (int i = 0; i < 30; i++) {switch (getDirection()) {case 0://向上if (getY() > 0 && !isTouchEnemyTank()){moveUp();}try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}break;case 1://向右if (getX() + 60 < 1000  && !isTouchEnemyTank()){moveRight();}try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}break;case 2://向下if (getY() + 60 < 722  && !isTouchEnemyTank()){moveDown();}try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}break;case 3://向左if (getX() > 0  && !isTouchEnemyTank()){moveLeft();}try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}break;}}try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}//然后随机的改变方向int direction = (int) (Math.random() * 4);setDirection(direction);//一旦写并发程序,一定要考虑清楚该线程什么时候结束//被子弹打中了,结束线程if (!isLive()) {break;}}}
}

(5)Hero 我方坦克类

package cn.bloghut.pojo;import cn.bloghut.service.Shot;import java.util.Vector;/*** @Classname Hero* @Description 自己坦克* @Date 2022/5/8 8:43* @Created by 闲言*/
public class Hero extends Tank{//定义一个shot对象,表示射击行为private Shot shot = null;//可以发射多颗子弹private Vector<Shot> shots = new Vector<>();public Hero(int x, int y) {super(x, y);}//射击public void shotEnemyTank(){//控制面板上子弹数量if (shots.size() >= 5){return;}//创建short对象,根据当前hero对象的位置方向来创建shot对象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;}//把进创建的short放到集合中shots.add(shot);//启动shot线程new Thread(shot).start();}public Vector<Shot> getShots() {return shots;}public void setShots(Vector<Shot> shots) {this.shots = shots;}public Shot getShot() {return shot;}public void setShot(Shot shot) {this.shot = shot;}
}

(6)Node 记录敌方坦克类(继续上局游戏用)

package cn.bloghut.pojo;/*** @Classname Node* @Description 一个node 对象,表示一个敌人坦克的信息* @Date 2022/5/9 10:47* @Created by 闲言*/
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;}
}

(7)Tank 坦克父类

package cn.bloghut.pojo;/*** @Classname Tank* @Description 坦克实体* @Date 2022/5/8 8:43* @Created by 闲言*/
public class Tank {private int x;private int y;private int direction;///坦克方向0-上 1-右 2-下 3-左private int speed = 1;//坦克速度private boolean isLive = true;public Tank(int x, int y) {this.x = x;this.y = y;}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;}//上下左右移动方法public void moveUp(){//坦克不能出边界if (y > 0){y-=speed;}}public void moveRight(){if (x + 60 < 1000){x+=speed;}}public void moveDown(){if (y + 60 < 722){y+=speed;}}public void moveLeft(){if (x > 0){x-=speed;}}public boolean isLive() {return isLive;}public void setLive(boolean live) {isLive = live;}public int getSpeed() {return speed;}public void setSpeed(int speed) {this.speed = speed;}
}

(8)PlayAudio 播放背景音乐类

package cn.bloghut.service;import javax.sound.sampled.*;
import java.io.*;/*** @author ajun* Date 2021/7/16* @version 1.0* 播放音乐*/
public class PlayAudio extends Thread {private String filename;public PlayAudio(String wavfile) {String path = System.getProperty("user.dir");filename = path+"\\"+wavfile;}@Overridepublic void run() {// 从项目资源目录下加载背景音乐AudioInputStream audioInputStream = null;try {audioInputStream = AudioSystem.getAudioInputStream(new BufferedInputStream(new FileInputStream(filename)));} 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();}}
}

(9)Recorder 记录游戏数据类

package cn.bloghut.service;import cn.bloghut.pojo.EnemyTank;
import cn.bloghut.pojo.Node;import java.io.*;
import java.util.Vector;/*** @Classname Recorder* @Description 用于记录* @Date 2022/5/9 10:00* @Created by 闲言*/
public class Recorder {//定义变量,记录我方击毁敌人坦克数量private static int allEnemyTankTotal = 0;//定义IO 对象,准备写数据到文件中private static BufferedWriter bufferedWriter = null;private static BufferedReader bufferedReader = null;private static String recordFile;//存储敌人坦克private static Vector<EnemyTank> enemyTanks = null;//定义一个Node 的Vector ,用于保存敌人的信息nodeprivate static Vector<Node> nodes = new Vector<>();static {String parentPath = System.getProperty("user.dir");recordFile = parentPath + "\\record.txt";}/***  该方法在继续上局时调用*  用于读取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 addlEnemyTankTotal(){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;}
}

(10)Shot 子弹类

package cn.bloghut.service;/*** @Classname Shot* @Description TODO* @Date 2022/5/8 14:15* @Created by 闲言*/
public class Shot implements Runnable{private int x;//子弹x坐标private int y;//子弹x坐标private int direction = 0;//子弹方向private int speed = 2;//子弹速度private boolean isLive = true; //子弹是否还存活@Overridepublic void run() {//射击行为while (true){//线程休眠 50 毫秒try {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;}System.out.println("x==>"+x+"   y===>"+y);//当子弹碰到敌人坦克时,也应该结束线程//当子弹移动到面板的边界时,销毁子弹if (!(x >= 0 && x <= 1000 && y >= 0 && y <= 750 && isLive)){//设置子弹是否存活状态isLive = false;System.out.println("子弹线程退出");break;}}}//构造子弹public Shot(int x, int y, int direction) {this.x = x;this.y = y;this.direction = direction;}public boolean isLive() {return isLive;}public void setLive(boolean live) {isLive = live;}public int getDirection() {return direction;}public void setDirection(int direction) {this.direction = direction;}public int getSpeed() {return speed;}public void setSpeed(int speed) {this.speed = speed;}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;}@Overridepublic String toString() {return "Shot{" +"x=" + x +", y=" + y +", direction=" + direction +", speed=" + speed +", isLive=" + isLive +'}';}
}

   注意:本工程是模块化进行开发的,所以一些文件( 图片、存档路径、音乐)的路径需要改成自己对应。

韩顺平--Java坦克大战相关推荐

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

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

  2. 韩顺平 java 坦克大战_HTML5坦克大战(韩顺平版本)

    1 //定义敌人和我们自己的坦克的颜色 2 var enemyColor = new Array("#0BB","#0FF");3 var heroColor ...

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

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

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

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

  5. java 坦克大战_java课程设计之坦克大战

    本文实例为大家分享了java坦克大战的具体代码,供大家参考,具体内容如下 环境要求: 操作系统:Windows 10 JAVA虚拟机:JDK1.8以上 开发环境:Eclipse(4.5以上) 功能提示 ...

  6. java坦克大战课设报告_java课程设计之坦克大战

    本文实例为大家分享了java坦克大战的具体代码,供大家参考,具体内容如下 环境要求: 操作系统:Windows 10 JAVA虚拟机:JDK1.8以上 开发环境:Eclipse(4.5以上) 功能提示 ...

  7. Java坦克大战游戏源码(java坦克大战)

    Java坦克大战游戏源码(java坦克大战) public Swingtest002() {// 设置标题setTitle("请登陆");// 绝对布局setLayout(null ...

  8. java坦克大战总体功能设计_Java坦克大战设计报告.doc

    Java坦克大战设计报告.doc <语言设计> 设计报告 信息工程学院专业班级:::指导老师:2011年7月22日 目录 目录2 题目一 坦克大战4 1.1题目简介4 1.2设计的内容.要 ...

  9. Java坦克大战,基于Swing编写很哇塞的小游戏,可以做课程设计毕业设计

    Java坦克大战,基于Swing编写很哇塞的小游戏,可以做课程设计毕业设计 有图有真相 操作方法:ASDW控制移动,鼠标控制炮筒旋转,鼠标左键开枪,空格发射炮弹, 开发思路是标准的游戏开发思路,单线程 ...

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

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

最新文章

  1. 已知一棵二叉树的中序序列和后序序列,写一个建立该二叉树的二叉链表存储结构的算法...
  2. 新建centos6虚拟机黑屏_虚拟机centos无法进去选择系统界面,也就是开机过bios就黑屏解决方案...
  3. VC++中忽略所有默认库纯Win32 API编译及链接 - 计算机软件编程 - Wangye's Space
  4. 数据粒度的上卷和下钻
  5. Linux(1) 目录结构
  6. unix下ODBC连接MySQL编程_通过unixODBC访问PostgreSQL数据库
  7. 最全iOS开发之第三方库
  8. 树莓派Pico 开机自动运行程序
  9. 微信小程序:实现微信登录
  10. android化学制图软件,虚拟化学实验室(Chemist)
  11. win10进程太多怎么优化_教你优化Windows7后台进程,让你的电脑启动更快、运行更流畅...
  12. HTML期末学生作业~html+css+javascript仿猫眼电影在线网站[毕业设计]
  13. 互联网创业的三年都学到了什么?
  14. 要玩就玩最好的棋牌游戏
  15. 【复现笔记】Iterative Corresponding Geometry
  16. GLES2.0中文API-glCompressedTexSubImage2D
  17. 杨建允:2022年社交电商要如何突围、会走向何方?
  18. Python实现电话号码的数字组合
  19. 计算机组装的规范装机流程,电脑装机详细步骤
  20. mysql实现vpd_一种存储的VPD信息访问方法及系统与流程

热门文章

  1. Oracle数据库下载安装和卸载简单说明
  2. 无盘服务器缓存,深入研究无盘服务器缓存
  3. 如何从官网下载oracle客户端,Oracle11g客户端client的下载与安装
  4. 苹果手机专用计算机,使用苹果手机,发现iphone连不上wifi怎么办?连不上wifi解决方法...
  5. mysql安装步骤以及问题---解压版本
  6. NLPIR/ICTCLAS中文分词系统 java相关api文档总结
  7. 数学建模四大模型总结
  8. Java已死?一眼就能看懂的Java自学手册,挑战大厂重燃激情!
  9. 推荐个 Java 开源商城项目,这个是真的好!
  10. 矩阵键盘行列扫描c语言,单片机矩阵键盘按钮行列逐级扫描法