day05-线程的应用04
7.线程的应用03
7.4坦克大战5.0版
增加功能:
- 我方坦克在发射的子弹消亡之后,才能发射新的子弹==>拓展:发射多颗子弹怎么办,控制一次最多只能发射5颗子弹
- 让敌人坦克发射的子弹消亡之后,可以再发射子弹
- 当敌人的坦克击中我方坦克之后,我方坦克消失,并出现爆炸效果
7.4.1功能1plus:我方坦克连发子弹
思路:
-
要发射多颗子弹,就使用Vector保存子弹对象
-
在绘制我方子弹的时候需要遍历Vector集合
-
同时要修改击中判定方法hitTank
修改处1:Hero类:
package li.TankGame.version05; import java.util.Vector; /** * @author 李 * @version 5.0 */ public class Hero extends Tank { //定义一个shot对象,表示一个射击(线程) Shot shot = null; //定义一个集合用来装hero发射的子弹对象,使其可以发射多颗子弹 Vector<Shot> shots = new Vector<>(); public Hero(int x, int y) { super(x, y); } //射击 public void shotEnemyTank() { if (shots.size() == 5) {//如果当前的子弹已经有 5颗,就不继续创建新的shot对象,直到当前子弹集合中的子弹对象被移除 return ; } //创建Shot对象,根据当前Hero对象的坐标位置和方向来设置子弹的位置和方向 switch (getDirect()) {//获取Hero对象的方向 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; } //把新创建的shot放入到shots集合中 shots.add(shot); //启动Shot线程 new Thread(shot).start(); } }
2:MyPanel的paint方法(部分):
//画出hero发射的子弹 for (int i = 0; i < hero.shots.size(); i++) { Shot shot = hero.shots.get(i); if (shot != null && shot.isLive) { //如果子弹对象不为空,并且处于存活状态(isLive=true) System.out.println("hero的子弹被绘制"); g.draw3DRect(hero.shots.get(i).x, hero.shots.get(i).y, 2, 2, false); } else {//如果该shot对象已经无效,就从shot集合中删除 hero.shots.remove(shot); } }
3:在MyPanel的hitTank方法之前再封装一个hitEnemyTank方法:
public void hitEnemyTank(){ //判断是否击中敌人坦克 for (int i = 0; i <hero.shots.size() ; i++) { Shot shot=hero.shots.get(i);//shot为当前的子弹对象 if (shot != null && shot.isLive) {//如果当前我的子弹不为空并且子弹还存活 //就遍历敌人所有的坦克 for (int j = 0; j < enemyTanks.size(); j++) { EnemyTank enemyTank = enemyTanks.get(j); hitTank(shot, enemyTank); } } } }
- 在MyPanel的run方法里,删除调用的hitTank方法,转为调用hitEnemyTank方法

7.4.2功能2:敌人的子弹消亡之后可以再发射子弹
修改位置:Enemy类:
package li.TankGame.version05; import java.util.Vector; public class EnemyTank extends Tank implements Runnable { //在敌人坦克类使用Vector保存多个shot Vector<Shot> shots = new Vector<>(); boolean isLive = true; public EnemyTank(int x, int y) { super(x, y); } @Override public void run() { while (true) { //这我们先判断当前的坦克是否存活 // 在判断shots.size<3是否真,为真,说明当前的3颗子弹已经消亡了, // 就创建一颗子弹,放到shots集合中,并启动线程 if (isLive && (shots.size() < 3)) {//可以通过控制数字来修改敌人坦克一次发射几颗子弹 Shot s = null; //判断坦克的方创建对应的子弹 switch (getDirect()) { 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(); } //根据坦克的方法来继续移动 switch (getDirect()) { case 0://上 //让坦克保持一个方向走50步 for (int i = 0; i < 50; i++) { if (getY() > 0) { moveUp(); } try { Thread.sleep(50); } catch (InterruptedException e) { e.printStackTrace(); } } break; case 1://右 //让坦克保持一个方向走50步 for (int i = 0; i < 50; i++) { if (getX() + 60 < 700) {//700为面板宽度 moveRight();//走一步 } try { Thread.sleep(50);//每走一步就休眠50毫秒 } catch (InterruptedException e) { e.printStackTrace(); } } break; case 2://下 for (int i = 0; i < 50; i++) { if (getY() + 60 < 550) {//550为面板宽度 moveDown(); } try { Thread.sleep(50); } catch (InterruptedException e) { e.printStackTrace(); } } break; case 3://左 for (int i = 0; i < 50; i++) { if (getX() > 0) { moveLeft(); } try { Thread.sleep(50); } catch (InterruptedException e) { e.printStackTrace(); } } break; } //随机地改变坦克的方向 0-3 setDirect((int) (Math.random() * 4));//[0,4)的取整 //如果被击中了,就退出线程 if (!isLive) { break;//退出线程 } } } }

7.4.3功能3:我方坦克被击中时销毁并出现爆炸效果
思路:编写方法,判断敌人的坦克是否击中我们的坦克
修改1:在Tank类中增加isLive属性
boolean isLive = true ;
2:修改MyPanel类的hitTank方法的参数改为(Shot s, Tank enemyTank)
:即将获得的坦克类型改为父类Tank
3 :在hitTank方法前面增加hitHero方法:
public void hitHeroTank() { //遍历敌人所有的坦克 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 (hero.isLive && shot.isLive) { hitTank(shot, hero); } } } }
4:在MyPanel类的paint方法里面增加绘出hero坦克的条件:
原来:
现在:
//画出自己的坦克-封装方法 if (hero != null && hero.isLive) { drawTank(hero.getX(), hero.getY(), g, hero.getDirect(), 1); }

ps:关于我方坦克被打爆后还是可以再继续移动操作的问题,是因为并没有处理hero对象,可以在Hero类中先判断hero对象的isLive为true,之后再进行移动发射等操作。该问题之后再解决。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!