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/translations/th/6-space-game/4-collision-detection/README.md

19 KiB

สร้างเกมอวกาศ ตอนที่ 4: เพิ่มเลเซอร์และตรวจจับการชน

แบบทดสอบก่อนเรียน

แบบทดสอบก่อนเรียน

ในบทเรียนนี้ คุณจะได้เรียนรู้วิธีการยิงเลเซอร์ด้วย JavaScript! เราจะเพิ่มสองสิ่งในเกมของเรา:

  • เลเซอร์: เลเซอร์นี้จะถูกยิงจากยานของฮีโร่และพุ่งขึ้นในแนวตั้ง
  • การตรวจจับการชน: ในการเพิ่มความสามารถในการ ยิง เราจะเพิ่มกฎของเกมที่น่าสนใจดังนี้:
    • เลเซอร์ชนศัตรู: ศัตรูจะตายเมื่อถูกเลเซอร์ยิง
    • เลเซอร์ชนขอบบนของหน้าจอ: เลเซอร์จะถูกทำลายเมื่อชนขอบบนของหน้าจอ
    • ศัตรูชนฮีโร่: ศัตรูและฮีโร่จะถูกทำลายเมื่อชนกัน
    • ศัตรูชนขอบล่างของหน้าจอ: ศัตรูและฮีโร่จะถูกทำลายเมื่อศัตรูชนขอบล่างของหน้าจอ

สรุปคือ คุณ -- ฮีโร่ -- ต้องยิงศัตรูทั้งหมดด้วยเลเซอร์ก่อนที่พวกมันจะเคลื่อนที่ไปถึงขอบล่างของหน้าจอ

ลองค้นคว้าเกี่ยวกับเกมคอมพิวเตอร์เกมแรกที่เคยถูกสร้างขึ้น มันมีฟังก์ชันการทำงานอะไรบ้าง?

มาร่วมเป็นฮีโร่ไปด้วยกัน!

การตรวจจับการชน

เราจะตรวจจับการชนได้อย่างไร? เราต้องคิดว่าออบเจ็กต์ในเกมของเราเป็นสี่เหลี่ยมที่เคลื่อนที่ไปมา ทำไมถึงเป็นแบบนั้น? เพราะภาพที่ใช้ในการวาดออบเจ็กต์ในเกมเป็นรูปสี่เหลี่ยม: มันมี x, y, width และ height

ถ้าสี่เหลี่ยมสองอัน เช่น ฮีโร่และศัตรู ตัดกัน นั่นหมายถึงเกิดการชน สิ่งที่ควรเกิดขึ้นหลังจากนั้นขึ้นอยู่กับกฎของเกม ในการสร้างการตรวจจับการชน คุณจะต้องมีสิ่งต่อไปนี้:

  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);
    }
    

วิธีการทำลายสิ่งต่าง ๆ

ในการทำลายสิ่งต่าง ๆ ในเกม คุณต้องแจ้งให้เกมทราบว่าไม่ควรวาดออบเจ็กต์นี้อีกในลูปของเกมที่ทำงานในช่วงเวลาที่กำหนด วิธีหนึ่งคือการทำเครื่องหมายว่าออบเจ็กต์ในเกม ตาย เมื่อเกิดเหตุการณ์บางอย่าง เช่นนี้:

// collision happened
enemy.dead = true

จากนั้นคุณสามารถจัดการกับออบเจ็กต์ที่ ตาย ก่อนที่จะวาดหน้าจอใหม่ เช่นนี้:

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

วิธีการยิงเลเซอร์

การยิงเลเซอร์หมายถึงการตอบสนองต่อเหตุการณ์กดปุ่มและสร้างออบเจ็กต์ที่เคลื่อนที่ในทิศทางที่กำหนด ดังนั้นเราต้องทำตามขั้นตอนต่อไปนี้:

  1. สร้างออบเจ็กต์เลเซอร์: จากด้านบนของยานฮีโร่ ซึ่งเมื่อถูกสร้างขึ้นจะเริ่มเคลื่อนที่ขึ้นไปยังขอบบนของหน้าจอ
  2. ผูกโค้ดกับเหตุการณ์กดปุ่ม: เราต้องเลือกปุ่มบนคีย์บอร์ดที่แทนการยิงเลเซอร์ของผู้เล่น
  3. สร้างออบเจ็กต์ในเกมที่ดูเหมือนเลเซอร์ เมื่อปุ่มถูกกด

การหน่วงเวลาในการยิงเลเซอร์

เลเซอร์ต้องถูกยิงทุกครั้งที่คุณกดปุ่ม เช่น space เพื่อป้องกันไม่ให้เกมสร้างเลเซอร์มากเกินไปในช่วงเวลาสั้น ๆ เราต้องแก้ไขสิ่งนี้ วิธีแก้ไขคือการเพิ่มสิ่งที่เรียกว่า cooldown หรือการหน่วงเวลา ซึ่งเป็นตัวจับเวลาที่ทำให้เลเซอร์สามารถยิงได้ในช่วงเวลาที่กำหนดเท่านั้น คุณสามารถทำได้ดังนี้:

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

