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/6-end-condition
softchris a7d39944e9
🌐 Update translations via Co-op Translator
1 month ago
..
solution 🌐 Update translations via Co-op Translator 3 months ago
your-work 🌐 Update translations via Co-op Translator 3 months ago
README.md 🌐 Update translations via Co-op Translator 1 month ago
assignment.md 🌐 Update translations via Co-op Translator 1 month ago

README.md

สร้างเกมอวกาศ ตอนที่ 6: จบเกมและเริ่มใหม่

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

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

วันนี้เราจะเพิ่มเงื่อนไขการชนะ/แพ้ที่เหมาะสมและระบบเริ่มใหม่ เมื่อจบบทเรียนนี้ คุณจะมีเกมที่สมบูรณ์แบบที่ผู้เล่นสามารถเล่นจนจบและเล่นซ้ำได้ เหมือนกับเกมอาร์เคดคลาสสิกที่เป็นที่รู้จักในวงการเกม

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

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

ทำความเข้าใจเงื่อนไขการจบเกม

เกมของคุณควรจบเมื่อไหร่? คำถามพื้นฐานนี้ได้กำหนดรูปแบบการออกแบบเกมตั้งแต่ยุคอาร์เคดแรก ๆ Pac-Man จบเมื่อคุณถูกผีจับหรือเก็บจุดทั้งหมด ในขณะที่ Space Invaders จบเมื่อเอเลี่ยนลงมาถึงด้านล่างหรือคุณทำลายพวกมันทั้งหมด

ในฐานะผู้สร้างเกม คุณเป็นผู้กำหนดเงื่อนไขการชนะและแพ้ สำหรับเกมอวกาศของเรา นี่คือวิธีการที่พิสูจน์แล้วว่าสร้างการเล่นเกมที่น่าสนใจ:

  • ทำลายยานศัตรู N ลำ: เป็นเรื่องปกติที่เกมจะถูกแบ่งออกเป็นระดับต่าง ๆ โดยคุณต้องทำลายยานศัตรู N ลำเพื่อผ่านด่าน
  • ยานของคุณถูกทำลาย: มีเกมที่คุณจะแพ้ทันทีหากยานของคุณถูกทำลาย อีกวิธีที่นิยมคือการมีระบบชีวิต ทุกครั้งที่ยานของคุณถูกทำลายจะลดจำนวนชีวิตลง เมื่อชีวิตหมดคุณก็จะแพ้เกม
  • คุณสะสมคะแนน N คะแนน: เงื่อนไขการจบเกมอีกแบบคือการสะสมคะแนน วิธีการได้คะแนนขึ้นอยู่กับคุณ แต่โดยทั่วไปจะมีการให้คะแนนจากกิจกรรมต่าง ๆ เช่น การทำลายยานศัตรู หรือการเก็บไอเท็มที่หล่นเมื่อถูกทำลาย
  • ผ่านด่าน: อาจมีเงื่อนไขหลายอย่าง เช่น ทำลายยานศัตรู X ลำ สะสมคะแนน Y หรือเก็บไอเท็มเฉพาะ

การเพิ่มฟังก์ชันการเริ่มเกมใหม่

เกมที่ดีจะกระตุ้นให้เล่นซ้ำผ่านระบบเริ่มใหม่ที่ราบรื่น เมื่อผู้เล่นจบเกม (หรือแพ้) พวกเขามักต้องการลองอีกครั้งทันที - ไม่ว่าจะเพื่อทำคะแนนให้ดีกว่าเดิมหรือปรับปรุงการเล่นของตนเอง

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

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

สิ่งที่คุณจะสร้าง

คุณจะเพิ่มฟีเจอร์สุดท้ายที่เปลี่ยนโปรเจกต์ของคุณให้เป็นประสบการณ์เกมที่สมบูรณ์ ฟีเจอร์เหล่านี้แยกเกมที่สมบูรณ์แบบออกจากต้นแบบพื้นฐาน

