|
|
# សាងសង់ហ្គេមអាកាសយាន 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 --> |