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/3-moving-elements-around/README.md

464 lines
40 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<!--
CO_OP_TRANSLATOR_METADATA:
{
"original_hash": "022bbb5c869091b98f19e408e0c51d5d",
"translation_date": "2025-10-23T21:17:20+00:00",
"source_file": "6-space-game/3-moving-elements-around/README.md",
"language_code": "th"
}
-->
# สร้างเกมอวกาศ ตอนที่ 3: เพิ่มการเคลื่อนไหว
ลองนึกถึงเกมโปรดของคุณ สิ่งที่ทำให้เกมน่าดึงดูดไม่ใช่แค่กราฟิกที่สวยงาม แต่เป็นวิธีที่ทุกอย่างเคลื่อนไหวและตอบสนองต่อการกระทำของคุณ ตอนนี้เกมอวกาศของคุณเหมือนภาพวาดที่สวยงาม แต่เรากำลังจะเพิ่มการเคลื่อนไหวเพื่อทำให้มันมีชีวิตชีวา
เมื่อวิศวกรของ NASA เขียนโปรแกรมคอมพิวเตอร์นำทางสำหรับภารกิจ Apollo พวกเขาเผชิญกับความท้าทายที่คล้ายกัน: จะทำให้ยานอวกาศตอบสนองต่อการควบคุมของนักบินในขณะที่ยังคงรักษาการปรับเส้นทางอัตโนมัติได้อย่างไร หลักการที่เราจะเรียนรู้ในวันนี้สะท้อนแนวคิดเดียวกัน การจัดการการเคลื่อนไหวที่ควบคุมโดยผู้เล่นควบคู่ไปกับพฤติกรรมของระบบอัตโนมัติ
ในบทเรียนนี้ คุณจะได้เรียนรู้วิธีทำให้ยานอวกาศลอยไปบนหน้าจอ ตอบสนองต่อคำสั่งของผู้เล่น และสร้างรูปแบบการเคลื่อนไหวที่ราบรื่น เราจะอธิบายทุกอย่างให้เข้าใจง่ายและเป็นขั้นตอน
เมื่อจบบทเรียนนี้ ผู้เล่นจะสามารถบังคับยานฮีโร่ของพวกเขาไปรอบ ๆ หน้าจอ ในขณะที่ยานศัตรูลาดตระเวนอยู่ด้านบน และที่สำคัญที่สุด คุณจะเข้าใจหลักการสำคัญที่ขับเคลื่อนระบบการเคลื่อนไหวในเกม
## แบบทดสอบก่อนเรียน
[แบบทดสอบก่อนเรียน](https://ff-quizzes.netlify.app/web/quiz/33)
## ทำความเข้าใจการเคลื่อนไหวในเกม
เกมจะมีชีวิตชีวาเมื่อสิ่งต่าง ๆ เริ่มเคลื่อนไหว และโดยพื้นฐานแล้วมีสองวิธีที่สิ่งนี้เกิดขึ้น:
- **การเคลื่อนไหวที่ควบคุมโดยผู้เล่น**: เมื่อคุณกดปุ่มหรือคลิกเมาส์ สิ่งต่าง ๆ จะเคลื่อนไหว นี่คือการเชื่อมต่อโดยตรงระหว่างคุณกับโลกของเกม
- **การเคลื่อนไหวอัตโนมัติ**: เมื่อเกมตัดสินใจเคลื่อนย้ายสิ่งต่าง ๆ เอง เช่น ยานศัตรูที่ต้องลาดตระเวนบนหน้าจอไม่ว่าคุณจะทำอะไรหรือไม่ก็ตาม
การทำให้วัตถุเคลื่อนที่บนหน้าจอคอมพิวเตอร์นั้นง่ายกว่าที่คุณคิด จำพิกัด x และ y จากชั้นเรียนคณิตศาสตร์ได้ไหม? นั่นแหละที่เรากำลังทำงานด้วย เมื่อกาลิเลโอเฝ้าสังเกตดวงจันทร์ของดาวพฤหัสบดีในปี 1610 เขาก็ทำสิ่งเดียวกัน วางตำแหน่งตามเวลาเพื่อทำความเข้าใจรูปแบบการเคลื่อนไหว
การเคลื่อนย้ายสิ่งต่าง ๆ บนหน้าจอเหมือนกับการสร้างภาพเคลื่อนไหวแบบพลิกหน้า คุณต้องทำตามสามขั้นตอนง่าย ๆ นี้:
1. **อัปเดตตำแหน่ง** เปลี่ยนตำแหน่งของวัตถุ (อาจจะเลื่อนไปทางขวา 5 พิกเซล)
2. **ลบเฟรมเก่า** ล้างหน้าจอเพื่อไม่ให้เห็นร่องรอยที่หลงเหลือ
3. **วาดเฟรมใหม่** วางวัตถุในตำแหน่งใหม่
ทำสิ่งนี้เร็วพอ แล้วบูม! คุณจะได้การเคลื่อนไหวที่ราบรื่นและรู้สึกเป็นธรรมชาติสำหรับผู้เล่น
นี่คือตัวอย่างในโค้ด:
```javascript
// Set the hero's location
hero.x += 5;
// Clear the rectangle that hosts the hero
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Redraw the game background and hero
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = "black";
ctx.drawImage(heroImg, hero.x, hero.y);
```
**สิ่งที่โค้ดนี้ทำ:**
- **อัปเดต** พิกัด x ของฮีโร่โดย 5 พิกเซลเพื่อเคลื่อนที่ในแนวนอน
- **ล้าง** พื้นที่แคนวาสทั้งหมดเพื่อลบเฟรมก่อนหน้า
- **เติม** พื้นหลังของแคนวาสด้วยสีดำ
- **วาดใหม่** ภาพฮีโร่ในตำแหน่งใหม่
✅ คุณคิดว่าการวาดฮีโร่ใหม่หลายเฟรมต่อวินาทีอาจส่งผลต่อประสิทธิภาพได้อย่างไร? อ่านเพิ่มเติมเกี่ยวกับ [ทางเลือกสำหรับรูปแบบนี้](https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Optimizing_canvas)
## จัดการเหตุการณ์คีย์บอร์ด
นี่คือจุดที่เราจะเชื่อมโยงการป้อนข้อมูลของผู้เล่นกับการกระทำในเกม เมื่อมีคนกด spacebar เพื่อยิงเลเซอร์หรือกดปุ่มลูกศรเพื่อหลบดาวเคราะห์น้อย เกมของคุณต้องตรวจจับและตอบสนองต่อการป้อนข้อมูลนั้น
เหตุการณ์คีย์บอร์ดเกิดขึ้นในระดับหน้าต่าง หมายความว่าหน้าต่างเบราว์เซอร์ทั้งหมดของคุณกำลังฟังการกดปุ่มเหล่านั้น ในทางกลับกัน การคลิกเมาส์สามารถผูกกับองค์ประกอบเฉพาะ (เช่น การคลิกปุ่ม) สำหรับเกมอวกาศของเรา เราจะเน้นที่การควบคุมด้วยคีย์บอร์ดเพราะนั่นคือสิ่งที่ให้ความรู้สึกเหมือนเกมอาร์เคดคลาสสิก
สิ่งนี้ทำให้ฉันนึกถึงวิธีที่ผู้ปฏิบัติการโทรเลขในศตวรรษที่ 19 ต้องแปลการป้อนข้อมูลรหัสมอร์สให้เป็นข้อความที่มีความหมาย เรากำลังทำสิ่งที่คล้ายกัน โดยแปลงการกดปุ่มให้เป็นคำสั่งในเกม
ในการจัดการเหตุการณ์ คุณต้องใช้เมธอด `addEventListener()` ของหน้าต่างและให้พารามิเตอร์สองตัวเป็นอินพุต พารามิเตอร์แรกคือชื่อของเหตุการณ์ เช่น `keyup` พารามิเตอร์ที่สองคือฟังก์ชันที่จะถูกเรียกใช้เมื่อเหตุการณ์เกิดขึ้น
ตัวอย่าง:
```javascript
window.addEventListener('keyup', (evt) => {
// evt.key = string representation of the key
if (evt.key === 'ArrowUp') {
// do something
}
});
```
**การอธิบายสิ่งที่เกิดขึ้นในที่นี้:**
- **ฟัง** เหตุการณ์คีย์บอร์ดในหน้าต่างทั้งหมด
- **จับ** ออบเจ็กต์เหตุการณ์ที่มีข้อมูลเกี่ยวกับปุ่มที่ถูกกด
- **ตรวจสอบ** ว่าปุ่มที่กดตรงกับปุ่มเฉพาะหรือไม่ (ในกรณีนี้คือปุ่มลูกศรขึ้น)
- **ดำเนินการ** โค้ดเมื่อเงื่อนไขตรงกัน
สำหรับเหตุการณ์คีย์ มีสองคุณสมบัติในเหตุการณ์ที่คุณสามารถใช้เพื่อดูว่าปุ่มใดถูกกด:
- `key` - เป็นตัวแทนข้อความของปุ่มที่กด เช่น `'ArrowUp'`
- `keyCode` - เป็นตัวแทนตัวเลข เช่น `37` ซึ่งตรงกับ `ArrowLeft`
✅ การจัดการเหตุการณ์คีย์มีประโยชน์นอกเหนือจากการพัฒนาเกม คุณคิดว่าเทคนิคนี้สามารถนำไปใช้ในด้านอื่น ๆ ได้อย่างไร?
### ปุ่มพิเศษ: ข้อควรระวัง!
บางปุ่มมีพฤติกรรมในตัวเบราว์เซอร์ที่อาจรบกวนเกมของคุณ ปุ่มลูกศรเลื่อนหน้า และ spacebar กระโดดลง พฤติกรรมที่คุณไม่ต้องการเมื่อมีคนพยายามควบคุมยานอวกาศของพวกเขา
เราสามารถป้องกันพฤติกรรมเริ่มต้นเหล่านี้และให้เกมของเราจัดการการป้อนข้อมูลแทน สิ่งนี้คล้ายกับวิธีที่โปรแกรมเมอร์คอมพิวเตอร์ยุคแรกต้องเขียนทับการขัดจังหวะของระบบเพื่อสร้างพฤติกรรมที่กำหนดเอง เราแค่ทำในระดับเบราว์เซอร์ นี่คือวิธี:
```javascript
const onKeyDown = function (e) {
console.log(e.keyCode);
switch (e.keyCode) {
case 37:
case 39:
case 38:
case 40: // Arrow keys
case 32:
e.preventDefault();
break; // Space
default:
break; // do not block other keys
}
};
window.addEventListener('keydown', onKeyDown);
```
**การทำความเข้าใจโค้ดป้องกันนี้:**
- **ตรวจสอบ** รหัสปุ่มเฉพาะที่อาจทำให้เกิดพฤติกรรมเบราว์เซอร์ที่ไม่ต้องการ
- **ป้องกัน** การกระทำเริ่มต้นของเบราว์เซอร์สำหรับปุ่มลูกศรและ spacebar
- **อนุญาต** ให้ปุ่มอื่นทำงานตามปกติ
- **ใช้** `e.preventDefault()` เพื่อหยุดพฤติกรรมในตัวของเบราว์เซอร์
## การเคลื่อนไหวที่เกิดจากเกม
ตอนนี้เรามาพูดถึงวัตถุที่เคลื่อนไหวโดยไม่มีการป้อนข้อมูลจากผู้เล่น ลองนึกถึงยานศัตรูที่ล่องลอยบนหน้าจอ กระสุนที่บินเป็นเส้นตรง หรือเมฆที่ลอยอยู่ในพื้นหลัง การเคลื่อนไหวอัตโนมัตินี้ทำให้โลกของเกมของคุณรู้สึกมีชีวิตชีวาแม้ไม่มีใครแตะต้องการควบคุม
เราใช้ตัวจับเวลาที่มีอยู่ใน JavaScript เพื่ออัปเดตตำแหน่งในช่วงเวลาปกติ แนวคิดนี้คล้ายกับวิธีการทำงานของนาฬิกาลูกตุ้ม กลไกปกติที่กระตุ้นการกระทำที่สม่ำเสมอและตรงเวลา นี่คือวิธีที่ง่าย:
```javascript
const id = setInterval(() => {
// Move the enemy on the y axis
enemy.y += 10;
}, 100);
```
**สิ่งที่โค้ดการเคลื่อนไหวนี้ทำ:**
- **สร้าง** ตัวจับเวลาที่ทำงานทุก ๆ 100 มิลลิวินาที
- **อัปเดต** พิกัด y ของศัตรูโดย 10 พิกเซลทุกครั้ง
- **เก็บ** ID ของช่วงเวลาเพื่อหยุดมันในภายหลังหากจำเป็น
- **เคลื่อนย้าย** ศัตรูลงบนหน้าจอโดยอัตโนมัติ
## วงลูปของเกม
นี่คือแนวคิดที่ผูกทุกอย่างเข้าด้วยกัน วงลูปของเกม หากเกมของคุณเป็นภาพยนตร์ วงลูปของเกมจะเป็นเครื่องฉายภาพยนตร์ที่แสดงเฟรมต่อเฟรมอย่างรวดเร็วจนทุกอย่างดูเหมือนเคลื่อนไหวอย่างราบรื่น
ทุกเกมมีวงลูปเหล่านี้ทำงานอยู่เบื้องหลัง เป็นฟังก์ชันที่อัปเดตวัตถุเกมทั้งหมด วาดหน้าจอใหม่ และทำซ้ำกระบวนการนี้อย่างต่อเนื่อง สิ่งนี้ช่วยติดตามฮีโร่ของคุณ ศัตรูทั้งหมด เลเซอร์ที่บินไปรอบ ๆ สถานะของเกมทั้งหมด
แนวคิดนี้ทำให้ฉันนึกถึงวิธีที่นักวาดภาพยนตร์ยุคแรก ๆ เช่น Walt Disney ต้องวาดตัวละครใหม่เฟรมต่อเฟรมเพื่อสร้างภาพลวงตาของการเคลื่อนไหว เรากำลังทำสิ่งเดียวกัน เพียงแค่ใช้โค้ดแทนดินสอ
นี่คือสิ่งที่วงลูปของเกมมักจะมีลักษณะเป็นโค้ด:
```javascript
const gameLoopId = setInterval(() => {
function gameLoop() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = "black";
ctx.fillRect(0, 0, canvas.width, canvas.height);
drawHero();
drawEnemies();
drawStaticObjects();
}
gameLoop();
}, 200);
```
**การทำความเข้าใจโครงสร้างวงลูปของเกม:**
- **ล้าง** แคนวาสทั้งหมดเพื่อลบเฟรมก่อนหน้า
- **เติม** พื้นหลังด้วยสีทึบ
- **วาด** วัตถุเกมทั้งหมดในตำแหน่งปัจจุบันของพวกมัน
- **ทำซ้ำ** กระบวนการนี้ทุก ๆ 200 มิลลิวินาทีเพื่อสร้างภาพเคลื่อนไหวที่ราบรื่น
- **จัดการ** อัตราเฟรมโดยการควบคุมช่วงเวลาเวลา
## การพัฒนาเกมอวกาศต่อไป
ตอนนี้เราจะเพิ่มการเคลื่อนไหวให้กับฉากนิ่งที่คุณสร้างไว้ก่อนหน้านี้ เรากำลังจะเปลี่ยนมันจากภาพหน้าจอเป็นประสบการณ์แบบโต้ตอบ เราจะทำงานผ่านขั้นตอนนี้ทีละขั้นตอนเพื่อให้แน่ใจว่าแต่ละส่วนสร้างขึ้นจากส่วนก่อนหน้า
ดึงโค้ดจากที่ที่เราหยุดในบทเรียนก่อนหน้า (หรือเริ่มต้นด้วยโค้ดในโฟลเดอร์ [Part II- starter](../../../../6-space-game/3-moving-elements-around/your-work) หากคุณต้องการเริ่มต้นใหม่)
**นี่คือสิ่งที่เรากำลังสร้างวันนี้:**
- **การควบคุมฮีโร่**: ใช้ปุ่มลูกศรเพื่อบังคับยานอวกาศของคุณบนหน้าจอ
- **การเคลื่อนไหวของศัตรู**: ยานเอเลี่ยนเหล่านั้นจะเริ่มการโจมตี
มาเริ่มต้นการเพิ่มฟีเจอร์เหล่านี้กันเถอะ
## ขั้นตอนที่แนะนำ
ค้นหาไฟล์ที่ถูกสร้างไว้ให้คุณในโฟลเดอร์ `your-work` มันควรมีสิ่งต่อไปนี้:
```bash
-| assets
-| enemyShip.png
-| player.png
-| index.html
-| app.js
-| package.json
```
เริ่มโปรเจกต์ของคุณในโฟลเดอร์ `your-work` โดยพิมพ์:
```bash
cd your-work
npm start
```
**สิ่งที่คำสั่งนี้ทำ:**
- **นำทาง** ไปยังไดเรกทอรีโปรเจกต์ของคุณ
- **เริ่มต้น** HTTP Server ที่อยู่ `http://localhost:5000`
- **ให้บริการ** ไฟล์เกมของคุณเพื่อทดสอบในเบราว์เซอร์
คำสั่งด้านบนจะเริ่ม HTTP Server ที่อยู่ `http://localhost:5000` เปิดเบราว์เซอร์และใส่ที่อยู่นั้น ตอนนี้มันควรจะแสดงฮีโร่และศัตรูทั้งหมด; แต่ยังไม่มีอะไรเคลื่อนไหว ยัง!
### เพิ่มโค้ด
1. **เพิ่มออบเจ็กต์เฉพาะ** สำหรับ `hero` และ `enemy` และ `game object` ซึ่งควรมีคุณสมบัติ `x` และ `y` (จำส่วนเกี่ยวกับ [Inheritance หรือ composition](../README.md))
*คำแนะนำ* `game object` ควรเป็นออบเจ็กต์ที่มี `x` และ `y` และความสามารถในการวาดตัวเองลงบนแคนวาส
> **เคล็ดลับ**: เริ่มต้นด้วยการเพิ่มคลาส `GameObject` ใหม่พร้อมตัวสร้างที่กำหนดไว้ดังนี้ และวาดมันลงบนแคนวาส:
```javascript
class GameObject {
constructor(x, y) {
this.x = x;
this.y = y;
this.dead = false;
this.type = "";
this.width = 0;
this.height = 0;
this.img = undefined;
}
draw(ctx) {
ctx.drawImage(this.img, this.x, this.y, this.width, this.height);
}
}
```
**การทำความเข้าใจคลาสพื้นฐานนี้:**
- **กำหนด** คุณสมบัติทั่วไปที่วัตถุเกมทั้งหมดมีร่วมกัน (ตำแหน่ง ขนาด ภาพ)
- **รวมถึง** ธง `dead` เพื่อติดตามว่าวัตถุควรถูกลบหรือไม่
- **ให้** เมธอด `draw()` ที่แสดงวัตถุบนแคนวาส
- **ตั้งค่า** ค่าเริ่มต้นสำหรับคุณสมบัติทั้งหมดที่คลาสลูกสามารถเขียนทับได้
ตอนนี้ ขยาย `GameObject` เพื่อสร้าง `Hero` และ `Enemy`:
```javascript
class Hero extends GameObject {
constructor(x, y) {
super(x, y);
this.width = 98;
this.height = 75;
this.type = "Hero";
this.speed = 5;
}
}
```
```javascript
class Enemy extends GameObject {
constructor(x, y) {
super(x, y);
this.width = 98;
this.height = 50;
this.type = "Enemy";
const id = setInterval(() => {
if (this.y < canvas.height - this.height) {
this.y += 5;
} else {
console.log('Stopped at', this.y);
clearInterval(id);
}
}, 300);
}
}
```
**แนวคิดสำคัญในคลาสเหล่านี้:**
- **สืบทอด** จาก `GameObject` โดยใช้คำสำคัญ `extends`
- **เรียก** ตัวสร้างของคลาสแม่ด้วย `super(x, y)`
- **ตั้งค่า** ขนาดและคุณสมบัติเฉพาะสำหรับแต่ละประเภทของวัตถุ
- **นำไปใช้** การเคลื่อนไหวอัตโนมัติสำหรับศัตรูโดยใช้ `setInterval()`
2. **เพิ่มตัวจัดการเหตุการณ์คีย์** เพื่อจัดการการนำทางด้วยคีย์ (เคลื่อนย้ายฮีโร่ขึ้น/ลง ซ้าย/ขวา)
*จำไว้* ว่ามันเป็นระบบคาร์ทีเซียน มุมบนซ้ายคือ `0,0` และอย่าลืมเพิ่มโค้ดเพื่อหยุด *พฤติกรรมเริ่มต้น*
> **เคล็ดลับ**: สร้างฟังก์ชัน `onKeyDown` ของคุณและผูกมันกับหน้าต่าง:
```javascript
const onKeyDown = function (e) {
console.log(e.keyCode);
// Add the code from the lesson above to stop default behavior
switch (e.keyCode) {
case 37:
case 39:
case 38:
case 40: // Arrow keys
case 32:
e.preventDefault();
break; // Space
default:
break; // do not block other keys
}
};
window.addEventListener("keydown", onKeyDown);
```
**สิ่งที่ตัวจัดการเหตุการณ์นี้ทำ:**
- **ฟัง** เหตุการณ์ keydown ในหน้าต่างทั้งหมด
- **บันทึก** รหัสคีย์เพื่อช่วยคุณดีบักว่าปุ่มใดถูกกด
- **ป้องกัน** พฤติกรรมเริ่มต้นของเบราว์เซอร์สำหรับปุ่มลูกศรและ spacebar
- **อนุญาต** ให้ปุ่มอื่นทำงานตามปกติ
ตรวจสอบคอนโซลเบราว์เซอร์ของคุณ จุดนี้ และดูการกดปุ่มที่ถูกบันทึกไว้
3. **นำไปใช้** [Pub sub pattern](../README.md) สิ่งนี้จะช่วยให้โค้ดของคุณสะอาดเมื่อคุณทำตามส่วนที่เหลือ
รูปแบบ Publish-Subscribe ช่วยจัดระเบียบโค้ดของคุณโดยแยกการตรวจจับเหตุการณ์ออกจากการจัดการเหตุการณ์ สิ่งนี้ทำให้โค้ดของคุณมีความเป็นโมดูลและดูแลรักษาได้ง่ายขึ้น
ในการทำส่วนสุดท้ายนี้ คุณสามารถ:
1. **เพิ่มตัวฟังเหตุการณ์** ในหน้าต่าง:
```javascript
window.addEventListener("keyup", (evt) => {
if (evt.key === "ArrowUp") {
eventEmitter.emit(Messages.KEY_EVENT_UP);
} else if (evt.key === "ArrowDown") {
eventEmitter.emit(Messages.KEY_EVENT_DOWN);
} else if (evt.key === "ArrowLeft") {
eventEmitter.emit(Messages.KEY_EVENT_LEFT);
} else if (evt.key === "ArrowRight") {
eventEmitter.emit(Messages.KEY_EVENT_RIGHT);
}
});
```
**สิ่งที่ระบบเหตุการณ์นี้ทำ:**
- **ตรวจจับ** การป้อนข้อมูลคีย์บอร์ดและแปลงเป็นเหตุการณ์เกมที่กำหนดเอง
- **แยก** การตรวจจับการป้อนข้อมูลออกจากตรรกะของเกม
- **ทำให้** การเปลี่ยนแปลงการควบคุมในภายหลังง่ายขึ้นโดยไม่กระทบต่อโค้ดเกม
- **อนุญาต** ให้ระบบหลายระบบ
- **สร้าง** ตารางของศัตรูโดยใช้ลูปซ้อนกัน
- **กำหนด** ภาพศัตรูให้กับวัตถุศัตรูแต่ละตัว
- **เพิ่ม** ศัตรูแต่ละตัวลงในอาร์เรย์วัตถุเกมแบบ global
และเพิ่มฟังก์ชัน `createHero()` เพื่อทำกระบวนการคล้ายกันสำหรับฮีโร่
```javascript
function createHero() {
hero = new Hero(
canvas.width / 2 - 45,
canvas.height - canvas.height / 4
);
hero.img = heroImg;
gameObjects.push(hero);
}
```
**สิ่งที่การสร้างฮีโร่ทำ:**
- **กำหนดตำแหน่ง** ฮีโร่ให้อยู่ตรงกลางด้านล่างของหน้าจอ
- **กำหนด** ภาพฮีโร่ให้กับวัตถุฮีโร่
- **เพิ่ม** ฮีโร่ลงในอาร์เรย์วัตถุเกมเพื่อการแสดงผล
และสุดท้าย เพิ่มฟังก์ชัน `drawGameObjects()` เพื่อเริ่มการวาด
```javascript
function drawGameObjects(ctx) {
gameObjects.forEach(go => go.draw(ctx));
}
```
**ทำความเข้าใจฟังก์ชันการวาด:**
- **วนลูป** ผ่านวัตถุเกมทั้งหมดในอาร์เรย์
- **เรียกใช้** เมธอด `draw()` บนวัตถุแต่ละตัว
- **ส่งผ่าน** context ของ canvas เพื่อให้วัตถุสามารถแสดงผลตัวเองได้
ศัตรูของคุณควรเริ่มเคลื่อนที่เข้าหายานอวกาศฮีโร่ของคุณ!
}
}
```
and add a `createHero()` function to do a similar process for the hero.
```javascript
function createHero() {
hero = new Hero(
canvas.width / 2 - 45,
canvas.height - canvas.height / 4
);
hero.img = heroImg;
gameObjects.push(hero);
}
```
และสุดท้าย เพิ่มฟังก์ชัน `drawGameObjects()` เพื่อเริ่มการวาด
```javascript
function drawGameObjects(ctx) {
gameObjects.forEach(go => go.draw(ctx));
}
```
ศัตรูของคุณควรเริ่มเคลื่อนที่เข้าหายานอวกาศฮีโร่ของคุณ!
---
## GitHub Copilot Agent Challenge 🚀
นี่คือความท้าทายที่จะช่วยปรับปรุงความสมบูรณ์ของเกมของคุณ: การเพิ่มขอบเขตและการควบคุมที่ลื่นไหล ปัจจุบันฮีโร่ของคุณสามารถบินออกนอกหน้าจอได้ และการเคลื่อนไหวอาจดูไม่ราบรื่น
**ภารกิจของคุณ:** ทำให้ยานอวกาศของคุณรู้สึกสมจริงมากขึ้นโดยการเพิ่มขอบเขตหน้าจอและการควบคุมที่ลื่นไหล นี่คล้ายกับระบบควบคุมการบินของ NASA ที่ป้องกันไม่ให้ยานอวกาศเกินพารามิเตอร์การปฏิบัติการที่ปลอดภัย
**สิ่งที่ต้องสร้าง:** สร้างระบบที่ทำให้ยานอวกาศฮีโร่ของคุณอยู่ในหน้าจอ และทำให้การควบคุมรู้สึกลื่นไหล เมื่อผู้เล่นกดปุ่มลูกศรค้างไว้ ยานควรลื่นไหลต่อเนื่องแทนที่จะเคลื่อนที่เป็นขั้นๆ ลองพิจารณาเพิ่มการตอบสนองภาพเมื่อยานถึงขอบหน้าจอ อาจเป็นเอฟเฟกต์เล็กๆ เพื่อบ่งบอกถึงขอบพื้นที่เล่น
เรียนรู้เพิ่มเติมเกี่ยวกับ [agent mode](https://code.visualstudio.com/blogs/2025/02/24/introducing-copilot-agent-mode) ที่นี่
## 🚀 Challenge
การจัดระเบียบโค้ดมีความสำคัญมากขึ้นเมื่อโปรเจกต์เติบโต คุณอาจสังเกตเห็นว่าไฟล์ของคุณเริ่มเต็มไปด้วยฟังก์ชัน ตัวแปร และคลาสที่ปะปนกัน นี่ทำให้นึกถึงวิศวกรที่จัดระเบียบโค้ดของภารกิจ Apollo ที่ต้องสร้างระบบที่ชัดเจนและดูแลรักษาได้ ซึ่งทีมหลายทีมสามารถทำงานร่วมกันได้
**ภารกิจของคุณ:**
คิดแบบสถาปนิกซอฟต์แวร์ คุณจะจัดระเบียบโค้ดของคุณอย่างไรเพื่อให้หกเดือนจากนี้ คุณ (หรือเพื่อนร่วมทีม) สามารถเข้าใจสิ่งที่เกิดขึ้นได้? แม้ว่าทุกอย่างจะยังอยู่ในไฟล์เดียวในตอนนี้ คุณสามารถสร้างการจัดระเบียบที่ดีขึ้นได้:
- **จัดกลุ่มฟังก์ชันที่เกี่ยวข้อง** พร้อมหัวข้อคอมเมนต์ที่ชัดเจน
- **แยกความรับผิดชอบ** - แยกตรรกะของเกมออกจากการแสดงผล
- **ใช้ชื่อที่สอดคล้องกัน** สำหรับตัวแปรและฟังก์ชัน
- **สร้างโมดูล** หรือ namespace เพื่อจัดระเบียบส่วนต่างๆ ของเกม
- **เพิ่มเอกสารประกอบ** ที่อธิบายวัตถุประสงค์ของแต่ละส่วนสำคัญ
**คำถามสะท้อน:**
- ส่วนใดของโค้ดของคุณที่เข้าใจยากที่สุดเมื่อคุณกลับมาดู?
- คุณจะจัดระเบียบโค้ดอย่างไรเพื่อให้ง่ายขึ้นสำหรับคนอื่นที่จะมีส่วนร่วม?
- จะเกิดอะไรขึ้นถ้าคุณต้องการเพิ่มฟีเจอร์ใหม่ เช่น power-ups หรือประเภทศัตรูที่แตกต่างกัน?
## Post-Lecture Quiz
[Post-lecture quiz](https://ff-quizzes.netlify.app/web/quiz/34)
## Review & Self Study
เรากำลังสร้างทุกอย่างตั้งแต่เริ่มต้น ซึ่งยอดเยี่ยมสำหรับการเรียนรู้ แต่มีความลับเล็กๆ น้อยๆ มีเฟรมเวิร์ก JavaScript ที่น่าทึ่งบางตัวที่สามารถจัดการงานหนักให้คุณได้ เมื่อคุณรู้สึกสบายใจกับพื้นฐานที่เราได้ครอบคลุมแล้ว คุ้มค่าที่จะ [สำรวจสิ่งที่มีอยู่](https://github.com/collections/javascript-game-engines)
คิดถึงเฟรมเวิร์กเหมือนมีชุดเครื่องมือที่ครบครันแทนที่จะสร้างเครื่องมือทุกชิ้นด้วยตัวเอง พวกมันสามารถแก้ปัญหาความท้าทายในการจัดระเบียบโค้ดที่เราพูดถึงได้มากมาย และยังมีฟีเจอร์ที่อาจใช้เวลาหลายสัปดาห์ในการสร้างเอง
**สิ่งที่ควรสำรวจ:**
- วิธีที่ game engines จัดระเบียบโค้ด คุณจะทึ่งกับรูปแบบที่ชาญฉลาดที่พวกเขาใช้
- เทคนิคการเพิ่มประสิทธิภาพเพื่อทำให้เกม canvas ทำงานได้อย่างราบรื่น
- ฟีเจอร์ JavaScript สมัยใหม่ที่สามารถทำให้โค้ดของคุณสะอาดและดูแลรักษาได้ง่ายขึ้น
- วิธีการต่างๆ ในการจัดการวัตถุเกมและความสัมพันธ์ของพวกมัน
## Assignment
[Comment your code](assignment.md)
---
**ข้อจำกัดความรับผิดชอบ**:
เอกสารนี้ได้รับการแปลโดยใช้บริการแปลภาษา AI [Co-op Translator](https://github.com/Azure/co-op-translator) แม้ว่าเราจะพยายามให้การแปลมีความถูกต้อง แต่โปรดทราบว่าการแปลโดยอัตโนมัติอาจมีข้อผิดพลาดหรือความไม่ถูกต้อง เอกสารต้นฉบับในภาษาดั้งเดิมควรถือเป็นแหล่งข้อมูลที่เชื่อถือได้ สำหรับข้อมูลที่สำคัญ ขอแนะนำให้ใช้บริการแปลภาษามืออาชีพ เราไม่รับผิดชอบต่อความเข้าใจผิดหรือการตีความผิดที่เกิดจากการใช้การแปลนี้