นี่คือสิ่งที่เราจะเพิ่มวันนี้:

  1. เงื่อนไขการชนะ: ทำลายศัตรูทั้งหมดและรับการเฉลิมฉลองที่เหมาะสม (คุณสมควรได้รับมัน!)
  2. เงื่อนไขการแพ้: หมดชีวิตและพบกับหน้าจอแพ้
  3. ระบบเริ่มใหม่: กด Enter เพื่อกลับมาเล่นอีกครั้ง - เพราะเกมเดียวไม่เคยพอ
  4. การจัดการสถานะ: เริ่มใหม่ทุกครั้ง - ไม่มีศัตรูที่เหลือหรือข้อผิดพลาดแปลก ๆ จากเกมก่อนหน้า

เริ่มต้น

เตรียมสภาพแวดล้อมการพัฒนา คุณควรมีไฟล์เกมอวกาศทั้งหมดจากบทเรียนก่อนหน้า

โปรเจกต์ของคุณควรมีลักษณะดังนี้:

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

เริ่มเซิร์ฟเวอร์พัฒนา:

cd your-work
npm start

คำสั่งนี้:

  • รันเซิร์ฟเวอร์ในเครื่องที่ http://localhost:5000
  • ให้บริการไฟล์ของคุณอย่างถูกต้อง
  • รีเฟรชอัตโนมัติเมื่อคุณทำการเปลี่ยนแปลง

เปิด http://localhost:5000 ในเบราว์เซอร์ของคุณและตรวจสอบว่าเกมของคุณทำงานอยู่ คุณควรสามารถเคลื่อนที่ ยิง และโต้ตอบกับศัตรูได้ เมื่อยืนยันแล้ว เราสามารถดำเนินการต่อไปยังการพัฒนา

💡 เคล็ดลับ: เพื่อหลีกเลี่ยงคำเตือนใน Visual Studio Code ให้ประกาศ gameLoopId ที่ด้านบนของไฟล์ของคุณเป็น let gameLoopId; แทนที่จะประกาศภายในฟังก์ชัน window.onload วิธีนี้เป็นไปตามแนวปฏิบัติที่ดีที่สุดในการประกาศตัวแปรใน JavaScript สมัยใหม่

ขั้นตอนการพัฒนา

ขั้นตอนที่ 1: สร้างฟังก์ชันติดตามเงื่อนไขการจบเกม

เราต้องการฟังก์ชันเพื่อเฝ้าดูว่าเมื่อใดที่เกมควรจบ เหมือนกับเซ็นเซอร์บนสถานีอวกาศนานาชาติที่เฝ้าตรวจสอบระบบสำคัญ ๆ อย่างต่อเนื่อง ฟังก์ชันเหล่านี้จะตรวจสอบสถานะเกมอย่างต่อเนื่อง

function isHeroDead() {
  return hero.life <= 0;
}

function isEnemiesDead() {
  const enemies = gameObjects.filter((go) => go.type === "Enemy" && !go.dead);
  return enemies.length === 0;
}

สิ่งที่เกิดขึ้นเบื้องหลัง:

  • ตรวจสอบ ว่าฮีโร่ของเราหมดชีวิตหรือไม่ (โอ๊ย!)
  • นับ จำนวนศัตรูที่ยังมีชีวิตอยู่
  • คืนค่า true เมื่อสนามรบว่างเปล่าจากศัตรู
  • ใช้ตรรกะ true/false ที่เรียบง่ายเพื่อให้เข้าใจง่าย
  • กรองผ่านวัตถุเกมทั้งหมดเพื่อหาผู้รอดชีวิต

ขั้นตอนที่ 2: อัปเดตตัวจัดการเหตุการณ์สำหรับเงื่อนไขการจบเกม

ตอนนี้เราจะเชื่อมโยงการตรวจสอบเงื่อนไขเหล่านี้กับระบบเหตุการณ์ของเกม ทุกครั้งที่เกิดการชน เกมจะประเมินว่ามันกระตุ้นเงื่อนไขการจบเกมหรือไม่ สิ่งนี้สร้างการตอบสนองทันทีสำหรับเหตุการณ์สำคัญในเกม

eventEmitter.on(Messages.COLLISION_ENEMY_LASER, (_, { first, second }) => {
    first.dead = true;
    second.dead = true;
    hero.incrementPoints();

    if (isEnemiesDead()) {
      eventEmitter.emit(Messages.GAME_END_WIN);
    }
});

