7.线程的应用03

7.4坦克大战5.0版

增加功能:

  1. 我方坦克在发射的子弹消亡之后,才能发射新的子弹==>拓展:发射多颗子弹怎么办,控制一次最多只能发射5颗子弹
  2. 让敌人坦克发射的子弹消亡之后,可以再发射子弹
  3. 当地人的坦克击中我方坦克之后,我方坦克小时,并出现爆炸效果

7.4.1功能1plus:我方坦克连发子弹

思路:

  1. 要发射多颗子弹,就使用Vector保存子弹对象

  2. 在绘制我方子弹的时候需要遍历Vector集合

  3. 同时要修改击中判定方法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);
}
}
}
}
  1. 在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,之后再进行移动发射等操作。该问题之后再解决。

最新文章

  1. mysql数据库远程访问指定数据库设置
  2. BZOJ2498 : Xavier is Learning to Count
  3. ASP.NET获取真正的客户端IP地址的6种方法
  4. ses_cations 值顺序
  5. HDU4325 树状数组
  6. Protostuff序列化
  7. HDU2102 A计划
  8. HttpContext.Current多线程调用
  9. UESTC-888-Absurdistan Roads(kruskal+floyd)
  10. js 实现图片压缩并转换成base64(data:image/jpeg;base64)格式
  11. MVC配置伪静态
  12. Python在mysql中进行操作是十分容易和简洁的
  13. jQuery常用操作
  14. Jmeter content-type:multipart/form-data温故
  15. [bzoj4712]洪水 线段树+树链剖分维护动态dp+二分
  16. SpringBoot+MyBatis中自动根据@Table注解和@Column注解生成ResultMap
  17. 利用Octopress在Github上搭建博客及后续问题总汇
  18. iOS 类似美团或饿了么评价中的星星评分控件
  19. vi错误terminal too wide解决方法
  20. SQL 行转列的两种做法

热门文章

  1. UiPath官方视频Level1
  2. UiPath图片操作截图的介绍和使用
  3. 细说GaussDB(DWS)复杂多样的资源负载管理手段
  4. SpringMVC-01
  5. HashMap中的哈希函数分析
  6. 强化版按键消抖Verilog实现
  7. 【docker专栏7】容器自启动与守护进程停止后容器保活
  8. 模板库 ~ Template library
  9. Informatica旗下PowerCenter的元数据库解析
  10. 如何让 JS 代码不可断点