You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Web-Dev-For-Beginners/6-space-game/4-collision-detection/translations
Jen Looper d48a6b54dd
Merge branch 'main' into nl
4 years ago
..
README.es.md lesson 6 quiz links 4 years ago
README.hi.md lesson 6 quiz links 4 years ago
README.it.md Italian translation - Some more localization query strings in quizzes missing 4 years ago
README.ja.md fix quiz url. 4 years ago
README.ko.md lesson 6 quiz links 4 years ago
README.ms.md translated to Malay 4 years ago
README.zh-tw.md redirect quiz links from zh-tw lessons 4 years ago
assignment.es.md Big commit 4 years ago
assignment.hi.md Big commit 4 years ago
assignment.it.md Chapter 6 - Part 4 translated 4 years ago
assignment.ja.md translate 4-collision-detection into japanese 4 years ago
assignment.ko.md Big commit 4 years ago
assignment.ms.md Big commit 4 years ago
assignment.nl.md small language improvements 4 years ago
assignment.zh-tw.md translate lesson 6 to zh-tw 4 years ago

README.zh-tw.md

建立太空遊戲 Part 4加入雷射與碰撞偵測

課前測驗

課前測驗

這堂課中,你會學會如何在 JavaScript 上發射雷射光!我們需要在遊戲中新增兩項東西:

  • 雷射光:這束雷射會從英雄艦艇垂直往上移動
  • 碰撞偵測,除了完成射擊這項能力,我們還會新增幾項遊戲規則:
    • 雷射擊中敵人:被雷射擊中的敵人會死亡
    • 雷射擊中畫面最上方:雷射擊中到畫面最上方會消失
    • 敵人碰觸到英雄:敵人與英雄在互相碰觸時皆會被摧毀
    • 敵人碰觸到畫面最下方:敵人碰觸到畫面最下方時,該敵人與英雄會被摧毀

簡單來說,你這位英雄需要在敵人到達畫面最下方之前,使用雷射擊毀它們。

做點關於第一款電腦遊戲的研究。它有哪些功能?

讓我們成為英雄吧!

碰撞偵測

我們該如何進行碰撞偵測呢?我們需要將遊戲物件視為移動中的矩形。你或許會問為什麼?這是因為,繪製遊戲物件的圖片皆為矩形:它有一組 xywidthheight

若兩個矩形,舉例來說:英雄與敵人相交了,這就是一次碰撞。至於會發生什麼事取決於遊戲規則。要製作碰撞偵測,你需要這些步驟:

  1. 取得表達遊戲物件為矩形的方法,好比是:

    rectFromGameObject() {
      return {
        top: this.y,
        left: this.x,
        bottom: this.y + this.height,
        right: this.x + this.width
      }
    }
    
  2. 一個比較函式,這個函式可以如下:

    function intersectRect(r1, r2) {
      return !(r2.left > r1.right ||
        r2.right < r1.left ||
        r2.top > r1.bottom ||
        r2.bottom < r1.top);
    }
    

我們該如何摧毀物件

要摧毀遊戲物件,你需要讓遊戲知道,它不再需要在定期的遊戲迴圈中繪製該物件。一種方法是在情況發生時,我們可以標記遊戲物件為死亡,例如:

// 碰撞發生
enemy.dead = true

接著,你在重新繪製畫面前,排除掉這些死亡的物件,例如:

gameObjects = gameObject.filter(go => !go.dead);

我們該如何發射雷射

發射雷射可以被視作回應一件鍵盤事件,並建立往特定方向移動的物件。因此我們需要列出下列步驟:

  1. 建立雷射物件:從英雄艦艇的正上方,建立往畫面上方移動的物件。
  2. 連接該程式到鍵盤事件:我們需要在鍵盤中挑選一個按鍵,表達玩家發射雷射光。
  3. 在按鍵按壓時,建立看起來像雷射光的遊戲物件

雷射的冷卻時間

在每次按壓按鍵時,好比說空白鍵,雷射光都需要被發射出來。為了讓遊戲不要在短時間內發射太多組雷射光,我們需要修正它。修法為建立冷卻時間 ── 一個計時器確保雷射在一定期間內只能被發射一次。你可以藉由下列方式建立:

class Cooldown {
  constructor(time) {
    this.cool = false;
    setTimeout(() => {
      this.cool = true;
    }, time)
  }
}

class Weapon {
  constructor {
  }
  fire() {
    if (!this.cooldown || this.cooldown.cool) {
      // 產生雷射光
      this.cooldown = new Cooldown(500);
    } else {
      // 什麼事都不做,冷卻中。
    }
  }
}

根據太空遊戲系列課程的第一章,回想關於冷卻時間

建立目標

你會利用上一堂課中現成的程式碼(你應該有整理並重構過)做延伸。使用來自 Part II 的檔案或是使用 Part III - Starter

要點:你需要使用的雷射光已經在資料夾中,並已匯入到程式碼中。

  • 加入碰撞偵測,建立下列規則給各個雷射碰觸到東西的情況:
    1. 雷射擊中敵人:被雷射擊中的敵人會死亡
    2. 雷射擊中畫面最上方:雷射擊中到畫面最上方會消失
    3. 敵人碰觸到英雄:敵人與英雄在互相碰觸時皆會被摧毀
    4. 敵人碰觸到畫面最下方:敵人碰觸到畫面最下方時,該敵人與英雄會被摧毀