eventEmitter.on(Messages.COLLISION_ENEMY_HERO, (_, { enemy }) => {
    enemy.dead = true;
    hero.decrementLife();
    if (isHeroDead())  {
      eventEmitter.emit(Messages.GAME_END_LOSS);
      return; // loss before victory
    }
    if (isEnemiesDead()) {
      eventEmitter.emit(Messages.GAME_END_WIN);
    }
});

eventEmitter.on(Messages.GAME_END_WIN, () => {
    endGame(true);
});
  
eventEmitter.on(Messages.GAME_END_LOSS, () => {
  endGame(false);
});

สิ่งที่เกิดขึ้นที่นี่:

  • เลเซอร์ชนศัตรู: ทั้งคู่หายไป คุณได้คะแนน และเราตรวจสอบว่าคุณชนะหรือไม่
  • ศัตรูชนคุณ: คุณเสียชีวิต และเราตรวจสอบว่าคุณยังมีชีวิตอยู่หรือไม่
  • ลำดับที่ชาญฉลาด: เราตรวจสอบการแพ้ก่อน (ไม่มีใครอยากชนะและแพ้ในเวลาเดียวกัน!)
  • การตอบสนองทันที: ทันทีที่มีสิ่งสำคัญเกิดขึ้น เกมจะรับรู้

ขั้นตอนที่ 3: เพิ่มค่าคงที่ข้อความใหม่

คุณจะต้องเพิ่มประเภทข้อความใหม่ลงในวัตถุค่าคงที่ Messages ค่าคงที่เหล่านี้ช่วยรักษาความสอดคล้องและป้องกันข้อผิดพลาดในการพิมพ์ในระบบเหตุการณ์ของคุณ

GAME_END_LOSS: "GAME_END_LOSS",
GAME_END_WIN: "GAME_END_WIN",

ในส่วนนี้ เราได้:

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

ขั้นตอนที่ 4: เพิ่มการควบคุมการเริ่มเกมใหม่

ตอนนี้คุณจะเพิ่มการควบคุมคีย์บอร์ดที่อนุญาตให้ผู้เล่นเริ่มเกมใหม่ได้ กดปุ่ม Enter เป็นตัวเลือกที่เหมาะสมเนื่องจากมักเกี่ยวข้องกับการยืนยันการกระทำและการเริ่มเกมใหม่

เพิ่มการตรวจจับปุ่ม Enter ลงในตัวฟังเหตุการณ์ keydown ที่มีอยู่ของคุณ:

else if(evt.key === "Enter") {
   eventEmitter.emit(Messages.KEY_EVENT_ENTER);
}

เพิ่มค่าคงที่ข้อความใหม่:

KEY_EVENT_ENTER: "KEY_EVENT_ENTER",

สิ่งที่คุณต้องรู้:

  • ขยายระบบการจัดการเหตุการณ์คีย์บอร์ดที่มีอยู่ของคุณ
  • ใช้ปุ่ม Enter เป็นตัวกระตุ้นการเริ่มเกมใหม่เพื่อประสบการณ์ผู้ใช้ที่เข้าใจง่าย
  • ส่งเหตุการณ์ที่กำหนดเองที่ส่วนอื่น ๆ ของเกมของคุณสามารถฟังได้
  • รักษารูปแบบเดียวกับการควบคุมคีย์บอร์ดอื่น ๆ ของคุณ

ขั้นตอนที่ 5: สร้างระบบแสดงข้อความ

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

สร้างฟังก์ชัน displayMessage():

function displayMessage(message, color = "red") {
  ctx.font = "30px Arial";
  ctx.fillStyle = color;
  ctx.textAlign = "center";
  ctx.fillText(message, canvas.width / 2, canvas.height / 2);
}

ทีละขั้นตอน สิ่งที่เกิดขึ้น:

  • ตั้งค่าขนาดและรูปแบบตัวอักษรเพื่อให้ข้อความอ่านง่าย
  • ใช้พารามิเตอร์สี โดยมี "สีแดง" เป็นค่าเริ่มต้นสำหรับคำเตือน
  • จัดกึ่งกลางข้อความในแนวนอนและแนวตั้งบนแคนวาส
  • ใช้พารามิเตอร์เริ่มต้นของ JavaScript สมัยใหม่เพื่อความยืดหยุ่นของตัวเลือกสี
  • ใช้บริบท 2D ของแคนวาสเพื่อการแสดงผลข้อความโดยตรง

