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

890 lines
67 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.

# สร้างเกมอวกาศ ตอนที่ 3: การเพิ่มการเคลื่อนที่
```mermaid
journey
title การเดินทางแอนิเมชันเกมของคุณ
section พื้นฐานการเคลื่อนไหว
เข้าใจหลักการเคลื่อนไหว: 3: Student
เรียนรู้การอัปเดตพิกัด: 4: Student
นำการเคลื่อนไหวพื้นฐานไปใช้: 4: Student
section การควบคุมผู้เล่น
จัดการเหตุการณ์แป้นพิมพ์: 4: Student
ป้องกันพฤติกรรมเริ่มต้น: 5: Student
สร้างการควบคุมที่ตอบสนอง: 5: Student
section ระบบเกม
สร้างวงจรเกม: 5: Student
จัดการวงจรชีวิตวัตถุ: 5: Student
นำแนวทาง pub/sub ไปใช้: 5: Student
```
ลองคิดถึงเกมที่คุณชอบที่สุด สิ่งที่ทำให้เกมเหล่านั้นน่าติดตามไม่ใช่แค่กราฟิกที่สวยงามเท่านั้น แต่คือวิธีที่ทุกอย่างเคลื่อนไหวและตอบสนองต่อการกระทำของคุณ ตอนนี้เกมอวกาศของคุณเหมือนภาพวาดที่สวยงาม แต่เรากำลังจะเพิ่มการเคลื่อนไหวที่ทำให้มันมีชีวิต
เมื่อวิศวกรของ NASA เขียนโปรแกรมคอมพิวเตอร์สำหรับการนำทางในภารกิจ Apollo พวกเขาต้องเผชิญกับความท้าทายคล้ายกัน: จะทำอย่างไรให้ยานอวกาศตอบสนองต่อการควบคุมของนักบินในขณะเดียวกันก็คงเส้นทางได้โดยอัตโนมัติ หลักการที่เราจะเรียนรู้วันนี้สะท้อนแนวคิดเหล่านั้น การจัดการการเคลื่อนไหวที่ควบคุมโดยผู้เล่นควบคู่กับพฤติกรรมอัตโนมัติของระบบ
ในบทเรียนนี้ คุณจะได้เรียนรู้วิธีทำให้ยานอวกาศลื่นไหลผ่านหน้าจอ ตอบสนองต่อคำสั่งของผู้เล่น และสร้างรูปแบบการเคลื่อนไหวที่ราบรื่น เราจะแบ่งทุกอย่างออกเป็นแนวคิดที่เข้าใจง่ายและต่อเนื่องกันอย่างเป็นธรรมชาติ
เมื่อจบบทเรียน คุณจะมีผู้เล่นบินเรือฮีโร่ไปรอบหน้าจอ ในขณะที่เรือศัตรูก็ลาดตระเวนอยู่เหนือน่านฟ้า ที่สำคัญกว่านั้น คุณจะเข้าใจหลักการสำคัญที่ขับเคลื่อนระบบการเคลื่อนไหวของเกม
```mermaid
mindmap
root((แอนิเมชันเกม))
Movement Types
Player Controlled [ผู้เล่นควบคุม]
Automatic Motion [การเคลื่อนที่อัตโนมัติ]
Physics Based [อิงฟิสิกส์]
Scripted Paths [เส้นทางกำหนดสคริปต์]
Event Handling
Keyboard Input [ป้อนข้อมูลแป้นพิมพ์]
Mouse Events [เหตุการณ์เมาส์]
Touch Controls [การควบคุมสัมผัส]
Default Prevention [ป้องกันค่าปริยาย]
Game Loop
Update Logic [อัปเดตตรรกะ]
Render Frame [เรนเดอร์เฟรม]
Clear Canvas [ล้างแคนวาส]
Frame Rate Control [ควบคุมอัตราเฟรม]
Object Management
Position Updates [อัปเดตตำแหน่ง]
Collision Detection [ตรวจจับการชน]
Lifecycle Management [จัดการวงจรชีวิต]
State Tracking [ติดตามสถานะ]
Communication
Pub/Sub Pattern [รูปแบบเผยแพร่/สมัครสมาชิก]
Event Emitters [เครื่องปล่อยเหตุการณ์]
Message Passing [ส่งข้อความ]
Loose Coupling [การรวมโค้ดแบบหลวม]
```
## แบบทดสอบก่อนฟังบรรยาย
[แบบทดสอบก่อนบรรยาย](https://ff-quizzes.netlify.app/web/quiz/33)
## ทำความเข้าใจการเคลื่อนไหวในเกม
เกมมีชีวิตชีวาเมื่อสิ่งต่างๆ เริ่มเคลื่อนไหว และโดยพื้นฐานมีสองวิธีที่สิ่งเหล่านี้เกิดขึ้น:
- **การเคลื่อนไหวที่ควบคุมโดยผู้เล่น**: เมื่อคุณกดปุ่มหรือคลิกเมาส์ สิ่งของบางอย่างเคลื่อนที่ นี่คือการเชื่อมโยงโดยตรงระหว่างตัวคุณกับโลกในเกม
- **การเคลื่อนไหวอัตโนมัติ**: เมื่อเกมตัดสินใจเคลื่อนไหวสิ่งของเอง เช่น เรือศัตรูที่ต้องลาดตระเวนหน้าจอไม่ว่าคุณจะทำอะไรหรือไม่ก็ตาม
การทำให้วัตถุเคลื่อนที่บนหน้าจอคอมพิวเตอร์นั้นง่ายกว่าที่คิด จำพิกัด x และ y จากชั้นเรียนคณิตศาสตร์ได้ไหม? นั่นแหละคือสิ่งที่เรากำลังทำอยู่ เมื่อกาลิเลโอเฝ้าดูดวงจันทร์ของดาวพฤหัสบดีในปี 1610 เขาก็ทำสิ่งเดียวกัน การกำหนดตำแหน่งตามเวลาเพื่อเข้าใจรูปแบบการเคลื่อนไหว
การเคลื่อนไหวบนหน้าจอเหมือนกับการสร้างภาพเคลื่อนไหวแบบแฟลชบุ๊ก คุณต้องปฏิบัติตามสามขั้นตอนง่ายๆ เหล่านี้:
```mermaid
flowchart LR
A["เฟรม N"] --> B["อัปเดตตำแหน่ง"]
B --> C["ล้างผืนผ้าใบ"]
C --> D["วาดวัตถุ"]
D --> E["เฟรม N+1"]
E --> F{ต่อไปไหม?}
F -->|ใช่| B
F -->|ไม่| G["เกมจบแล้ว"]
subgraph "วงจรอนิเมชัน"
H["1. คำนวณตำแหน่งใหม่"]
I["2. ลบเฟรมก่อนหน้า"]
J["3. เรนเดอร์เฟรมใหม่"]
end
style B fill:#e1f5fe
style C fill:#ffebee
style D fill:#e8f5e8
```
1. **อัปเดตตำแหน่ง** เปลี่ยนตำแหน่งของวัตถุ (เช่น เลื่อนมันไปทางขวา 5 พิกเซล)
2. **ลบเฟรมเก่า** ล้างหน้าจอเพื่อไม่ให้เห็นเงาหรือรอยที่ไม่ต้องการ
3. **วาดเฟรมใหม่** วางวัตถุในตำแหน่งใหม่
ทำเร็วพอ แล้วบูม! คุณจะได้การเคลื่อนไหวที่ราบรื่นและรู้สึกเป็นธรรมชาติต่อผู้เล่น
นี่คือตัวอย่างโค้ด:
```javascript
// ตั้งตำแหน่งของฮีโร่
hero.x += 5;
// ล้างสี่เหลี่ยมที่เป็นที่อยู่ของฮีโร่
ctx.clearRect(0, 0, canvas.width, canvas.height);
// วาดฉากหลังเกมและฮีโร่ใหม่
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 เพื่อยิงเลเซอร์ หรือกดปุ่มลูกศรเพื่อหลบอะสเทอรอยด์ เกมของคุณต้องตรวจจับและตอบสนองต่อข้อมูลนั้น
เหตุการณ์แป้นพิมพ์เกิดขึ้นในระดับหน้าต่างเบราว์เซอร์ หมายความว่าหน้าต่างเบราว์เซอร์ทั้งหมดจะฟังการกดปุ่มเหล่านั้น คลิกเมาส์ในทางกลับกันสามารถจับกับองค์ประกอบเฉพาะ เช่น ปุ่ม สำหรับเกมอวกาศของเรา เราจะโฟกัสที่การควบคุมด้วยแป้นพิมพ์เพราะนี่คือสิ่งที่ให้ความรู้สึกคลาสสิกแบบเกมอาร์เคด
สิ่งนี้ทำให้นึกถึงโอเปอเรเตอร์ระบบโทรเลขในช่วงปี 1800 ที่ต้องแปลงสัญญาณมอร์สให้กลายเป็นข้อความที่มีความหมาย เราก็กำลังทำสิ่งเดียวกันคือแปลงการกดปุ่มเป็นคำสั่งเกม
ในการจัดการเหตุการณ์ คุณต้องใช้เมธอด `addEventListener()` ของวินโดวส์ พร้อมกับส่งพารามิเตอร์สองตัว ตัวแรกคือชื่อเหตุการณ์ เช่น `keyup` ตัวที่สองคือฟังก์ชันที่จะถูกเรียกใช้เมื่อเกิดเหตุการณ์
ตัวอย่างโค้ด:
```javascript
window.addEventListener('keyup', (evt) => {
// evt.key = การแทนค่ารูปแบบสตริงของปุ่ม
if (evt.key === 'ArrowUp') {
// ทำบางอย่าง
}
});
```
**สรุปสิ่งที่เกิดขึ้น:**
- **ฟัง** เหตุการณ์แป้นพิมพ์บนหน้าต่างทั้งหมด
- **รับ** อ็อบเจกต์เหตุการณ์ซึ่งมีข้อมูลว่าปุ่มไหนถูกกด
- **ตรวจสอบ** ว่าปุ่มที่กดตรงกับปุ่มที่กำหนดหรือไม่ (กรณีนี้คือปุ่มลูกศรขึ้น)
- **ดำเนินการ** โค้ดเมื่อเงื่อนไขเป็นจริง
สำหรับเหตุการณ์คีย์ มีสองคุณสมบัติในเหตุการณ์ที่คุณใช้ดูว่ากดปุ่มไหน:
- `key` - เป็นสตริงแสดงปุ่มที่กด เช่น `'ArrowUp'`
- `keyCode` - เป็นตัวเลขแสดงรหัส เช่น `37` ซึ่งหมายถึง `ArrowLeft`
✅ การจัดการเหตุการณ์คีย์มีประโยชน์นอกพัฒนาเกม คุณคิดว่าจะใช้เทคนิคนี้ทำอะไรได้อีกบ้าง?
```mermaid
sequenceDiagram
participant User
participant Browser
participant EventSystem
participant GameLogic
participant Hero
User->>Browser: กดปุ่มลูกศรขึ้น
Browser->>EventSystem: เหตุการณ์กดแป้นพิมพ์
EventSystem->>EventSystem: preventDefault()
EventSystem->>GameLogic: emit('KEY_EVENT_UP')
GameLogic->>Hero: hero.y -= 5
Hero->>Hero: อัปเดตตำแหน่ง
Note over Browser,GameLogic: การไหลของเหตุการณ์ป้องกันค่าเริ่มต้นของเบราว์เซอร์
Note over GameLogic,Hero: รูปแบบ pub/sub ช่วยให้การสื่อสารมีความชัดเจน
```
### คีย์พิเศษ: แจ้งเตือน!
ปุ่มบางปุ่มมีพฤติกรรมในตัวของเบราว์เซอร์ที่อาจทำให้เกมของคุณมีปัญหา ปุ่มลูกศรเลื่อนหน้าเว็บ และ spacebar กระโดดลงด้านล่าง พฤติกรรมที่คุณไม่ต้องการเวลาคนพยายามควบคุมยานอวกาศของพวกเขา
เราสามารถป้องกันพฤติกรรมเริ่มต้นเหล่านี้และปล่อยให้เกมเราเป็นคนจัดการแทน เหมือนกับที่โปรแกรมเมอร์คอมพิวเตอร์ยุคแรกต้องเขียนทับการหยุดชะงักของระบบเพื่อสร้างพฤติกรรมพิเศษ เรากำลังทำแบบเดียวกันแต่ในระดับเบราว์เซอร์ นี่คือวิธี:
```javascript
const onKeyDown = function (e) {
console.log(e.keyCode);
switch (e.keyCode) {
case 37:
case 39:
case 38:
case 40: // ปุ่มลูกศร
case 32:
e.preventDefault();
break; // ช่องว่าง
default:
break; // ไม่บล็อกปุ่มอื่น ๆ
}
};
window.addEventListener('keydown', onKeyDown);
```
**เข้าใจโค้ดป้องกันนี้:**
- **ตรวจสอบ** รหัสคีย์ที่อาจทำให้เกิดพฤติกรรมไม่พึงประสงค์
- **ป้องกัน** พฤติกรรมเบราว์เซอร์เริ่มต้นสำหรับปุ่มลูกศรและ spacebar
- **อนุญาต** ให้ปุ่มอื่นทำงานได้ตามปกติ
- **ใช้** `e.preventDefault()` เพื่อหยุดพฤติกรรมเริ่มต้นของเบราว์เซอร์
### 🔄 **ตรวจสอบความเข้าใจเชิงการสอน**
**ความเข้าใจเกี่ยวกับการจัดการเหตุการณ์**: ก่อนย้ายไปที่การเคลื่อนไหวอัตโนมัติ ให้แน่ใจว่าคุณสามารถ:
- ✅ อธิบายความแตกต่างระหว่างเหตุการณ์ `keydown` และ `keyup`
- ✅ เข้าใจเหตุผลที่เราต้องป้องกันพฤติกรรมเริ่มต้นของเบราว์เซอร์
- ✅ อธิบายได้ว่าการฟังเหตุการณ์เชื่อมต่อกับข้อมูลป้อนของผู้ใช้อย่างไร
- ✅ ระบุได้ว่าปุ่มไหนอาจรบกวนการควบคุมเกม
**ทดสอบตัวเองแบบด่วน**: จะเกิดอะไรขึ้นถ้าคุณไม่ป้องกันพฤติกรรมเริ่มต้นของปุ่มลูกศร?
*คำตอบ: เบราว์เซอร์จะเลื่อนหน้าเว็บ ทำให้การเคลื่อนไหวในเกมเกิดการรบกวน*
**สถาปัตยกรรมระบบเหตุการณ์**: ตอนนี้คุณเข้าใจว่า:
- **การฟังในระดับหน้าต่าง**: รับเหตุการณ์ในระดับเบราว์เซอร์
- **คุณสมบัติของอ็อบเจกต์เหตุการณ์**: สตริง `key` กับตัวเลข `keyCode`
- **การป้องกันพฤติกรรมเริ่มต้น**: หยุดพฤติกรรมที่ไม่ต้องการของเบราว์เซอร์
- **ตรรกะเงื่อนไข**: ตอบสนองต่อชุดปุ่มเฉพาะ
## การเคลื่อนไหวที่เกิดจากเกม
ตอนนี้มาคุยถึงวัตถุที่เคลื่อนไหวโดยไม่มีการป้อนข้อมูลจากผู้เล่น ลองนึกถึงเรือศัตรูที่แล่นผ่านหน้าจอ กระสุนที่ยิงเป็นเส้นตรง หรือเมฆที่ลอยอยู่เบื้องหลัง การเคลื่อนไหวอิสระนี้ทำให้โลกในเกมของคุณดูมีชีวิตแม้ไม่มีใครสัมผัสการควบคุมเลย
เราจะใช้ตัวจับเวลาที่มีอยู่ใน JavaScript เพื่ออัปเดตตำแหน่งเป็นช่วงๆ แนวคิดนี้คล้ายกับนาฬิกาลูกตุ้ม กลไกที่เรียบง่ายที่ทำงานเป็นระยะเวลาสม่ำเสมอ นี่คือตัวอย่างที่ง่าย:
```javascript
const id = setInterval(() => {
// เคลื่อนศัตรูในแนวแกน y
enemy.y += 10;
}, 100);
```
**โค้ดเคลื่อนไหวนี้ทำอะไร:**
- **สร้าง** ตัวจับเวลาที่ทำงานทุก 100 มิลลิวินาที
- **อัปเดต** ค่าพิกัด y ของศัตรูเพิ่มขึ้น 10 พิกเซลทุกครั้ง
- **เก็บ** รหัสตัวจับเวลาไว้เพื่อหยุดเมื่อจำเป็น
- **เคลื่อนที่** ศัตรูลงล่างบนหน้าจอโดยอัตโนมัติ
## วงจรเกม (Game Loop)
นี่คือแนวคิดที่เชื่อมทุกอย่างเข้าด้วยกัน วงจรเกม ถ้าเกมของคุณเป็นภาพยนตร์ วงจรเกมคือเครื่องฉายภาพยนตร์ที่แสดงภาพทีละเฟรมอย่างรวดเร็วจนทุกอย่างดูเคลื่อนไหวอย่างราบรื่น
ทุกเกมมีวงจรแบบนี้ทำงานอยู่เบื้องหลัง มันเป็นฟังก์ชันที่อัปเดตวัตถุในเกมทั้งหมด วาดหน้าจอใหม่ และทำซ้ำกระบวนการนี้ตลอดเวลา เพื่อให้ติดตามฮีโร่ ศัตรู และเลเซอร์ต่างๆ ได้ทั้งหมด สถานะของเกมโดยรวม
แนวคิดนี้ทำให้นึกถึงคนทำแอนิเมชันยุคแรกอย่าง Walt Disney ที่ต้องวาดตัวละครทีละเฟรมเพื่อสร้างภาพเคลื่อนไหว ความจริงแล้วเราแค่ใช้โค้ดแทนดินสอเท่านั้น
นี่คือตัวอย่างโค้ตเกมลูปที่ใช้บ่อย:
```mermaid
flowchart TD
A["เริ่มลูปเกม"] --> B["ล้างผืนผ้าใบ"]
B --> C["เติมพื้นหลัง"]
C --> D["อัปเดตอ็อบเจ็กต์เกม"]
D --> E["วาดฮีโร่"]
E --> F["วาดศัตรู"]
F --> G["วาดองค์ประกอบ UI"]
G --> H["รอสำหรับเฟรมถัดไป"]
H --> I{เกมกำลังทำงานอยู่หรือไม่?}
I -->|ใช่| B
I -->|ไม่ใช่| J["จบเกม"]
subgraph "ควบคุมอัตราเฟรม"
K["60 FPS = 16.67ms"]
L["30 FPS = 33.33ms"]
M["10 FPS = 100ms"]
end
style B fill:#ffebee
style D fill:#e1f5fe
style E fill:#e8f5e8
style F fill:#e8f5e8
```
```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 ที่อยู่ `http://localhost:5000`
- **ให้บริการ** ไฟล์เกมของคุณเพื่อทดสอบในเบราว์เซอร์
คำสั่งข้างต้นจะเริ่มเซิร์ฟเวอร์ HTTP ที่อยู่ `http://localhost:5000` เปิดเบราว์เซอร์และใส่ URL นี้ ตอนนี้ควรแสดงฮีโร่และศัตรูทั้งหมด แต่ยังไม่มีการเคลื่อนไหว!
### เพิ่มโค้ด
1. **เพิ่มวัตถุเฉพาะ** สำหรับ `hero` และ `enemy` และ `game object` แต่ละอันควรมีคุณสมบัติ `x` และ `y` (จำหัวข้อ [สืบทอดหรือประกอบ](../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()` เพื่อวาดวัตถุลงบนแคนวาส
- **ตั้งค่า** ค่าเริ่มต้นสำหรับคุณสมบัติทั้งหมดที่คลาสลูกสามารถเขียนทับได้
```mermaid
classDiagram
class GameObject {
+x: number
+y: number
+dead: boolean
+type: string
+width: number
+height: number
+img: Image
+draw(ctx)
}
class Hero {
+speed: number
+type: "ฮีโร่"
+width: 98
+height: 75
}
class Enemy {
+type: "ศัตรู"
+width: 98
+height: 50
+setInterval()
}
GameObject <|-- Hero
GameObject <|-- Enemy
class EventEmitter {
+listeners: object
+on(ข้อความ, ผู้ฟัง)
+emit(ข้อความ, ข้อมูล)
}
```
ตอนนี้ ขยายคลาส `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);
// เพิ่มโค้ดจากบทเรียนข้างต้นเพื่อหยุดพฤติกรรมเริ่มต้น
switch (e.keyCode) {
case 37:
case 39:
case 38:
case 40: // ปุ่มลูกศร
case 32:
e.preventDefault();
break; // ช่องว่าง
default:
break; // อย่าบล็อกปุ่มอื่น
}
};
window.addEventListener("keydown", onKeyDown);
```
**ตัวจัดการเหตุการณ์นี้ทำอะไร:**
- **ฟัง** เหตุการณ์ keydown บนหน้าต่างทั้งหมด
- **บันทึก** รหัสปุ่มเพื่อช่วยดีบักว่าปุ่มไหนถูกกด
- **ป้องกัน** พฤติกรรมเริ่มต้นของเบราว์เซอร์สำหรับลูกศรและ spacebar
- **ปล่อย** ให้ปุ่มอื่นทำงานตามปกติ
ตรวจสอบคอนโซลเบราว์เซอร์ตอนนี้และดูการพิมพ์ปุ่มที่ถูกกด
3. **ดำเนินการ** [รูปแบบ Pub sub](../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);
}
});
```
**ระบบเหตุการณ์นี้ทำอะไร:**
- **ตรวจจับ** ข้อมูลแป้นพิมพ์และแปลงเป็นเหตุการณ์เกมส่วนตัว
- **แยก** การตรวจจับข้อมูลกับตรรกะของเกมออกจากกัน
- **ทำให้** เปลี่ยนการควบคุมในภายหลังได้ง่ายโดยไม่กระทบโค้ดเกม
- **อนุญาต** ระบบหลายตัวตอบสนองข้อมูลเดียวกันได้
```mermaid
flowchart TD
A["การป้อนข้อมูลจากแป้นพิมพ์"] --> B["ตัวฟังเหตุการณ์หน้าต่าง"]
B --> C["ตัวปล่อยเหตุการณ์"]
C --> D["เหตุการณ์กดปุ่มขึ้น"]
C --> E["เหตุการณ์กดปุ่มลง"]
C --> F["เหตุการณ์กดปุ่มซ้าย"]
C --> G["เหตุการณ์กดปุ่มขวา"]
D --> H["การเคลื่อนที่ของฮีโร่"]
D --> I["ระบบเสียง"]
D --> J["เอฟเฟกต์ภาพ"]
E --> H
F --> H
G --> H
style A fill:#e1f5fe
style C fill:#e8f5e8
style H fill:#fff3e0
```
2. **สร้างคลาส EventEmitter** เพื่อเผยแพร่และสมัครรับข้อความ:
```javascript
class EventEmitter {
constructor() {
this.listeners = {};
}
on(message, listener) {
if (!this.listeners[message]) {
this.listeners[message] = [];
}
this.listeners[message].push(listener);
}
3. **เพิ่มคอนสแตนต์** และตั้งค่า EventEmitter:
```javascript
const Messages = {
KEY_EVENT_UP: "KEY_EVENT_UP",
KEY_EVENT_DOWN: "KEY_EVENT_DOWN",
KEY_EVENT_LEFT: "KEY_EVENT_LEFT",
KEY_EVENT_RIGHT: "KEY_EVENT_RIGHT",
};
let heroImg,
enemyImg,
laserImg,
canvas, ctx,
gameObjects = [],
hero,
eventEmitter = new EventEmitter();
```
**เข้าใจการตั้งค่า:**
- **กำหนด** ค่าคงที่ของข้อความเพื่อหลีกเลี่ยงการพิมพ์ผิดและง่ายต่อการแก้ไขโค้ด
- **ประกาศ** ตัวแปรสำหรับภาพ แคนวาส และสถานะเกม
- **สร้าง** อีเวนต์อีมิตเตอร์แบบทั่วโลกสำหรับระบบ pub-sub
- **กำหนดค่าเริ่มต้น** อาร์เรย์เพื่อเก็บวัตถุในเกมทั้งหมด
4. **เริ่มต้นเกม**
```javascript
function initGame() {
gameObjects = [];
createEnemies();
createHero();
eventEmitter.on(Messages.KEY_EVENT_UP, () => {
hero.y -= 5;
});
eventEmitter.on(Messages.KEY_EVENT_DOWN, () => {
hero.y += 5;
});
eventEmitter.on(Messages.KEY_EVENT_LEFT, () => {
hero.x -= 5;
});
4. **ตั้งค่าลูปเกม**
ปรับโค้ดฟังก์ชัน `window.onload` ให้เริ่มต้นเกมและตั้งค่าลูปเกมในช่วงเวลาที่เหมาะสม คุณจะเพิ่มลำแสงเลเซอร์ด้วย:
```javascript
window.onload = async () => {
canvas = document.getElementById("canvas");
ctx = canvas.getContext("2d");
heroImg = await loadTexture("assets/player.png");
enemyImg = await loadTexture("assets/enemyShip.png");
laserImg = await loadTexture("assets/laserRed.png");
initGame();
const gameLoopId = setInterval(() => {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = "black";
ctx.fillRect(0, 0, canvas.width, canvas.height);
drawGameObjects(ctx);
}, 100);
};
```
**ทำความเข้าใจการตั้งค่าเกม:**
- **รอ** ให้หน้าเว็บโหลดเสร็จสมบูรณ์ก่อนเริ่ม
- **รับ** อิลิเมนต์แคนวาสและคอนเท็กซ์ 2D ของมัน
- **โหลด** ไฟล์รูปภาพทั้งหมดแบบไม่ประสานโดยใช้ `await`
- **เริ่ม** ลูปเกมทำงานที่ช่วงเวลา 100 มิลลิวินาที (10 เฟรมต่อวินาที)
- **ล้าง** และวาดใหม่ทั้งหน้าจอในแต่ละเฟรม
5. **เพิ่มโค้ด** เพื่อให้ศัตรูเคลื่อนที่ในช่วงเวลาที่กำหนด
ปรับโค้ดฟังก์ชัน `createEnemies()` เพื่อสร้างศัตรูและเพิ่มพวกมันเข้าในคลาส gameObjects ใหม่:
```javascript
function createEnemies() {
const MONSTER_TOTAL = 5;
const MONSTER_WIDTH = MONSTER_TOTAL * 98;
const START_X = (canvas.width - MONSTER_WIDTH) / 2;
const STOP_X = START_X + MONSTER_WIDTH;
for (let x = START_X; x < STOP_X; x += 98) {
for (let y = 0; y < 50 * 5; y += 50) {
const enemy = new Enemy(x, y);
enemy.img = enemyImg;
gameObjects.push(enemy);
}
}
}
```
**สิ่งที่การสร้างศัตรูทำ:**
- **คำนวณ** ตำแหน่งเพื่อวางศัตรูให้อยู่กึ่งกลางหน้าจอ
- **สร้าง** ตารางศัตรูโดยใช้ลูปซ้อนกัน
- **กำหนด** รูปภาพศัตรูให้แก่แต่ละวัตถุศัตรู
- **เพิ่ม** ศัตรูแต่ละตัวเข้าอาร์เรย์วัตถุเกมรวม
และเพิ่มฟังก์ชัน `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()` ในแต่ละวัตถุ
- **ส่งผ่าน** คอนเท็กซ์ของแคนวาสเพื่อให้วัตถุวาดตัวเองได้
### 🔄 **ตรวจสอบความเข้าใจเชิงการสอน**
**ความเข้าใจระบบเกมครบถ้วน**: ตรวจสอบความชำนาญของคุณในสถาปัตยกรรมทั้งหมด:
- การสืบทอดทำให้ Hero และ Enemy แชร์คุณสมบัติของ GameObject ได้อย่างไร?
- ทำไมรูปแบบ pub/sub ถึงทำให้โค้ดของคุณดูแลรักษาง่ายขึ้น?
- ลูปเกมมีบทบาทอย่างไรในการสร้างอนิเมชันที่ลื่นไหล?
- ตัวฟังเหตุการณ์เชื่อมโยงการป้อนข้อมูลของผู้ใช้เข้ากับพฤติกรรมของวัตถุเกมอย่างไร?
**การบูรณาการระบบ**: เกมของคุณตอนนี้แสดงให้เห็น:
- **การออกแบบเชิงวัตถุ**: คลาสแม่พร้อมการสืบทอดเฉพาะทาง
- **สถาปัตยกรรมขับเคลื่อนด้วยเหตุการณ์**: รูปแบบ pub/sub เพื่อความยืดหยุ่น
- **กรอบอนิเมชัน**: ลูปเกมกับการอัปเดตเฟรมที่สม่ำเสมอ
- **ระบบป้อนข้อมูล**: กิจกรรมแป้นพิมพ์พร้อมการป้องกันค่าดีฟอลต์
- **การจัดการทรัพยากร**: การโหลดภาพและการแสดงสไปรต์
**รูปแบบมืออาชีพ**: คุณได้ดำเนินการ:
- **แยกหน้าที่อย่างชัดเจน**: แยกอินพุต, โลจิก และการวาดออกจากกัน
- **พอลิมอร์ฟิซึม**: ทุกวัตถุเกมแชร์อินเทอร์เฟซการวาดเดียวกัน
- **การส่งผ่านข้อความ**: การสื่อสารที่สะอาดระหว่างองค์ประกอบต่างๆ
- **การจัดการทรัพยากร**: การจัดการสไปรต์และอนิเมชันอย่างมีประสิทธิภาพ
ศัตรูของคุณควรเริ่มต้นเคลื่อนที่เข้าหายานอวกาศของฮีโร่แล้ว!
}
}
```
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 🚀
นี่คือความท้าทายที่จะช่วยปรับแต่งเกมของคุณ: การเพิ่มขอบเขตและการควบคุมที่ลื่นไหล ขณะนี้ ฮีโร่ของคุณสามารถบินออกนอกหน้าจอได้ และการเคลื่อนไหวอาจรู้สึกกระตุก
**ภารกิจของคุณ:** ทำให้ยานอวกาศของคุณรู้สึกสมจริงมากขึ้นด้วยการเพิ่มขอบเขตจอและการเคลื่อนไหวที่ลื่นไหล เหมือนกับระบบการควบคุมการบินของ NASA ที่ป้องกันไม่ให้ยานเกินพารามิเตอร์การทำงานที่ปลอดภัย
**สิ่งที่ต้องสร้าง:** สร้างระบบที่รักษายานอวกาศฮีโร่ให้คงอยู่ในหน้าจอ และทำให้การควบคุมรู้สึกลื่นไหล เมื่อผู้เล่นกดปุ่มลูกศรค้างไว้ ยานควรเคลื่อนต่อเนื่องแทนการเคลื่อนเป็นขั้นๆ ลองเพิ่มสัญญาณภาพเมื่อยานถึงขอบหน้าจอ เช่น เอฟเฟกต์เบาๆ เพื่อบอกขอบเขตพื้นที่เล่น
เรียนรู้เพิ่มเติมเกี่ยวกับ [โหมด agent](https://code.visualstudio.com/blogs/2025/02/24/introducing-copilot-agent-mode) ที่นี่
## 🚀 ความท้าทาย
การจัดระเบียบโค้ดสำคัญขึ้นเรื่อยๆ เมื่อโปรเจกต์โตขึ้น คุณอาจสังเกตเห็นไฟล์ของคุณแน่นไปด้วยฟังก์ชัน, ตัวแปร และคลาสที่ผสมกัน นี่เตือนฉันถึงวิธีที่วิศวกรโค้ดของภารกิจ Apollo ต้องสร้างระบบที่ชัดเจนและดูแลรักษาง่ายซึ่งทีมหลายทีมสามารถทำงานพร้อมกันได้
**ภารกิจของคุณ:**
คิดเหมือนสถาปนิกซอฟต์แวร์ คุณจะจัดระเบียบโค้ดอย่างไรเพื่อให้หลังจากหกเดือน คุณ (หรือเพื่อนร่วมงาน) สามารถเข้าใจสิ่งที่เกิดขึ้น แม้ตอนนี้ทุกอย่างจะยังอยู่ในไฟล์เดียว คุณก็ยังสามารถจัดระเบียบได้ดีขึ้นโดย:
- **จัดกลุ่มฟังก์ชันที่เกี่ยวข้อง** ด้วยหัวข้อคอมเมนต์ที่ชัดเจน
- **แยกหน้าที่กัน** - แยกโลจิกเกมออกจากการวาด
- **ใช้การตั้งชื่อตัวแปรและฟังก์ชันที่สม่ำเสมอ**
- **สร้างโมดูล** หรือเนมสเปซเพื่อจัดการส่วนต่างๆ ของเกม
- **เพิ่มเอกสาร** อธิบายจุดประสงค์ของแต่ละส่วนหลัก
**คำถามสะท้อนความคิด:**
- ส่วนใดของโค้ดที่คุณเข้าใจยากที่สุดเวลาคุณกลับมาดูอีกครั้ง?
- คุณจะจัดระเบียบโค้ดยังไงเพื่อให้ง่ายต่อการมีส่วนร่วมของผู้อื่น?
- จะเกิดอะไรขึ้นถ้าคุณต้องการเพิ่มฟีเจอร์ใหม่ๆ เช่น power-ups หรือศัตรูประเภทใหม่?
## แบบทดสอบหลังเรียน
[แบบทดสอบหลังเรียน](https://ff-quizzes.netlify.app/web/quiz/34)
## รีวิว & เรียนรู้ด้วยตนเอง
เราสร้างทุกอย่างตั้งแต่เริ่มต้น ซึ่งดีมากสำหรับการเรียนรู้ แต่มีความลับอยู่ มีเฟรมเวิร์ก JavaScript ที่ยอดเยี่ยมหลายตัวที่ช่วยจัดการงานหนักให้คุณได้ เมื่อคุณชำนาญพื้นฐานที่เราเรียนไปแล้ว ก็คุ้มค่าที่จะ [สำรวจสิ่งที่มีอยู่](https://github.com/collections/javascript-game-engines)
คิดว่าเฟรมเวิร์กเหมือนกล่องเครื่องมือที่เต็มไปด้วยเครื่องมือ แทนที่จะทำเครื่องมือทุกชิ้นด้วยมือเอง พวกมันช่วยแก้ปัญหาการจัดระเบียบโค้ดที่เราพูดถึง รวมถึงให้ฟีเจอร์ที่จะใช้เวลาหลายสัปดาห์ถ้าสร้างเอง
**สิ่งที่ควรสำรวจ:**
- วิธีที่เอนจินเกมจัดระเบียบโค้ด คุณจะทึ่งกับรูปแบบสุดเจ๋งที่เขาใช้
- เทคนิคประสิทธิภาพสำหรับเกมแคนวาสให้เล่นลื่นไหล
- ฟีเจอร์ JavaScript สมัยใหม่ที่ทำให้โค้ดสะอาดและดูแลง่ายขึ้น
- แนวทางต่างๆ ในการจัดการวัตถุเกมและความสัมพันธ์ของมัน
## 🎯 กรอบเวลาการเชี่ยวชาญอนิเมชันเกมของคุณ
```mermaid
timeline
title ความก้าวหน้าในการเรียนรู้การเคลื่อนไหวและการโต้ตอบในเกม
section พื้นฐานการเคลื่อนไหว (20 นาที)
หลักการแอนิเมชัน: แอนิเมชันแบบเฟรม
: การอัปเดตตำแหน่ง
: ระบบพิกัด
: การเคลื่อนไหวที่ราบรื่น
section ระบบเหตุการณ์ (25 นาที)
การป้อนข้อมูลผู้ใช้: การจัดการเหตุการณ์คีย์บอร์ด
: การป้องกันพฤติกรรมเริ่มต้น
: คุณสมบัติวัตถุเหตุการณ์
: การฟังระดับหน้าต่าง
section สถาปัตยกรรมเกม (30 นาที)
การออกแบบวัตถุ: รูปแบบการสืบทอด
: การสร้างคลาสฐาน
: พฤติกรรมเฉพาะทาง
: อินเทอร์เฟซแบบพหุรูป
section รูปแบบการสื่อสาร (35 นาที)
การใช้งาน Pub/Sub: ตัวส่งเหตุการณ์
: ค่าคงที่ของข้อความ
: การผูกมัดแบบหย่อน
: การบูรณาการระบบ
section ความชำนาญวงจรเกม (40 นาที)
ระบบเรียลไทม์: การควบคุมอัตราเฟรม
: รอบการอัปเดต/เรนเดอร์
: การจัดการสถานะ
: การเพิ่มประสิทธิภาพ
section เทคนิคขั้นสูง (45 นาที)
ฟีเจอร์ระดับมืออาชีพ: การตรวจจับการชน
: การจำลองฟิสิกส์
: เครื่องสถานะ
: ระบบคอมโพเนนต์
section แนวคิดเครื่องยนต์เกม (1 สัปดาห์)
ความเข้าใจเฟรมเวิร์ก: ระบบเอนทิตี-คอมโพเนนต์
: กราฟฉาก
: ท่อส่งสินทรัพย์
: การวิเคราะห์ประสิทธิภาพ
section ทักษะการผลิต (1 เดือน)
การพัฒนามืออาชีพ: การจัดระเบียบโค้ด
: การร่วมมือทีม
: กลยุทธ์การทดสอบ
: การเพิ่มประสิทธิภาพการเผยแพร่
```
### 🛠️ สรุปชุดเครื่องมือพัฒนาเกมของคุณ
หลังจากจบบทเรียนนี้ คุณได้ชำนาญ:
- **หลักการอนิเมชัน**: การเคลื่อนไหวแบบเฟรมและการเปลี่ยนผ่านที่ลื่นไหล
- **โปรแกรมขับเคลื่อนด้วยเหตุการณ์**: การจัดการอินพุตด้วยแป้นพิมพ์แบบมีการจัดการเหตุการณ์ถูกต้อง
- **การออกแบบเชิงวัตถุ**: โครงสร้างการสืบทอดและอินเทอร์เฟซพอลิมอร์ฟิก
- **รูปแบบการสื่อสาร**: สถาปัตยกรรม pub/sub เพื่อโค้ดที่ดูแลรักษาง่าย
- **โครงสร้างลูปเกม**: การอัปเดตและวาดภาพแบบเรียลไทม์
- **ระบบอินพุต**: การแมปการควบคุมผู้ใช้พร้อมป้องกันพฤติกรรมดีฟอลต์
- **การจัดการทรัพยากร**: การโหลดสไปรต์และเทคนิคการเรนเดอร์ที่มีประสิทธิภาพ
### ⚡ **สิ่งที่คุณทำได้ใน 5 นาทีถัดไป**
- [ ] เปิดคอนโซลในเบราว์เซอร์แล้วลอง `addEventListener('keydown', console.log)` เพื่อตรวจเหตุการณ์แป้นพิมพ์
- [ ] สร้าง div ง่ายๆ แล้วเคลื่อนย้ายโดยใช้ปุ่มลูกศร
- [ ] ทดลองใช้ `setInterval` เพื่อสร้างการเคลื่อนที่ต่อเนื่อง
- [ ] ลองป้องกันพฤติกรรมดีฟอลต์ด้วย `event.preventDefault()`
### 🎯 **สิ่งที่ทำได้ในชั่วโมงนี้**
- [ ] ทำแบบทดสอบหลังเรียนและเข้าใจโปรแกรมขับเคลื่อนด้วยเหตุการณ์
- [ ] สร้างยานฮีโร่ที่เคลื่อนที่ได้ด้วยแป้นพิมพ์ครบถ้วน
- [ ] ใช้รูปแบบการเคลื่อนที่ศัตรูที่ลื่นไหล
- [ ] เพิ่มขอบเขตไม่ให้วัตถุเกมออกนอกหน้าจอ
- [ ] สร้างระบบตรวจจับการชนเบื้องต้นระหว่างวัตถุเกม
### 📅 **การเดินทางอนิเมชันตลอดสัปดาห์ของคุณ**
- [ ] สร้างเกมอวกาศเต็มรูปแบบที่มีการเคลื่อนไหวและปฏิสัมพันธ์ที่ปรับแต่งแล้ว
- [ ] เพิ่มรูปแบบการเคลื่อนที่ขั้นสูง เช่น เส้นโค้ง, การเร่งความเร็ว และฟิสิกส์
- [ ] สร้างการเปลี่ยนผ่านและฟังก์ชัน easing ที่ลื่นไหล
- [ ] สร้างเอฟเฟกต์อนุภาคและระบบสัญญาณภาพ
- [ ] ปรับประสิทธิภาพเกมให้เล่นลื่นไหลที่ 60fps
- [ ] เพิ่มการควบคุมด้วยสัมผัสมือถือและดีไซน์ตอบสนอง
### 🌟 **การพัฒนาแบบอินเทอร์แอคทีฟตลอดเดือนของคุณ**
- [ ] สร้างแอปพลิเคชันเชิงโต้ตอบซับซ้อนด้วยระบบอนิเมชันขั้นสูง
- [ ] เรียนรู้ไลบรารีอนิเมชันเช่น GSAP หรือสร้างเอนจินอนิเมชันของตัวเอง
- [ ] มีส่วนร่วมพัฒนาเกมและโปรเจกต์อนิเมชันแบบโอเพนซอร์ส
- [ ] เชี่ยวชาญการปรับประสิทธิภาพสำหรับแอปกราฟิกหนัก
- [ ] สร้างเนื้อหาการเรียนรู้เกี่ยวกับการพัฒนาเกมและอนิเมชัน
- [ ] สร้างพอร์ตโฟลิโอแสดงทักษะโปรแกรมเชิงโต้ตอบขั้นสูง
**แอปพลิเคชันจริง:** ทักษะอนิเมชันเกมของคุณนำไปใช้ได้กับ:
- **เว็บแอปพลิเคชันเชิงโต้ตอบ**: แดชบอร์ดแบบไดนามิกและอินเทอร์เฟซเรียลไทม์
- **การแสดงข้อมูล**: แผนภูมิอนิเมชันและกราฟิกเชิงโต้ตอบ
- **ซอฟต์แวร์การศึกษา**: การจำลองเชิงโต้ตอบและเครื่องมือเรียนรู้
- **พัฒนามือถือ**: เกมสัมผัสและการจัดการท่าทาง
- **แอปเดสก์ท็อป**: แอป Electron พร้อมอนิเมชันลื่นไหล
- **อนิเมชันเว็บ**: ไลบรารีอนิเมชัน CSS และ JavaScript
**ทักษะมืออาชีพที่ได้รับ:** ตอนนี้คุณสามารถ:
- **ออกแบบสถาปัตยกรรม** ระบบขับเคลื่อนด้วยเหตุการณ์ที่ปรับขยายได้ตามความซับซ้อน
- **สร้างอนิเมชันลื่นไหล** โดยใช้หลักคณิตศาสตร์
- **ดีบัก** ระบบปฏิสัมพันธ์ซับซ้อนด้วยเครื่องมือพัฒนาในเบราว์เซอร์
- **ปรับประสิทธิภาพ** เกมสำหรับอุปกรณ์และเบราว์เซอร์ต่างๆ
- **ออกแบบ** โครงสร้างโค้ดที่ดูแลรักษาได้โดยใช้รูปแบบที่พิสูจน์แล้ว
**ความเข้าใจแนวคิดพัฒนาเกม:**
- **การจัดการเฟรมเรต**: เข้าใจ FPS และการควบคุมเวลา
- **การจัดการอินพุต**: ระบบเหตุการณ์และแป้นพิมพ์ข้ามแพลตฟอร์ม
- **วงจรชีวิตวัตถุ**: รูปแบบการสร้าง, อัปเดต และทำลาย
- **การซิงโครไนซ์สถานะ**: รักษาสถานะเกมให้สอดคล้องระหว่างเฟรม
- **สถาปัตยกรรมเหตุการณ์**: การสื่อสารแบบแยกส่วนระหว่างระบบเกม
**ขั้นถัดไป:** คุณพร้อมเพิ่มระบบตรวจจับการชน, ระบบคะแนน, เอฟเฟกต์เสียง หรือสำรวจเฟรมเวิร์กเกมสมัยใหม่ เช่น Phaser หรือ Three.js!
🌟 **ความสำเร็จ:** คุณได้สร้างระบบเกมเชิงโต้ตอบครบสมบูรณ์ด้วยสถาปัตยกรรมมืออาชีพแล้ว!
## การบ้าน
[คอมเมนต์โค้ดของคุณ](assignment.md)
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**ข้อจำกัดความรับผิดชอบ**:
เอกสารนี้ได้รับการแปลโดยใช้บริการแปลด้วย AI [Co-op Translator](https://github.com/Azure/co-op-translator) แม้ว่าเราจะพยายามให้ความถูกต้องสูงสุด แต่โปรดทราบว่าการแปลอัตโนมัติอาจมีข้อผิดพลาดหรือความไม่แม่นยำ เอกสารต้นฉบับในภาษาต้นทางควรถูกพิจารณาเป็นแหล่งข้อมูลที่เชื่อถือได้ สำหรับข้อมูลที่สำคัญ ขอแนะนำให้ใช้บริการแปลโดยมนุษย์มืออาชีพ เราไม่รับผิดชอบต่อความเข้าใจผิดหรือการตีความผิดใดๆ ที่เกิดจากการใช้การแปลนี้
<!-- CO-OP TRANSLATOR DISCLAIMER END -->