建議步驟

在你的 your-work 子資料夾中,確認檔案是否建立完成。它應該包括:

-| assets
  -| enemyShip.png
  -| player.png
  -| laserRed.png
-| index.html
-| app.js
-| package.json

開始 your_work 資料夾中的專案,輸入:

cd your-work
npm start

這會啟動 HTTP 伺服器並發布網址 http://localhost:5000。開啟瀏覽器並輸入該網址,現在它能呈現英雄以及所有的敵人,但它們還沒辦法移動!

建立程式碼

  1. 設定表達遊戲物件為矩形的方法,以處理碰撞狀況 下列的程式表達 GameObject 的矩形呈現方式。編輯你的 GameObject class

    rectFromGameObject() {
        return {
          top: this.y,
          left: this.x,
          bottom: this.y + this.height,
          right: this.x + this.width,
        };
      }
    
  2. 加入程式碼來檢查碰撞 這會是新函式來測試兩矩形是否相交:

    function intersectRect(r1, r2) {
      return !(
        r2.left > r1.right ||
        r2.right < r1.left ||
        r2.top > r1.bottom ||
        r2.bottom < r1.top
      );
    }
    
  3. 加入雷射發射功能

    1. 加入鍵盤事件訊息空白鍵要能在英雄艦艇上方建立雷射光。加入三個常數到 Messages 物件中:

       KEY_EVENT_SPACE: "KEY_EVENT_SPACE",
       COLLISION_ENEMY_LASER: "COLLISION_ENEMY_LASER",
       COLLISION_ENEMY_HERO: "COLLISION_ENEMY_HERO",
      
    2. 處理空白鍵。 編輯 window.addEventListener 的 keyup 函式來處理空白鍵:

        } else if(evt.keyCode === 32) {
          eventEmitter.emit(Messages.KEY_EVENT_SPACE);
        }
      
    3. 加入監聽者。 編輯函式 initGame() 來確保英雄可以在空白鍵按壓時,發射雷射光:

      eventEmitter.on(Messages.KEY_EVENT_SPACE, () => {
       if (hero.canFire()) {
         hero.fire();
       }
      

      建立新的函式 eventEmitter.on() 確保敵人碰觸到雷射光時,能更新死亡狀態:

      eventEmitter.on(Messages.COLLISION_ENEMY_LASER, (_, { first, second }) => {
        first.dead = true;
        second.dead = true;
      })
      
    4. 移動物件。 確保雷射逐步地向畫面上方移動。建立新的 class Laser 延伸自 GameObject,你應該有做過:

        class Laser extends GameObject {
        constructor(x, y) {
          super(x,y);
          (this.width = 9), (this.height = 33);
          this.type = 'Laser';
          this.img = laserImg;
          let id = setInterval(() => {
            if (this.y > 0) {
              this.y -= 15;
            } else {
              this.dead = true;
              clearInterval(id);
            }
          }, 100)
        }
      }
      
    5. 處理碰撞。 建立雷射的碰撞規則。加入函式 updateGameObjects() 來確認被碰撞的物件。

      function updateGameObjects() {
        const enemies = gameObjects.filter(go => go.type === 'Enemy');
        const lasers = gameObjects.filter((go) => go.type === "Laser");
      // 雷射擊中某物
        lasers.forEach((l) => {
          enemies.forEach((m) => {
            if (intersectRect(l.rectFromGameObject(), m.rectFromGameObject())) {
            eventEmitter.emit(Messages.COLLISION_ENEMY_LASER, {
              first: l,
              second: m,
            });
          }
         });
      });
      
        gameObjects = gameObjects.filter(go => !go.dead);
      }  
      

      記得在 window.onload 裡的遊戲迴圈中加入 updateGameObjects()

    6. 設定雷射的冷卻時間,它只能在定期內發射一次。

      最後,編輯 Hero class 來允許冷卻:

      class Hero extends GameObject {
       constructor(x, y) {
         super(x, y);
         (this.width = 99), (this.height = 75);
         this.type = "Hero";
         this.speed = { x: 0, y: 0 };
         this.cooldown = 0;
       }
       fire() {
         gameObjects.push(new Laser(this.x + 45, this.y - 10));
         this.cooldown = 500;
      
         let id = setInterval(() => {
           if (this.cooldown > 0) {
             this.cooldown -= 100;
           } else {
             clearInterval(id);
           }
         }, 200);
       }
       canFire() {
         return this.cooldown === 0;
       }
      }
      

到這裡,你的遊戲有了些功能!你可以測試方向鍵,使用空白鍵發射雷射。當你擊中敵人時它們會消失。幹得漂亮!


🚀 挑戰

加入爆炸特效! 看看 Space Art Repo 中的檔案,試著在雷射擊中外星人時,加入爆炸畫面。

課後測驗

課後測驗

複習與自學

對遊戲中的迴圈定時做點實驗。當你改變數值時,發生了什麼事?閱讀更多關於 JavaScript 計時事件

作業

探索碰撞