สร้างฟังก์ชัน endGame():

function endGame(win) {
  clearInterval(gameLoopId);

  // Set a delay to ensure any pending renders complete
  setTimeout(() => {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    ctx.fillStyle = "black";
    ctx.fillRect(0, 0, canvas.width, canvas.height);
    if (win) {
      displayMessage(
        "Victory!!! Pew Pew... - Press [Enter] to start a new game Captain Pew Pew",
        "green"
      );
    } else {
      displayMessage(
        "You died !!! Press [Enter] to start a new game Captain Pew Pew"
      );
    }
  }, 200)  
}

สิ่งที่ฟังก์ชันนี้ทำ:

  • หยุดทุกอย่างในที่ - ไม่มีการเคลื่อนที่ของยานหรือเลเซอร์อีกต่อไป
  • หยุดชั่วคราวเล็กน้อย (200ms) เพื่อให้เฟรมสุดท้ายวาดเสร็จ
  • ล้างหน้าจอให้สะอาดและเปลี่ยนเป็นสีดำเพื่อความดราม่า
  • แสดงข้อความที่แตกต่างกันสำหรับผู้ชนะและผู้แพ้
  • ใช้สีเพื่อสื่อสาร - สีเขียวสำหรับข่าวดี สีแดงสำหรับ...ข่าวร้าย
  • บอกผู้เล่นว่าต้องทำอย่างไรเพื่อกลับมาเล่นอีกครั้ง

ขั้นตอนที่ 6: เพิ่มฟังก์ชันการรีเซ็ตเกม

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

สร้างฟังก์ชัน resetGame():

function resetGame() {
  if (gameLoopId) {
    clearInterval(gameLoopId);
    eventEmitter.clear();
    initGame();
    gameLoopId = setInterval(() => {
      ctx.clearRect(0, 0, canvas.width, canvas.height);
      ctx.fillStyle = "black";
      ctx.fillRect(0, 0, canvas.width, canvas.height);
      drawPoints();
      drawLife();
      updateGameObjects();
      drawGameObjects(ctx);
    }, 100);
  }
}

มาทำความเข้าใจแต่ละส่วน:

  • ตรวจสอบว่ามีลูปเกมที่กำลังทำงานอยู่ก่อนที่จะรีเซ็ต
  • ล้างลูปเกมที่มีอยู่เพื่อหยุดกิจกรรมเกมปัจจุบันทั้งหมด
  • ลบตัวฟังเหตุการณ์ทั้งหมดเพื่อป้องกันการรั่วไหลของหน่วยความจำ
  • เริ่มต้นใหม่สถานะเกมด้วยวัตถุและตัวแปรใหม่
  • เริ่มต้นลูปเกมใหม่ด้วยฟังก์ชันเกมที่จำเป็นทั้งหมด
  • รักษาช่วงเวลา 100ms เดิมเพื่อประสิทธิภาพของเกมที่สม่ำเสมอ

เพิ่มตัวจัดการเหตุการณ์ปุ่ม Enter ลงในฟังก์ชัน initGame():

eventEmitter.on(Messages.KEY_EVENT_ENTER, () => {
  resetGame();
});

เพิ่มเมธอด clear() ลงในคลาส EventEmitter ของคุณ:

clear() {
  this.listeners = {};
}

จุดสำคัญที่ต้องจำ:

  • เชื่อมโยงการกดปุ่ม Enter กับฟังก์ชันการรีเซ็ตเกม
  • ลงทะเบียนตัวฟังเหตุการณ์นี้ระหว่างการเริ่มต้นเกม
  • ให้วิธีการลบตัวฟังเหตุการณ์ทั้งหมดเมื่อรีเซ็ต
  • ป้องกันการรั่วไหลของหน่วยความจำโดยการล้างตัวจัดการเหตุการณ์ระหว่างเกม
  • รีเซ็ตวัตถุ listeners ให้เป็นสถานะว่างเปล่าเพื่อการเริ่มต้นใหม่

