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

889 lines
72 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.

# សាងសង់ហ្គេមអាកាសយាន Part 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 ពីថ្នាក់គណិតវិទ្យាដែរឬ? នេះគឺជាម៉ាស៊ីនដែលយើងកំពុងប្រើប្រាស់នៅទីនេះ។ ពេល Galileo តាមដានព្រះច័ន្ទរបស់ Jupiter នៅឆ្នាំ 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 ដើម្បីបាញ់កាំភ្លើង ឬប៉ះក្តារចុចមុំដើម្បីជៀសវាងត្មួយផ្កាយ យើងត្រូវការឲ្យហ្គេមចាប់សញ្ញានិងឆ្លើយតបនឹងការបញ្ចូលនោះ។
ព្រឹត្តិការណ៍ក្តារចុចកើតឡើងនៅលើបិទបើកវីនដោ (window) មានន័យថាវីនដោកំណត់តម្រូវគ្រប់គ្រងនូវព្រឹត្តិការណ៍ទាំងនោះទាំងមូល។ ចុចម៉ៅស៍ផ្ទាល់ត្រូវបានភ្ជាប់ទៅធាតុជាក់លាក់ទេ (ដូចការចុចប៊ូតុងមួួយ)។ សម្រាប់ហ្គេមអាកាសយានរបស់យើង យើងនឹងផ្តោតទៅលើការគ្រប់គ្រងតាមរយៈក្តារចុចពីព្រោះវ៉ាអាចផ្តល់អារម្មណ៍ហ្គេម arcade ដោយសារៈសំខាន់ដល់អ្នកលេង។
វាបម្រាមជួយជំរាបថាការចុចក្តារចុចមានអត្ថន័យដូចការប្រែសំឡេង ម៉ូស៍កូដ (Morse code) ដែលអ្នកប្រើtelegramនៅសតវត្សទី១៩ត្រូវបម្លែងវាទៅជាសារសំខាន់ៗ យើងកំពុងធ្វើអ្វីដូចគ្នា សន្ទស្សន៏ក្តារចុចទៅជាពាក្យបញ្ជាហ្គេម។
ដើម្បីគ្រប់គ្រងព្រឹត្តិការណ៍ អ្នកត្រូវប្រើវិធីសាស្រ្ត `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: ចុចក្តារចុច ArrowUp
Browser->>EventSystem: ព្រឹត្តិការណ៍ keydown
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 ភិកសែលគ្រប់ពេល
- **រក្សា** លេខសម្គាល់រង្វាស់ម៉ោងនោះ ដើម្បីបញ្ឈប់វាបានបន្ទាប់ប្រសិនបើចាំបាច់
- **ផ្លាស់ទី** សត្រូវចុះក្រោមអេក្រង់ដោយស្វ័យប្រវត្តិ
## រង្វង់ហ្គេម
នេះជាគំនិតដែលភ្ជាប់គ្រប់យ៉ាងទាំងអស់ រង្វង់ហ្គេម។ ប្រសិនបើហ្គេមរបស់អ្នកជាផលិតកម្មភាពយន្ត រង្វង់ហ្គេមនឹងជាឧបករណ៍បញ្ចាំងទាំងអស់ បង្ហាញទំព័រតាមទំព័រយ៉ាងរហ័សទាំងដែលឲ្យមើលឃើញចលនាត្រង់សុភាព។
គ្រប់ហ្គេមមានរង្វង់បែបនេះដែលដំណើរការក្រោយឆatem។ វាជាមុខងារដែលធ្វើបច្ចុប្បន្នភាពវត្ថុរបស់ហ្គេមទាំងអស់ គូរឡើងវិញអេក្រង់ និងធ្វើឡើងម្ដងម្កាលជាបន្តបន្ទាប់។ វាអាចតាមដានវិរុទ្ធរបស់អ្នក រួមទាំងសត្រូវ ទាំងកាំភ្លើង និងសភាពហ្គេមទាំងមូល។
គំនិតនេះធ្វើឲ្យចង្អុលបង្ហាញពីរបៀបដែលអ្នកគូរអាណីម៉េត័រប្រទេសដើមជាមួយ 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) ប្រសិនបើអ្នកត្រូវការចាប់ផ្តើមថ្មី)។
**នេះគឺអ្វីដែលយើងកំពុងសាងសង់ថ្ងៃនេះ៖**
- **ការគ្រប់គ្រងវិរុទ្ធ**៖ ប៊ូតុងព្រួញនឹងបើកបរ យន្តហោះរបស់អ្នកនៅរង្វង់អេក្រង់
- **ចលនាសត្រូវ**៖ នាវាអ alien នឹងចាប់ផ្តើមចាក់ដំណើរការ
ចាប់ផ្តើមអនុវត្តលក្ខណះទាំងនេះ។
## ជំហានដែលសូមណែនាំ
ស្វែងរកឯកសារដែលបានបង្កើតសម្រាប់អ្នកក្នុងថត `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`។ បើកកម្មវិធីរុករក ហើយបញ្ចូលអាសយដ្ឋាននោះ ឥឡូវវាគួរតែបង្ហាញវិរុទ្ធ និងសត្រូវទាំងអស់; មិនមានអ្វីផ្លាស់ទីទេ - រហូតដល់ឥឡូវ!
### បន្ថែមកូដ
1. **បន្ថែមវត្ថុផ្តល់ការ** សម្រាប់ `hero` និង `enemy` និង `game object` ពួកវាគួរតែមានគុណលក្ខណៈ `x` និង `y`។ (ចងចាំផ្នែក [Inheritance ឬ composition](../README.md))។
*សំគាល់* `game object` គួរតែជាវត្តុដែលមាន `x` និង `y` និងមានសមត្ថភាពគូរទៅ canvas។
> **ជំនួយ**៖ ចាប់ផ្តើមដោយបន្ថែមថ្នាក់ `GameObject` ថ្មីដែលមាន constructor ដូចខាងក្រោម ហើយបន្ទាប់មកគូរវាទៅ canvas៖
```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()` ដែលគូរវត្ថុទៅលើ canvas
- **កំណត់** តម្លៃលំនាំដើមសម្រាប់គុណលក្ខណៈទាំងអស់ដែលថ្នាក់កូនអាចលើកឡើងបាន
```mermaid
classDiagram
class GameObject {
+x: number
+y: number
+dead: boolean
+type: string
+width: number
+height: number
+img: រូបភាព
+draw(ctx)
}
class Hero {
+speed: ចំនួន
+type: "វីរបុរស"
+width: 98
+height: 75
}
class Enemy {
+type: "សត្រូវ"
+width: 98
+height: 50
+setInterval()
}
GameObject <|-- Hero
GameObject <|-- Enemy
class EventEmitter {
+listeners: វត្ថុ
+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`
- **ហៅ** កំណត់ constructor ប៉ារ៉េនត៍ជាមួយ `super(x, y)`
- **កំណត់** ទំហំនិងគុណលក្ខណៈជាក់លាក់ សម្រាប់វត្ថុបែបផ្សេងៗ
- **អនុវត្ត** ចលនាស្វ័យប្រវត្តិសម្រាប់សត្រូវដោយប្រើ `setInterval()`
2. **បន្ថែមអ្នកចាប់ព្រឹត្តិការណ៍គ្រប់គ្រង key-event** សម្រាប់គ្រប់គ្រងការត្រួតពិនិត្យក្តារចុច (ចលាវិរុទ្ធឡើង/ចុះឆ្វេង/ស្តាំ)
*ចងចាំ* វាជាប្រព័ន្ធកាតេស៊្យាន(top-left ជា `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) pattern ដែលនឹងគ្រប់គ្រងកូដរបស់អ្នកឱ្យស្អាតពេលអ្នកធ្វើតាមផ្នែកដែលនៅសល់។
លំនាំ 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["KEY_EVENT_UP"]
C --> E["KEY_EVENT_DOWN"]
C --> F["KEY_EVENT_LEFT"]
C --> G["KEY_EVENT_RIGHT"]
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();
```
**យល់ដឹងអំពីការរៀបចំ:**
- **កំណត់** អថេរពាក្យសារ ដើម្បីជៀសវាងកំហុសហ្រ្វាំ និងងាយស្រួលកែលម្អ
- **ប្រកាស** អថេររូបភាព, context canvas និងស្ថានភាពហ្គេម
- **បង្កើត** រង្វង់ព្រឹត្តិការណ៍សកលសំរាប់ប្រព័ន្ធ 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);
};
```
**យល់ដឹងអំពីការរៀបចំហ្គេម៖**
- **រង់ចាំ** ទំព័រត្រូវបានផ្ទុកពេញលេញមុនចាប់ផ្ដើម
- **យក** ធាតុ canvas និង context សំរាប់គំនូរ 2D របស់វា
- **ផ្ទុក** រូបភាពទាំងអស់យ៉ាងអាស៊ីនខណៈដោយប្រើ `await`
- **ចាប់ផ្ដើម** លំហូរហ្គេមដែលរត់ជាប្រក្រឹត់លើចន្លោះ 100ms (10 FPS)
- **សំអាត** និងគូរសារឡើងវិញអេក្រង់ទាំងមូលក្នុងរាល់ខ្ទង់ពេល
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);
}
```
**អ្វីដែលការបង្កើតវីរបុរសធ្វើ៖**
- **ចាក់ទីតាំង** វីរបុរសនៅចំណុចខាងក្រោមកណ្ដាលអេក្រង់
- **ផ្ដល់** រូបភាពវីរបុរសទៅវត្ថុវីរបុរស
- **បន្ថែម** វីរបុរសទៅក្នុងអារ game objects សម្រាប់គំនូរ
ហើយចុងបញ្ចប់ បន្ថែមមុខងារ `drawGameObjects()` ដើម្បីចាប់ផ្ដើមគូរវត្ថុ:
```javascript
function drawGameObjects(ctx) {
gameObjects.forEach(go => go.draw(ctx));
}
```
**យល់ដឹងអំពីមុខងារគូរ៖**
- **ធ្វើបន្ទាត់** តាមរយៈវត្ថុំហ្គេមទាំងអស់ក្នុងអារ
- **ហៅ** មុខងារ `draw()` លើគ្រប់វត្ថុ
- **ផ្ដល់** context canvas ដូច្នេះវត្ថុអាចគូរផ្ទាល់ខ្លួន
### 🔄 **ពិនិត្យការយល់ដឹង​ចំណេះដឹង**
**យល់ដឹងឆ្លាតវៃអំពីប្រព័ន្ធហ្គេមសរុប**៖ ពិនិត្យការយល់ដឹងរបស់អ្នកអំពីសំណង់ទាំងមូល៖
- តើការចិញ្ចើមធ្វើឲ្យ Hero និង Enemy ចែករំលែកលក្ខណៈ GameObject យ៉ាងដូចម្តេច?
- ហេតុអ្វីបានជា​របៀប pub/sub ធ្វើឲ្យកូដរបស់អ្នកអាចថែរក្សาง่ายជាងមុន?
- តើលំហូរហ្គេមមានតួនាទីអ្វីក្នុងការបង្កើតអង់ម៉ាស៊ីនរលូន?
- តើអ្នកស្ដាប់ព្រឹតិ្តការណ៍ភ្ជាប់ការបញ្ចូលរបស់អ្នកប្រើទៅនឹងអាកប្បកិរិយាវត្ថុហ្គេមដូចម្តេច?
**ការរួមបញ្ចូលប្រព័ន្ធ**៖ ហ្គេមរបស់អ្នកឥឡូវនេះបង្ហាញថា៖
- **រចនាបថអចិន្រ្តៃយ៍**៖ ថ្នាក់មូលដ្ឋានដែលមានការចិញ្ចើមជាពិសេស
- **សំណង់លើព្រឹតិ្តការណ៍**៖ របៀប pub/sub សម្រាប់ការតភ្ជាប់បន្តួយៗ
- **ស៊ុមខ្សែអនុភាព**៖ លំហូរហ្គេមដែលមានការអាប់ដេតថេរៗ
- **សម្ភារៈបញ្ចូល**៖ ព្រឹតិ្តការណ៍ក្តារចុចជាមួយការព្រមានលំនាំដើម
- **គ្រប់គ្រងទ្រព្យសម្បត្តិ**៖ ការផ្ទុករូបភាព និងគូរបង្ហាញ sprites
**គំរូវិជ្ជាជីវៈ**៖ អ្នកបានអនុវត្ត៖
- **បំបែកការទំនួលខុសត្រូវ**៖ បញ្ចូល, តុល្យភាព និងគំនូរត្រូវបានបំបែក
- **ពហុរាង**៖ គ្រប់វត្ថុហ្គេមចែករំលែកផ្ទាំងតំណាងគូរ
- **ផ្លូវសារ**៖ ការប្រាស្រ័យទាក់ទងស្អាតរវាងក្រុមផ្សេងៗ
- **គ្រប់គ្រងធនធាន**៖ ការគ្រប់គ្រងស្ព្រាយ និងអនុភាពមានប្រសិទ្ធិភាព
សត្រូវរបស់អ្នកគួរតែចាប់ផ្ដើមរំកិលទៅលើកប៉ាល់មហានៅរបស់អ្នកហើយ!
}
}
```
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 ដែលការពារកាឡាក់ភ័ឡង់ពីការលំលងចំណុចប្រតិបត្តិការដែលមានសុវត្ថិភាព។
**អ្វីដែលត្រូវបង្កើត៖** បង្កើតប្រព័ន្ធដែលរក្សាវីរបុរសរបស់អ្នកនៅលើអេក្រង់ ហើយធ្វើឲ្យការគ្រប់គ្រងមានភាពរលោង។ នៅពេលអ្នកលេងចុចរាល់លើប៊ូតុងអក្សរបស់ភ្លើងដែលចុច។ កប៉ាល់គួរជ្រេបទៅមុខបន្តបន្ទាប់ មិនមែនផ្លាស់ទីតាមជំហានតែមួយៗទេ។ ពិចារណាបន្ថែមមាតិកាដែលបង្ហាញរូបភាពពេលកប៉ាល់ដល់ដែនកំណត់អេក្រង់ ប្រហែលជា​អេហ្វធីតតូចៗមួយដើម្បីបង្ហាញដែនលេង។
​សូមស្វែងយល់បន្ថែមអំពី [ម៉ូដ​ក្នុង​តំណាង](https://code.visualstudio.com/blogs/2025/02/24/introducing-copilot-agent-mode) នៅទីនេះ។
## 🚀 ការប្រកួត
ការរៀបចំកូដកាន់តែមានសារៈសំខាន់បន្ថែមឡើងពេលគម្រោងធំឡើង។ អ្នកអាចមានមើលឃើញថា​ឯកសាររបស់អ្នកពោរពេញដោយមុខងារ អថេរ និងថ្នាក់។ វាជារៀនសូត្រដូចជាអ្នកវិស្វករសម្រាប់ការរៀបចំកូដភាគច្រើនដែលក្រុមនានាត្រូវបានធ្វើការជាមួយគ្នា។
**បេសកកម្មរបស់អ្នក៖**
គិតដូចជាវិស្វករពហុកម្មវិធី។ តើអ្នកនឹងរៀបចំកូដរបស់អ្នកដូចម្តេច ដើម្បីឲ្យប្រាំមួយខែទៀត អ្នកឬសមាជិកក្រុមអាចយល់ពីអ្វីកំពុងកើតឡើង? ទោះបីឯកសារទាំងអស់នៅក្នុងឯកសារមួយ ក៏អ្នកអាចបង្កើតការរៀបចំដែលល្អជាងនេះ៖
- **ក្រុមមុខងារពាក់ព័ន្ធគ្នា** ជាមួយក្បួនមតិការអធិប្បាយច្បាស់លាស់
- **បំបែកការទំនួលខុសត្រូវ** - រក្សាគ្រប់គ្រងហ្គេមពីការជួរមុខគំនូរ
- **ប្រើកំណត់ឈ្មោះយ៉ាងត្រឹមត្រូវ** សម្រាប់អថេរ និងមុខងារ
- **បង្កើតម៉ូឌុល** namespace ដើម្បីរៀបចំផ្នែកផ្សេងៗក្នុងហ្គេម
- **បន្ថែមឯកសារសង្ខេប** ដែលពន្យល់ពីគោលបំណងនៃផ្នែកធម្មតាៗ
**សំណួរពិចារណា៖**
- តើផ្នែកណានៃកូដរបស់អ្នកពិបាកយល់បំផុត នៅពេលអ្នកត្រឡប់មកវិញ?
- តើអ្នកអាចរៀបចំកូដរបស់អ្នកដូចម្តេច ដើម្បីធ្វើឲ្យមនុស្សផ្សេងទៀតអាចរួមចំណែកបានកាន់តែងាយស្រួល?
- តើអ្វីនឹងកើតឡើង ប្រសិនបើអ្នកចង់បន្ថែមមុខងារថ្មីៗ ដូចជាពូម៉ឺ up ប្រភេទសត្រូវផ្សេងទៀត?
## សំនួរប្រឡងបន្ទាប់ពីមេរៀន
[សំនួរប្រឡងបន្ទាប់ពីមេរៀន](https://ff-quizzes.netlify.app/web/quiz/34)
## ពិនិត្យឡើងវិញ & ការសិក្សាឯករាជ្យ
យើងបានបង្កើតគ្រប់អ្វីពីដើម ដែលវាអស្ចារ្យសម្រាប់ការរៀន ប៉ុន្តែល្អប្រសើរជាងនេះ មាន框架 JavaScript ខ្លះៗដែលអាចធ្វើការទាញទំនិញធ្ងន់ធ្ងរច្រើនសម្រាប់អ្នក។ បន្ទាប់ពីអ្នកមានអារម្មណ៍ស្រួលល្អជាមួយមូលដ្ឋានយើងបានគ្រប់ដ្ឋាន អ្នកគួរតែ [ស្វែងយល់វត្ថុដែលអាចប្រើបាន](https://github.com/collections/javascript-game-engines)
គិតថា 框架ដូចជា ប្រដាប់ឧបករណ៍ដែលមានឧបករណ៍ពេញលេញជំនួសអំពីការធ្វើឧបករណ៍ដោយដៃ។ វាអាចដោះស្រាយបញ្ហានៃការរៀបចំកូដយើងបាននិយាយ និងផ្តល់លក្ខណៈពិសេសដែលត្រូវការពេលប៉ុន្មានសប្តាហ៍ដើម្បីបង្កើតដោយខ្លួនឯង។
**រឿងដែលគួរនៅស្វែងយល់៖**
- របៀបដែលហ្គេមម៉ាស៊ីនរៀបចំកូដ - អ្នកនឹងភ្ញាក់ផ្អើលពីគំរូវៃឆ្លាតដែលពួកគេប្រើ
- ល្បិចប្រសិទ្ធភាពសម្រាប់ធ្វើឲ្យហ្គេម canvas រត់រលូន
- លក្ខណៈពិសេស JavaScript សម័យថ្មីដែលអាចធ្វើឲ្យកូដអ្នកស្អាតនិងថែទាំបានងាយ
- មធ្យោបាយផ្សេងៗក្នុងការគ្រប់គ្រងវត្ថុហ្គេម និងទំនាក់ទំនងរបស់ពួកវា
## 🎯 របៀបម៉ាស៊ីនរូបភាពហ្គេមរបស់អ្នក
```mermaid
timeline
title ការរៀនអំពីផ្នែកចលនា និងអន្តរការ ឯកទេសហ្គេម
section មូលដ្ឋានចលនា (២០ នាទី)
គោលការណ៍ អ្នកចលនា: ស៊េរីឯកសារជារូបភាព
: ការអាប់ដេតទីតាំង
: ប្រព័ន្ធកូអរដោនេ이트
: ចលនារលូន
section ប្រព័ន្ធព្រឹត្តិការណ៍ (២៥ នាទី)
បញ្ចូលអ្នកប្រើ: ការគ្រប់គ្រងព្រឹត្តិការណ៍ក្តាស់ក្លាវ
: ការកាត់បន្ថយការជីកអោយមានការសកម្មឯកសារ
: លក្ខណៈព្រឹត្តិការណ៍វត្ថុ
: ការស្តាប់នៅលើបន្ទាត់បង្អួច
section រចនាសម្ព័ន្ធហ្គេម (៣០ នាទី)
ការរចនាវត្ថុ: រចនាបថបInheritance
: បង្កើតថ្នាក់មេ
: អាកប្បកិរិយាពិសេស
: ចំណុចប្រទាក់ងាយបម្លែង
section រចនាបទការទំនាក់ទំនង (៣៥ នាទី)
ការអនុវត្ត Pub/Sub: អ្នកបញ្ចេញព្រឹត្តិការណ៍
: អចលនាប័ណ្ណសារ
: ការតភ្ជាប់រាបសារ
: ការរួមបញ្ចូលប្រព័ន្ធ
section ជំនាញវដ្តហ្គេម (៤០ នាទី)
ប្រព័ន្ធពេលពិត: ការគ្រប់គ្រងអត្រារ៉េម
: វដ្តកែប្រែ/បង្ហាញ
: ការគ្រប់គ្រងស្ថានភាព
: បង្កើនប្រសិទ្ធភាព
section បច្ចេកទេសខ្ពស់ (៤៥ នាទី)
លក្ខណៈជំនាញ: ការរកឃើញការប៉ះទង្គិច
: ការសំឡេងហ័រ
: ម៉ាស៊ីនស្ថានភាព
: ប្រព័ន្ធបន្ទុក
section គំនិតម៉ាស៊ីនហ្គេម (១ សប្តាហ៍)
ការយល់ដឹងស៊េរី: ប្រព័ន្ធអង្គភាព-ផ្សេងៗ
: ក្រាហ្វភីបន្ទះ
: បណ្តោយទ្រព្យសម្បត្តិ
: ការវាយតម្លៃប្រសិទ្ធភាព
section ជំនាញផលិតកម្ម (១ ខែ)
ការអភិវឌ្ឍជំនាញ: ការរៀបចំកូដ
: ការសហការជាក្រុម
:យុទ្ធសាស្រ្តការប្រមូលផ្តុំនូវតេស្ត
: ការបង្កើនប្រសិទ្ធភាពដាក់បញ្ចេញ
```
### 🛠️ សង្ខេបប្រដាប់សម្រាប់អភិវឌ្ឍហ្គេមរបស់អ្នក
បន្ទាប់ពីបញ្ចប់មេរៀននេះ អ្នកបានទទួលជំនាញ៖
- **គោលការណ៍អនុភាព**៖ ចលនាដោយខ្ទង់ និងការប្រែប្រួលរលូន
- **កម្មវិធីផ្អែកលើព្រឹតិ្តការណ៍**៖ ការគ្រប់គ្រងបញ្ចូលពីក្តារចុច ជាមួយការគ្រប់គ្រងព្រឹតិ្តការណ៍ត្រឹមត្រូវ
- **រចនាបថអចិន្រ្តៃយ៍**៖ ការចិញ្ចើមរៀងៗខ្លួន និងផ្ទាំងតំណាងភាគីជាច្រើនរាង
- **គំរូការប្រាស្រ័យ**៖ សំណង់ pub/sub សម្រាប់កូដងាយថែរក្សា
- **សំណង់លំហូរហ្គេម**៖ ការអាប់ដេត និងគំនូរផ្សេងៗទាន់ពេលវេលា
- **ប្រព័ន្ធបញ្ចូល**៖ ការច្រកការគ្រប់គ្រងអ្នកប្រើជាមួយការព្រមានលំនាំដើម
- **គ្រប់គ្រងទ្រព្យសម្បត្តិ**៖ ការផ្ទុកស្ព្រាយ និងការគូរបង្ហាញប្រសិទ្ធិភាព
### ⚡ **អ្វីដែលអ្នកអាចធ្វើបានក្នុង 5 នាទីបន្ទាប់**
- [ ] បើក consoleក្នុងbrowser ហើយសាកល្បង `addEventListener('keydown', console.log)` ដើម្បីមើលព្រឹតិ្តការណ៍ក្តារចុច
- [ ] បង្កើតធាតុ div សាមញ្ញ និងផ្លាស់ទីវាដោយប្រើក្តារចុចបង្ខូច
- [ ] សាកល្បង `setInterval` ដើម្បីបង្កើតចលនាបន្ត
- [ ] ព្យាយាមការពារលំនាំដើម​ដោយ `event.preventDefault()`
### 🎯 **អ្វីដែលអ្នកអាចសម្រេចបានក្នុងម៉ោងនេះ**
- [ ] បញ្ចប់សំណួរប្រឡងបន្ទាប់ពីមេរៀន និងយល់ដឹងកម្មវិធីផ្អែកលើព្រឹតិ្តការណ៍
- [ ] បង្កើតកប៉ាល់វីរបុរសចលនាជាមួយការគ្រប់គ្រងក្តារចុចពេញលេញ
- [ ] អនុវត្តលំនាំចលនាសត្រូវទន់Smooth
- [ ] បន្ថែមដែនកំណត់ដើម្បីរារាំងវត្ថុហ្គេមចេញពីអេក្រង់
- [ ] បង្កើតការស្កេនករណីជួបប្រទៈមូលដ្ឋានរវាងវត្ថុហ្គេម
### 📅 **ការធ្វើដំណើរអនុភាពរបស់អ្នកក្នុងមួយសប្តាហ៍**
- [ ] បញ្ចប់ហ្គេមអាកាសពេញលេញជាមួយចលនាបន្លឺ និងអថេរភាព
- [ ] បន្ថែមលំនាំចលនាជ្រៅដូចជា​ខ្សែ, បន្ទុះ, និងរូបវិទ្យា
- [ ] អនុវត្តពន្លឺរលោង និងមុខងារជ្រេបរលាក
- [ ] បង្កើតប៉ាត្រិច និងប្រព័ន្ធត្រួតពិនិត្យរូបភាព
- [ ] បង្កើតប្រសិទ្ធភាពហ្គេមសម្រាប់ការរត់រលូន 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 -->