class Weapon {
  constructor {
  }
  fire() {
    if (!this.cooldown || this.cooldown.cool) {
      // produce a laser
      this.cooldown = new Cooldown(500);
    } else {
      // do nothing - it hasn't cooled down yet.
    }
  }
}

ย้อนกลับไปดูบทเรียนที่ 1 ในซีรีส์เกมอวกาศเพื่อทบทวนเกี่ยวกับ cooldowns

สิ่งที่ต้องสร้าง

คุณจะนำโค้ดที่มีอยู่ (ซึ่งคุณควรทำความสะอาดและปรับปรุงแล้ว) จากบทเรียนก่อนหน้า และขยายมันต่อไป คุณสามารถเริ่มต้นด้วยโค้ดจากตอนที่ II หรือใช้โค้ดจาก Part III- starter

เคล็ดลับ: เลเซอร์ที่คุณจะทำงานด้วยนั้นอยู่ในโฟลเดอร์ assets ของคุณแล้วและถูกอ้างอิงในโค้ดของคุณ

  • เพิ่มการตรวจจับการชน เมื่อเลเซอร์ชนกับบางสิ่ง กฎต่อไปนี้ควรนำมาใช้:
    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 Server ที่อยู่ http://localhost:5000 เปิดเบราว์เซอร์และใส่ที่อยู่นั้น ตอนนี้มันควรแสดงฮีโร่และศัตรูทั้งหมด แต่ยังไม่มีอะไรเคลื่อนไหว :)

เพิ่มโค้ด

  1. ตั้งค่าตัวแทนสี่เหลี่ยมของออบเจ็กต์ในเกมเพื่อจัดการการชน โค้ดด้านล่างช่วยให้คุณสร้างตัวแทนสี่เหลี่ยมของ GameObject แก้ไขคลาส GameObject ของคุณเพื่อขยายมัน:

    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. เพิ่มข้อความเหตุการณ์กดปุ่ม ปุ่ม space ควรสร้างเลเซอร์ที่อยู่เหนือยานฮีโร่ เพิ่มค่าคงที่สามตัวในออบเจ็กต์ Messages:

       KEY_EVENT_SPACE: "KEY_EVENT_SPACE",
       COLLISION_ENEMY_LASER: "COLLISION_ENEMY_LASER",
       COLLISION_ENEMY_HERO: "COLLISION_ENEMY_HERO",
      
    2. จัดการปุ่ม space แก้ไขฟังก์ชัน window.addEventListener keyup เพื่อจัดการ space:

        } else if(evt.keyCode === 32) {
          eventEmitter.emit(Messages.KEY_EVENT_SPACE);
        }
      
    3. เพิ่มตัวฟังเหตุการณ์ แก้ไขฟังก์ชัน initGame() เพื่อให้แน่ใจว่าฮีโร่สามารถยิงได้เมื่อกด space bar:

      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. เคลื่อนที่ออบเจ็กต์ ตรวจสอบให้แน่ใจว่าเลเซอร์เคลื่อนที่ไปยังขอบบนของหน้าจออย่างค่อยเป็นค่อยไป คุณจะสร้างคลาส 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");
      // laser hit something
        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);
      }  
      

      ตรวจสอบให้แน่ใจว่าได้เพิ่ม updateGameObjects() ในลูปของเกมใน window.onload

    6. เพิ่ม cooldown ให้กับเลเซอร์ เพื่อให้สามารถยิงได้ในช่วงเวลาที่กำหนดเท่านั้น

      สุดท้าย แก้ไขคลาส Hero เพื่อให้สามารถหน่วงเวลาได้:

      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 bar และศัตรูจะหายไปเมื่อคุณยิงโดนพวกมัน เก่งมาก!


🚀 ความท้าทาย

เพิ่มเอฟเฟกต์ระเบิด! ลองดูที่ทรัพยากรเกมใน Space Art repo และลองเพิ่มเอฟเฟกต์ระเบิดเมื่อเลเซอร์ชนกับเอเลี่ยน

แบบทดสอบหลังเรียน

แบบทดสอบหลังเรียน

ทบทวนและศึกษาด้วยตัวเอง

ทดลองปรับช่วงเวลาในเกมของคุณจนถึงตอนนี้ จะเกิดอะไรขึ้นเมื่อคุณเปลี่ยนมัน? อ่านเพิ่มเติมเกี่ยวกับ JavaScript timing events

การบ้าน

สำรวจการชน


ข้อจำกัดความรับผิดชอบ:
เอกสารนี้ได้รับการแปลโดยใช้บริการแปลภาษา AI Co-op Translator แม้ว่าเราจะพยายามให้การแปลมีความถูกต้อง แต่โปรดทราบว่าการแปลอัตโนมัติอาจมีข้อผิดพลาดหรือความไม่แม่นยำ เอกสารต้นฉบับในภาษาต้นทางควรถือเป็นแหล่งข้อมูลที่เชื่อถือได้ สำหรับข้อมูลที่สำคัญ ขอแนะนำให้ใช้บริการแปลภาษามนุษย์มืออาชีพ เราจะไม่รับผิดชอบต่อความเข้าใจผิดหรือการตีความที่ผิดพลาดซึ่งเกิดจากการใช้การแปลนี้