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,之後再進行移動發射等操作。該問題之後再解決。