ยินดีด้วย! 🎉

👽 💥 🚀 คุณได้สร้างเกมที่สมบูรณ์แบบจากศูนย์สำเร็จแล้ว เหมือนกับโปรแกรมเมอร์ที่สร้างวิดีโอเกมแรกในยุค 1970 คุณได้เปลี่ยนโค้ดให้กลายเป็นประสบการณ์การเล่นเกมที่มีกลไกเกมและการตอบสนองผู้ใช้ที่เหมาะสม 🚀 💥 👽

สิ่งที่คุณทำสำเร็จ:

  • เพิ่มเงื่อนไขการชนะและแพ้ที่สมบูรณ์พร้อมการตอบสนองผู้ใช้
  • สร้างระบบเริ่มใหม่ที่ราบรื่นสำหรับการเล่นเกมต่อเนื่อง
  • ออกแบบการสื่อสารภาพที่ชัดเจนสำหรับสถานะเกม
  • จัดการการเปลี่ยนแปลงสถานะเกมที่ซับซ้อนและการทำความสะอาด
  • ประกอบส่วนประกอบทั้งหมดให้เป็นเกมที่เล่นได้อย่างสมบูรณ์

ความท้าทาย GitHub Copilot Agent 🚀

ใช้โหมด Agent เพื่อทำความท้าทายต่อไปนี้:

คำอธิบาย: ปรับปรุงเกมอวกาศโดยเพิ่มระบบความก้าวหน้าของระดับที่มีความยากเพิ่มขึ้นและฟีเจอร์โบนัส

คำสั่ง: สร้างระบบเกมอวกาศแบบหลายระดับที่แต่ละระดับมียานศัตรูมากขึ้นพร้อมความเร็วและพลังชีวิตที่เพิ่มขึ้น เพิ่มตัวคูณคะแนนที่เพิ่มขึ้นในแต่ละระดับ และเพิ่มพลังพิเศษ (เช่น การยิงเร็วหรือโล่) ที่ปรากฏแบบสุ่มเมื่อศัตรูถูกทำลาย รวมโบนัสการจบระดับและแสดงระดับปัจจุบันบนหน้าจอควบคู่ไปกับคะแนนและชีวิตที่มีอยู่

เรียนรู้เพิ่มเติมเกี่ยวกับ agent mode ได้ที่นี่

🚀 ความท้าทายเสริมเพิ่มเติม

เพิ่มเสียงในเกมของคุณ: เพิ่มประสบการณ์การเล่นเกมของคุณโดยการเพิ่มเอฟเฟกต์เสียง! ลองเพิ่มเสียงสำหรับ:

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

ตัวอย่างการเพิ่มเสียง:

// Create audio objects
const laserSound = new Audio('assets/laser.wav');
const explosionSound = new Audio('assets/explosion.wav');

// Play sounds during game events
function playLaserSound() {
  laserSound.currentTime = 0; // Reset to beginning
  laserSound.play();
}

สิ่งที่คุณต้องรู้:

  • สร้างวัตถุเสียงสำหรับเอฟเฟกต์เสียงต่าง ๆ
  • รีเซ็ต currentTime เพื่อให้เอฟเฟกต์เสียงทำงานได้อย่างรวดเร็ว
  • จัดการนโยบายการเล่นอัตโนมัติของเบราว์เซอร์โดยการกระตุ้นเสียงจากการโต้ตอบของผู้ใช้
  • จัดการระดับเสียงและเวลาเสียงเพื่อประสบการณ์เกมที่ดีขึ้น

💡 แหล่งเรียนรู้: สำรวจ audio sandbox เพื่อเรียนรู้เพิ่มเติมเกี่ยวกับการเพิ่มเสียงในเกม JavaScript

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

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

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

การบ้านของคุณคือการสร้างตัวอย่างเกมใหม่ ดังนั้นลองสำรวจเกมที่น่าสนใจบางเกมเพื่อดูว่าคุณอาจสร้างเกมประเภทใด

การบ้าน

สร้างตัวอย่างเกม


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