day05-執行緒的應用04

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方法

image-20220908171939043

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;//退出執行緒
            }
        }
    }
}

image-20220908175719465

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坦克的條件:

原來:

image-20220908185008101

現在:

//畫出自己的坦克-封裝方法
if (hero != null && hero.isLive) {
    drawTank(hero.getX(), hero.getY(), g, hero.getDirect(), 1);
}

image-20220908185440422

ps:關於我方坦克被打爆後還是可以再繼續移動操作的問題,是因為並沒有處理hero對象,可以在Hero類中先判斷hero對象的isLive為true,之後再進行移動發射等操作。該問題之後再解決。