# สร้างเกมอวกาศ ตอนที่ 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) --- **ข้อจำกัดความรับผิดชอบ**: เอกสารนี้ได้รับการแปลโดยใช้บริการแปลด้วย AI [Co-op Translator](https://github.com/Azure/co-op-translator) แม้ว่าเราจะพยายามให้ความถูกต้องสูงสุด แต่โปรดทราบว่าการแปลอัตโนมัติอาจมีข้อผิดพลาดหรือความไม่แม่นยำ เอกสารต้นฉบับในภาษาต้นทางควรถูกพิจารณาเป็นแหล่งข้อมูลที่เชื่อถือได้ สำหรับข้อมูลที่สำคัญ ขอแนะนำให้ใช้บริการแปลโดยมนุษย์มืออาชีพ เราไม่รับผิดชอบต่อความเข้าใจผิดหรือการตีความผิดใดๆ ที่เกิดจากการใช้การแปลนี้