18 KiB
Gumawa ng Space Game Bahagi 1: Panimula
Katulad ng mission control ng NASA na nagkokoordina ng maraming sistema sa panahon ng paglulunsad ng spacecraft, gagawa tayo ng isang space game na nagpapakita kung paano maaaring magtulungan ang iba't ibang bahagi ng isang programa nang maayos. Habang gumagawa ng isang bagay na maaari mong aktwal na laruin, matututo ka ng mahahalagang konsepto sa programming na maaaring gamitin sa anumang proyekto ng software.
Susuriin natin ang dalawang pangunahing paraan ng pag-oorganisa ng code: inheritance at composition. Hindi lang ito mga akademikong konsepto – ito ang mga pattern na ginagamit sa lahat mula sa video games hanggang sa mga sistema ng pagbabangko. Magpapatupad din tayo ng isang sistema ng komunikasyon na tinatawag na pub/sub na gumagana tulad ng mga network ng komunikasyon na ginagamit sa spacecraft, na nagpapahintulot sa iba't ibang bahagi na magbahagi ng impormasyon nang walang paglikha ng mga dependency.
Sa pagtatapos ng seryeng ito, maiintindihan mo kung paano bumuo ng mga application na maaaring mag-scale at mag-evolve – maging gumagawa ka man ng mga laro, web application, o anumang sistema ng software.
Pre-Lecture Quiz
Inheritance at Composition sa Pagbuo ng Laro
Habang lumalaki ang mga proyekto sa pagiging kumplikado, nagiging kritikal ang organisasyon ng code. Ang nagsimula bilang isang simpleng script ay maaaring maging mahirap panatilihin nang walang tamang istruktura – katulad ng kung paano ang Apollo missions ay nangangailangan ng maingat na koordinasyon sa pagitan ng libu-libong mga bahagi.
Susuriin natin ang dalawang pangunahing paraan ng pag-oorganisa ng code: inheritance at composition. Ang bawat isa ay may natatanging mga benepisyo, at ang pag-unawa sa pareho ay tumutulong sa iyo na pumili ng tamang paraan para sa iba't ibang sitwasyon. Ipapakita namin ang mga konseptong ito sa pamamagitan ng aming space game, kung saan ang mga bayani, kalaban, power-ups, at iba pang mga bagay ay kailangang mag-interact nang mahusay.
✅ Isa sa mga pinakasikat na aklat sa programming ay tungkol sa design patterns.
Sa anumang laro, mayroon kang game objects – ang mga interactive na elemento na bumubuo sa mundo ng laro. Ang mga bayani, kalaban, power-ups, at visual effects ay lahat ng game objects. Ang bawat isa ay umiiral sa mga partikular na coordinate ng screen gamit ang x at y na mga halaga, katulad ng pag-plot ng mga puntos sa isang coordinate plane.
Sa kabila ng kanilang mga visual na pagkakaiba, madalas na may mga karaniwang pag-uugali ang mga bagay na ito:
- Umiiral sila sa isang lugar – Ang bawat bagay ay may x at y coordinates para malaman ng laro kung saan ito iguguhit
- Marami ang maaaring gumalaw – Tumakbo ang mga bayani, habulin ng mga kalaban, lumipad ang mga bala sa screen
- May lifespan sila – Ang ilan ay nananatili magpakailanman, ang iba (tulad ng mga pagsabog) ay lumilitaw nang sandali at nawawala
- Reaksyon sila sa mga bagay – Kapag nagbanggaan, nakokolekta ang mga power-ups, nag-a-update ang mga health bar
✅ Isipin ang isang laro tulad ng Pac-Man. Maaari mo bang tukuyin ang apat na uri ng mga bagay na nakalista sa itaas sa larong ito?
Pagpapahayag ng Pag-uugali sa Pamamagitan ng Code
Ngayon na naiintindihan mo ang mga karaniwang pag-uugali na ibinabahagi ng mga game objects, tingnan natin kung paano ipatupad ang mga pag-uugaling ito sa JavaScript. Maaari mong ipahayag ang pag-uugali ng mga bagay sa pamamagitan ng mga method na nakakabit sa mga klase o indibidwal na mga bagay, at may ilang mga paraan na maaaring piliin.
Ang Paraan na Batay sa Klase
Ang mga klase at inheritance ay nagbibigay ng istrukturadong paraan ng pag-oorganisa ng mga game objects. Katulad ng taxonomic classification system na binuo ni Carl Linnaeus, nagsisimula ka sa isang base class na naglalaman ng mga karaniwang properties, pagkatapos ay lumikha ng mga espesyal na klase na nagmamana ng mga pundasyon habang nagdaragdag ng mga partikular na kakayahan.
✅ Ang inheritance ay isang mahalagang konsepto na dapat maunawaan. Matuto pa sa artikulo ng MDN tungkol sa inheritance.
Narito kung paano mo maipapatupad ang mga game objects gamit ang mga klase at inheritance:
// Step 1: Create the base GameObject class
class GameObject {
constructor(x, y, type) {
this.x = x;
this.y = y;
this.type = type;
}
}
Himayin natin ito nang hakbang-hakbang:
- Gumagawa tayo ng isang pangunahing template na maaaring gamitin ng bawat game object
- Ang constructor ay nagse-save kung nasaan ang object (
x,y) at kung anong uri ng bagay ito - Ito ang nagiging pundasyon na gagamitin ng lahat ng iyong game objects
// Step 2: Add movement capability through inheritance
class Movable extends GameObject {
constructor(x, y, type) {
super(x, y, type); // Call parent constructor
}
// Add the ability to move to a new position
moveTo(x, y) {
this.x = x;
this.y = y;
}
}
Sa itaas, ginawa natin ang sumusunod:
- In-extend ang GameObject class upang magdagdag ng functionality sa paggalaw
- Tinawag ang parent constructor gamit ang
super()upang i-initialize ang mga inherited properties - Nagdagdag ng
moveTo()method na nag-a-update sa posisyon ng object
// Step 3: Create specific game object types
class Hero extends Movable {
constructor(x, y) {
super(x, y, 'Hero'); // Set type automatically
}
}
class Tree extends GameObject {
constructor(x, y) {
super(x, y, 'Tree'); // Trees don't need movement
}
}
// Step 4: Use your game objects
const hero = new Hero(0, 0);
hero.moveTo(5, 5); // Hero can move!
const tree = new Tree(10, 15);
// tree.moveTo() would cause an error - trees can't move
Pag-unawa sa mga konseptong ito:
- Lumilikha ng mga espesyal na uri ng object na nagmamana ng naaangkop na mga pag-uugali
- Nagpapakita kung paano pinapayagan ng inheritance ang selective feature inclusion
- Ipinapakita na ang mga bayani ay maaaring gumalaw habang ang mga puno ay nananatiling stationary
- Nagpapakita kung paano pinipigilan ng class hierarchy ang mga hindi naaangkop na aksyon
✅ Maglaan ng ilang minuto upang muling isipin ang isang Pac-Man hero (Inky, Pinky o Blinky, halimbawa) at kung paano ito isusulat sa JavaScript.
Ang Paraan ng Composition
Ang composition ay sumusunod sa modular na pilosopiya ng disenyo, katulad ng kung paano dinisenyo ng mga inhinyero ang spacecraft na may mga interchangeable na bahagi. Sa halip na magmana mula sa isang parent class, pinagsasama mo ang mga partikular na pag-uugali upang lumikha ng mga bagay na may eksaktong functionality na kailangan nila. Ang paraang ito ay nag-aalok ng flexibility nang walang mahigpit na hierarchical constraints.
// Step 1: Create base behavior objects
const gameObject = {
x: 0,
y: 0,
type: ''
};
const movable = {
moveTo(x, y) {
this.x = x;
this.y = y;
}
};
Narito ang ginagawa ng code na ito:
- Nagde-define ng base
gameObjectna may position at type properties - Lumilikha ng hiwalay na
movablebehavior object na may functionality sa paggalaw - Naghiwalay ng mga concern sa pamamagitan ng pagpapanatili ng position data at movement logic na independent
// Step 2: Compose objects by combining behaviors
const movableObject = { ...gameObject, ...movable };
// Step 3: Create factory functions for different object types
function createHero(x, y) {
return {
...movableObject,
x,
y,
type: 'Hero'
};
}
function createStatic(x, y, type) {
return {
...gameObject,
x,
y,
type
};
}
Sa itaas, ginawa natin ang sumusunod:
- Pinagsama ang base object properties sa movement behavior gamit ang spread syntax
- Lumilikha ng mga factory function na nagbabalik ng customized na mga object
- Nag-enable ng flexible object creation nang walang mahigpit na class hierarchies
- Nagpapahintulot sa mga object na magkaroon ng eksaktong mga pag-uugali na kailangan nila
// Step 4: Create and use your composed objects
const hero = createHero(10, 10);
hero.moveTo(5, 5); // Works perfectly!
const tree = createStatic(0, 0, 'Tree');
// tree.moveTo() is undefined - no movement behavior was composed
Mga mahalagang punto na dapat tandaan:
- Nagko-compose ng mga object sa pamamagitan ng pag-mix ng mga pag-uugali sa halip na magmana ng mga ito
- Nagbibigay ng mas maraming flexibility kaysa sa mahigpit na inheritance hierarchies
- Nagpapahintulot sa mga object na magkaroon ng eksaktong mga feature na kailangan nila
- Gumagamit ng modernong JavaScript spread syntax para sa malinis na object combination
**Which Pattern Should You Choose?**
> 💡 **Pro Tip**: Both patterns have their place in modern JavaScript development. Classes work well for clearly defined hierarchies, while composition shines when you need maximum flexibility.
>
**Here's when to use each approach:**
- **Choose** inheritance when you have clear "is-a" relationships (a Hero *is-a* Movable object)
- **Select** composition when you need "has-a" relationships (a Hero *has* movement abilities)
- **Consider** your team's preferences and project requirements
- **Remember** that you can mix both approaches in the same application
## Communication Patterns: The Pub/Sub System
As applications grow complex, managing communication between components becomes challenging. The publish-subscribe pattern (pub/sub) solves this problem using principles similar to radio broadcasting – one transmitter can reach multiple receivers without knowing who's listening.
Consider what happens when a hero takes damage: the health bar updates, sound effects play, visual feedback appears. Rather than coupling the hero object directly to these systems, pub/sub allows the hero to broadcast a "damage taken" message. Any system that needs to respond can subscribe to this message type and react accordingly.
✅ **Pub/Sub** stands for 'publish-subscribe'
### Understanding the Pub/Sub Architecture
The pub/sub pattern keeps different parts of your application loosely coupled, meaning they can work together without being directly dependent on each other. This separation makes your code more maintainable, testable, and flexible to changes.
**The key players in pub/sub:**
- **Messages** – Simple text labels like `'PLAYER_SCORED'` that describe what happened (plus any extra info)
- **Publishers** – The objects that shout out "Something happened!" to anyone who's listening
- **Subscribers** – The objects that say "I care about that event" and react when it happens
- **Event System** – The middleman that makes sure messages get to the right listeners
### Building an Event System
Let's create a simple but powerful event system that demonstrates these concepts:
```javascript
// Step 1: Create the EventEmitter class
class EventEmitter {
constructor() {
this.listeners = {}; // Store all event listeners
}
// Register a listener for a specific message type
on(message, listener) {
if (!this.listeners[message]) {
this.listeners[message] = [];
}
this.listeners[message].push(listener);
}
// Send a message to all registered listeners
emit(message, payload = null) {
if (this.listeners[message]) {
this.listeners[message].forEach(listener => {
listener(message, payload);
});
}
}
}
Paghimay sa nangyayari dito:
- Lumilikha ng central event management system gamit ang isang simpleng klase
- Nag-iimbak ng mga listener sa isang object na naka-organize ayon sa uri ng mensahe
- Nagre-rehistro ng mga bagong listener gamit ang
on()method - Nagbo-broadcast ng mga mensahe sa lahat ng interesadong listener gamit ang
emit() - Sumusuporta sa optional na data payloads para sa pagpapasa ng kaugnay na impormasyon
Pagsasama-sama: Isang Praktikal na Halimbawa
Sige, tingnan natin ito sa aksyon! Bubuo tayo ng isang simpleng movement system na nagpapakita kung gaano kalinis at flexible ang pub/sub:
// Step 1: Define your message types
const Messages = {
HERO_MOVE_LEFT: 'HERO_MOVE_LEFT',
HERO_MOVE_RIGHT: 'HERO_MOVE_RIGHT',
ENEMY_SPOTTED: 'ENEMY_SPOTTED'
};
// Step 2: Create your event system and game objects
const eventEmitter = new EventEmitter();
const hero = createHero(0, 0);
Narito ang ginagawa ng code na ito:
- Nagde-define ng constants object upang maiwasan ang mga typo sa mga pangalan ng mensahe
- Lumilikha ng event emitter instance upang pamahalaan ang lahat ng komunikasyon
- Nag-i-initialize ng hero object sa starting position
// Step 3: Set up event listeners (subscribers)
eventEmitter.on(Messages.HERO_MOVE_LEFT, () => {
hero.moveTo(hero.x - 5, hero.y);
console.log(`Hero moved to position: ${hero.x}, ${hero.y}`);
});
eventEmitter.on(Messages.HERO_MOVE_RIGHT, () => {
hero.moveTo(hero.x + 5, hero.y);
console.log(`Hero moved to position: ${hero.x}, ${hero.y}`);
});
Sa itaas, ginawa natin ang sumusunod:
- Nagrehistro ng mga event listener na tumutugon sa mga movement message
- Nag-update ng posisyon ng hero batay sa direksyon ng paggalaw
- Nagdagdag ng console logging upang subaybayan ang mga pagbabago sa posisyon ng hero
- Naghiwalay ng movement logic mula sa input handling
// Step 4: Connect keyboard input to events (publishers)
window.addEventListener('keydown', (event) => {
switch(event.key) {
case 'ArrowLeft':
eventEmitter.emit(Messages.HERO_MOVE_LEFT);
break;
case 'ArrowRight':
eventEmitter.emit(Messages.HERO_MOVE_RIGHT);
break;
}
});
Pag-unawa sa mga konseptong ito:
- Nagkokonekta ng keyboard input sa mga game event nang walang tight coupling
- Nag-enable sa input system na makipag-ugnayan sa mga game object nang hindi direktang nakikilala ang isa't isa
- Nagpapahintulot sa maraming sistema na tumugon sa parehong keyboard events
- Ginagawang madali ang pagbabago ng key bindings o pagdaragdag ng mga bagong input method
💡 Pro Tip: Ang kagandahan ng pattern na ito ay ang flexibility! Madali kang makakapagdagdag ng sound effects, screen shake, o particle effects sa pamamagitan lamang ng pagdaragdag ng higit pang event listener – walang kailangang baguhin sa umiiral na keyboard o movement code.
Narito kung bakit magugustuhan mo ang paraang ito:
- Ang pagdaragdag ng mga bagong feature ay nagiging napakadali – makinig lang sa mga event na mahalaga sa iyo
- Maraming bagay ang maaaring tumugon sa parehong event nang hindi nagkakagulo
- Ang testing ay nagiging mas simple dahil ang bawat bahagi ay gumagana nang independent
- Kapag may nasira, alam mo kung saan eksaktong titingin
Bakit Epektibo ang Pag-scale ng Pub/Sub
Ang pub/sub pattern ay nagpapanatili ng pagiging simple habang lumalaki ang pagiging kumplikado ng mga application. Maging sa pamamahala ng dose-dosenang mga kalaban, dynamic na UI updates, o sound systems, hinahawakan ng pattern ang pagtaas ng scale nang walang pagbabago sa arkitektura. Ang mga bagong feature ay madaling isama sa umiiral na event system nang hindi naaapektuhan ang naitatag na functionality.
⚠️ Karaniwang Pagkakamali: Huwag gumawa ng masyadong maraming partikular na uri ng mensahe sa simula. Magsimula sa malawak na mga kategorya at i-refine ang mga ito habang nagiging mas malinaw ang mga pangangailangan ng iyong laro.
Mga pinakamahusay na kasanayan na dapat sundin:
- Naggrupo ng mga kaugnay na mensahe sa lohikal na mga kategorya
- Gumagamit ng mga deskriptibong pangalan na malinaw na nagpapahiwatig kung ano ang nangyari
- Pinapanatili ang mga payload ng mensahe na simple at nakatuon
- Nagdo-dokumento ng iyong mga uri ng mensahe para sa pakikipagtulungan sa koponan
Hamon ng GitHub Copilot Agent 🚀
Gamitin ang Agent mode upang kumpletuhin ang sumusunod na hamon:
Deskripsyon: Gumawa ng simpleng sistema ng game object gamit ang parehong inheritance at pub/sub pattern. Magpapatupad ka ng basic na laro kung saan ang iba't ibang object ay maaaring makipag-ugnayan sa pamamagitan ng mga event nang hindi direktang nakikilala ang isa't isa.
Prompt: Gumawa ng JavaScript game system na may sumusunod na mga kinakailangan: 1) Gumawa ng base GameObject class na may x, y coordinates at type property. 2) Gumawa ng Hero class na nag-extend sa GameObject at maaaring gumalaw. 3) Gumawa ng Enemy class na nag-extend sa GameObject at maaaring habulin ang hero. 4) Magpatupad ng EventEmitter class para sa pub/sub pattern. 5) Mag-set up ng mga event listener upang kapag gumalaw ang hero, ang mga malapit na kalaban ay makatanggap ng 'HERO_MOVED' event at i-update ang kanilang posisyon upang habulin ang hero. Isama ang mga console.log statement upang ipakita ang komunikasyon sa pagitan ng mga object.
Matuto pa tungkol sa agent mode dito.
🚀 Hamon
Pag-isipan kung paano maaaring mapahusay ng pub-sub pattern ang arkitektura ng laro. Tukuyin kung aling mga bahagi ang dapat mag-emit ng mga event at kung paano dapat tumugon ang sistema. Magdisenyo ng konsepto ng laro at i-map out ang mga pattern ng komunikasyon sa pagitan ng mga bahagi nito.
Post-Lecture Quiz
Review & Self Study
Matuto pa tungkol sa Pub/Sub sa pamamagitan ng pagbabasa tungkol dito.
Assignment
Paunawa:
Ang dokumentong ito ay isinalin gamit ang AI translation service na Co-op Translator. Bagamat sinisikap naming maging tumpak, mangyaring tandaan na ang mga awtomatikong pagsasalin ay maaaring maglaman ng mga pagkakamali o hindi pagkakatugma. Ang orihinal na dokumento sa kanyang katutubong wika ang dapat ituring na opisyal na pinagmulan. Para sa mahalagang impormasyon, inirerekomenda ang propesyonal na pagsasalin ng tao. Hindi kami mananagot sa anumang hindi pagkakaunawaan o maling interpretasyon na dulot ng paggamit ng pagsasaling ito.
