journey
title Călătoria ta prin animația jocului
section Noțiuni de bază despre mișcare
Înțelege principiile mișcării: 3: Student
Învață actualizările coordonatelor: 4: Student
Implementează mișcarea de bază: 4: Student
section Controale jucător
Gestionează evenimentele tastaturii: 4: Student
Previi comportamentele implicite: 5: Student
Creează controale responsive: 5: Student
section Sisteme de joc
Construiește bucla jocului: 5: Student
Gestionează ciclul de viață al obiectelor: 5: Student
Implementează modelul pub/sub: 5: Student
Gândește-te la jocurile tale preferate – ceea ce le face captivante nu sunt doar grafica frumoasă, ci modul în care totul se mișcă și răspunde la acțiunile tale. Acum, jocul tău spațial este ca o pictură frumoasă, dar suntem pe cale să adăugăm mișcare care îi dă viață.
Când inginerii NASA au programat computerul de ghidare pentru misiunile Apollo, s-au confruntat cu o provocare similară: cum faci o navă spațială să răspundă la comenzile pilotului în timp ce menține automat corectarea traiectoriei? Principiile pe care le vom învăța astăzi reflectă aceleași concepte – gestionarea mișcării controlate de jucător împreună cu comportamentele automate ale sistemului.
În această lecție, vei învăța cum să faci navele spațiale să alunece pe ecran, să răspundă la comenzile jucătorului și să creezi tipare de mișcare fluide. Vom descompune totul în concepte gestionabile care se construiesc natural unul pe celălalt.
La final, jucătorii își vor pilota nava erou pe ecran în timp ce vasele inamice patrulează deasupra. Mai important, vei înțelege principiile fundamentale care alimentează sistemele de mișcare ale jocurilor.
mindmap
root((Animarea Jocului))
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
Jocurile prind viață când lucrurile încep să se miște, iar în esență există două moduri în care se întâmplă asta:
- Mișcare controlată de jucător: Când apeși o tastă sau dai click cu mouse-ul, ceva se mișcă. Aceasta este conexiunea directă între tine și lumea jocului tău.
- Mișcare automată: Când jocul însuși decide să miște lucrurile – cum ar fi vasele inamice care trebuie să patruleze ecranul indiferent dacă faci ceva sau nu.
Făcutul obiectelor să se miște pe un ecran de computer este mai simplu decât ai putea crede. Ți-aduci aminte de coordonatele x și y din ora de matematică? Exact cu asta lucrăm aici. Când Galileo a urmărit lunile lui Jupiter în 1610, practic făcea același lucru – plota poziții în timp pentru a înțelege tiparele de mișcare.
Mișcarea lucrurilor pe ecran este ca să creezi o animație dintr-o carte de flip – trebuie să urmezi acești trei pași simpli:
flowchart LR
A["Cadru N"] --> B["Actualizează pozițiile"]
B --> C["Șterge pânza"]
C --> D["Desenează obiectele"]
D --> E["Cadru N+1"]
E --> F{Continuăm?}
F -->|Da| B
F -->|Nu| G["Sfârșitul jocului"]
subgraph "Ciclu de animație"
H["1. Calculează noile poziții"]
I["2. Șterge cadrul anterior"]
J["3. Redă cadrul nou"]
end
style B fill:#e1f5fe
style C fill:#ffebee
style D fill:#e8f5e8
- Actualizează poziția – Schimbă locul unde ar trebui să fie obiectul tău (poate mută-l 5 pixeli spre dreapta)
- Șterge cadrul vechi – Curăță ecranul ca să nu vezi urme fantomatice peste tot
- Desenează cadrul nou – Pune obiectul tău în noua lui poziție
Fă asta suficient de rapid și bam! Ai mișcare fluidă care se simte naturală pentru jucători.
Iată cum ar putea arăta în cod:
// Setează locația eroului
hero.x += 5;
// Curăță dreptunghiul care găzduiește eroul
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Re-desenează fundalul jocului și eroul
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = "black";
ctx.drawImage(heroImg, hero.x, hero.y);Acesta este ce face acest cod:
- Actualizează coordonata x a eroului cu 5 pixeli pentru a-l mișca orizontal
- Curăță întreaga zonă a canvas-ului pentru a elimina cadrul anterior
- Umple canvas-ul cu o culoare de fundal neagră
- Redesenază imaginea eroului în noua poziție
✅ Te poți gândi la un motiv pentru care redessinarea eroului de mai multe cadre pe secundă ar putea implica costuri de performanță? Citește despre alternative la acest tipar.
Aici conectăm intrarea jucătorului la acțiunea din joc. Când cineva apasă bara de spațiu pentru a trage cu laserul sau apasă o săgeată pentru a evita un asteroid, jocul tău trebuie să detecteze și să răspundă la acea intrare.
Evenimentele de la tastatură se întâmplă la nivel de fereastră, ceea ce înseamnă că întregul tău browser ascultă acele apăsări de taste. Click-urile cu mouse-ul, pe de altă parte, pot fi legate de elemente specifice (cum ar fi apăsarea unui buton). Pentru jocul nostru spațial, ne vom concentra pe controlul prin tastatură deoarece acesta oferă jucătorilor sentimentul clasic de arcade.
Aceasta îmi amintește de modul în care operatorii telegrafici din anii 1800 trebuiau să traducă intrările în cod Morse în mesaje semnificative – noi facem ceva similar, traducând apăsările tastelor în comenzi de joc.
Pentru a gestiona un eveniment trebuie să folosești metoda addEventListener() a ferestrei și să îi oferi doi parametri de intrare. Primul este numele evenimentului, de exemplu keyup. Al doilea este funcția care trebuie invocată ca rezultat al apariției evenimentului.
Iată un exemplu:
window.addEventListener('keyup', (evt) => {
// evt.key = reprezentarea sub formă de șir a tastei
if (evt.key === 'ArrowUp') {
// fă ceva
}
});Descompunerea a ceea ce se întâmplă aici:
- Ascultă evenimente de tastatură pe întreaga fereastră
- Captează obiectul de eveniment care conține informații despre tasta apăsată
- Verifică dacă tasta apăsată corespunde unei taste specifice (în acest caz, săgeata sus)
- Execută codul când condiția este îndeplinită
Pentru evenimentele tastaturii sunt două proprietăți ale evenimentului pe care le poți folosi pentru a vedea ce tastă a fost apăsată:
key- este o reprezentare ca șir a tastei apăsate, de exemplu'ArrowUp'keyCode- este o reprezentare numerică, de exemplu37, corespunde tasteiArrowLeft
✅ Manipularea evenimentelor tastaturii este utilă și în afara dezvoltării jocurilor. La ce alte scopuri te poți gândi pentru această tehnică?
sequenceDiagram
participant User
participant Browser
participant EventSystem
participant GameLogic
participant Hero
User->>Browser: Apasă tasta ArrowUp
Browser->>EventSystem: eveniment keydown
EventSystem->>EventSystem: preventDefault()
EventSystem->>GameLogic: emit('KEY_EVENT_UP')
GameLogic->>Hero: hero.y -= 5
Hero->>Hero: Actualizează poziția
Note over Browser,GameLogic: Fluxul evenimentelor previne comportamentele implicite ale browserului
Note over GameLogic,Hero: Modelul pub/sub permite o comunicare curată
Unele taste au comportamente implicite în browser care pot interfera cu jocul tău. Tastele săgeată derulează pagina iar bara de spațiu face sări – comportamente nedorite când cineva încearcă să piloteze nava spațială.
Putem preveni aceste comportamente implicite și lăsa jocul să gestioneze intrarea în schimb. Este similar cu modul în care primii programatori de computere trebuiau să suprascrie întreruperile sistemului pentru a crea comportamente personalizate – noi facem asta la nivel de browser. Iată cum:
const onKeyDown = function (e) {
console.log(e.keyCode);
switch (e.keyCode) {
case 37:
case 39:
case 38:
case 40: // Tastele săgeată
case 32:
e.preventDefault();
break; // Spațiu
default:
break; // nu bloca alte taste
}
};
window.addEventListener('keydown', onKeyDown);Înțelegerea acestui cod de prevenire:
- Verifică coduri de taste specifice care ar putea cauza comportamente nedorite ale browserului
- Previne comportamentul implicit al browserului pentru tastele săgeată și bara de spațiu
- Permite altor taste să funcționeze normal
- Folosește
e.preventDefault()pentru a opri comportamentul încorporat al browserului
Înțelegerea gestionării evenimentelor: Înainte de a trece la mișcarea automată, asigură-te că poți:
- ✅ Explica diferența dintre evenimentele
keydownșikeyup - ✅ Înțelege de ce prevenim comportamentele implicite ale browserului
- ✅ Descrie cum ascultătorii de evenimente conectează intrarea utilizatorului la logica jocului
- ✅ Identifica ce taste ar putea interfera cu controalele jocului
Test rapid de auto-verificare: Ce s-ar întâmpla dacă nu ai preveni comportamentul implicit pentru tastele săgeată? Răspuns: Browserul ar derula pagina, interferând cu mișcarea din joc
Arhitectura sistemului de evenimente: Acum înțelegi:
- Ascultarea la nivel de fereastră: Capturarea evenimentelor la nivelul browserului
- Proprietățile obiectului eveniment: șiruri
keyvs numerekeyCode - Prevenirea comportamentelor implicite: Oprirea comportamentelor nedorite ale browserului
- Logica condițională: Răspunsul la combinații specifice de taste
Acum să vorbim despre obiecte care se mișcă fără comanda jucătorului. Gândește-te la navele inamice care croiesc drum pe ecran, gloanțe care zboară în linii drepte sau nori care plutesc în fundal. Această mișcare autonomă face lumea jocului tău să pară vie chiar și când nimeni nu atinge comenzile.
Folosim temporizatoarele încorporate ale JavaScript pentru a actualiza pozițiile la intervale regulate. Acest concept este asemănător modului în care ceasurile cu pendul funcționează – un mecanism regulat care declanșează acțiuni repetate, la intervale de timp. Iată cât de simplu poate fi:
const id = setInterval(() => {
// Mută inamicul pe axa y
enemy.y += 10;
}, 100);Ce face acest cod de mișcare:
- Creează un temporizator care rulează la fiecare 100 milisecunde
- Actualizează coordonata y a inamicului cu 10 pixeli de fiecare dată
- Stochează ID-ul intervalului ca să-l putem opri apoi dacă e nevoie
- Muta inamicul în jos pe ecran în mod automat
Iată conceptul care leagă totul – bucla jocului. Dacă jocul tău ar fi un film, bucla jocului ar fi proiectoul de film, care afișează cadru după cadru atât de repede încât totul pare a se mișca fluid.
Fiecare joc are una dintre aceste bucle care rulează în fundal. Este o funcție care actualizează toate obiectele din joc, redesenează ecranul și repetă acest proces continuu. Ea ține evidența eroului tău, a tuturor inamicilor, a oricăror lasere care zboară – întreg starea jocului.
Acest concept îmi amintește de cum animatorii filmelor timpurii precum Walt Disney trebuiau să redeseneze cadrele personajelor pentru a crea iluzia mișcării. Facem același lucru, doar cu cod în loc de creioane.
Iată cum ar putea arăta o buclă tipică de joc, exprimată în cod:
flowchart TD
A["Începe Bucla Jocului"] --> B["Curăță Pânza"]
B --> C["Umple Fundalul"]
C --> D["Actualizează Obiectele Jocului"]
D --> E["Desenează Eroul"]
E --> F["Desenează Inamicii"]
F --> G["Desenează Elemente UI"]
G --> H["Așteaptă Următorul Cadru"]
H --> I{Jocul Rulează?}
I -->|Da| B
I -->|Nu| J["Încheie Jocul"]
subgraph "Controlul Ratei de Cadre"
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
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);Înțelegerea structurii buclei jocului:
- Curăță întreg canvas-ul pentru a elimina cadrul anterior
- Umple fundalul cu o culoare solidă
- Desenează toate obiectele jocului în pozițiile lor curente
- Repetă acest proces la fiecare 200 milisecunde pentru a crea o animație fluidă
- Gestionează viteza cadrelor controlând timpul intervalului
Acum vom adăuga mișcare scenei statice pe care ai construit-o anterior. Vom transforma o captură de ecran într-o experiență interactivă. Vom parcurge pas cu pas pentru a asigura că fiecare parte se construiește pe ce a fost pus înainte.
Ia codul de unde am rămas în lecția precedentă (sau începe cu codul din folderul Part II- starter dacă ai nevoie de un început nou).
Iată ce construim astăzi:
- Controale erou: Tastele săgeată vor pilota nava ta spațială pe ecran
- Mișcare inamic: Navele extraterestre vor începe avansul
Să începem să implementăm aceste funcționalități.
Găsește fișierele care ți-au fost create în sub-folderul your-work. Ar trebui să conțină următoarele:
-| assets
-| enemyShip.png
-| player.png
-| index.html
-| app.js
-| package.jsonPornești proiectul în folderul your-work tastând:
cd your-work
npm startCe face această comandă:
- Navighează către directorul proiectului tău
- Pornește un server HTTP la adresa
http://localhost:5000 - Servește fișierele jocului ca să le poți testa în browser
Comanda de mai sus va porni un server HTTP la adresa http://localhost:5000. Deschide un browser și introdu acea adresă, ar trebui să afișeze eroul și toți inamicii; nimic nu se mișcă – încă!
-
Adaugă obiecte dedicate pentru
heroșienemyșigame object, acestea ar trebui să aibă proprietățixșiy. (Amintește-ți partea despre Moștenire sau compoziție).SUGESTIE
game objectar trebui să fie cel cuxșiyși cu abilitatea de a se desena singur pe canvas.Sfaturi: Începe prin a adăuga o nouă clasă
GameObjectcu constructorul delimitat ca mai jos, apoi deseneaz-o pe canvas: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); } }
Înțelegerea acestei clase de bază:
- Definește proprietăți comune pe care le împart toate obiectele din joc (poziție, dimensiune, imagine)
- Include un semnalizator
deadpentru a urmări dacă obiectul trebuie eliminat - Oferă o metodă
draw()care redă obiectul pe canvas - Setează valori implicite pentru toate proprietățile pe care clasele copil le pot suprascrie
classDiagram
class GameObject {
+x: number
+y: number
+dead: boolean
+type: string
+width: number
+height: number
+img: Image
+draw(ctx)
}
class Hero {
+speed: number
+type: "Erou"
+width: 98
+height: 75
}
class Enemy {
+type: "Inamic"
+width: 98
+height: 50
+setInterval()
}
GameObject <|-- Hero
GameObject <|-- Enemy
class EventEmitter {
+listeners: obiect
+on(mesaj, ascultător)
+emit(mesaj, payload)
}
Acum, extinde această `GameObject` pentru a crea `Hero` și `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);
}
}
```
**Concepte cheie în aceste clase:**
- **Moștenește** de la `GameObject` folosind cuvântul cheie `extends`
- **Apelează** constructorul părinte cu `super(x, y)`
- **Setează** dimensiuni și proprietăți specifice fiecărui tip de obiect
- **Implementează** mișcare automată pentru inamici folosind `setInterval()`
-
Adaugă gestori de evenimente pentru taste pentru a manevra navigarea prin taste (mișcă eroul sus/jos/stânga/dreapta)
AMINTEȘTE-ȚI este un sistem cartezian, colțul din stânga sus este
0,0. De asemenea, amintește-ți să adaugi cod pentru a opri comportamentul implicitSfaturi: Creează funcția ta
onKeyDownși atașeaz-o la fereastră:const onKeyDown = function (e) { console.log(e.keyCode); // Adaugă codul din lecția de mai sus pentru a opri comportamentul implicit switch (e.keyCode) { case 37: case 39: case 38: case 40: // Tastele săgeți case 32: e.preventDefault(); break; // Spațiu default: break; // nu bloca alte taste } }; window.addEventListener("keydown", onKeyDown);
Ce face acest handler de eveniment:
- Ascultă pentru evenimente de tip keydown pe întreaga fereastră
- Înregistrează codul tastei pentru a te ajuta la depanare ce taste sunt apăsate
- Previne comportamentul implicit al browserului la tastele săgeată și bara de spațiu
- Permite altor taste să funcționeze normal
Verifică consola browserului tău în acest punct și urmărește cum sunt înregistrate apăsările de taste.
-
Implementează paternul Publish-Subscribe, acesta va păstra codul curat pe măsură ce parcurgi restul părților.
Paternul Publish-Subscribe ajută la organizarea codului prin separarea detectării evenimentelor de gestionarea lor. Aceasta face codul tău mai modular și mai ușor de întreținut.
Pentru această ultimă parte, poți:
-
Adaugă un ascultător de evenimente pe fereastră:
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); } });
Ce face acest sistem de evenimente:
- Detectează intrarea de la tastatură și o convertește în evenimente personalizate de joc
- Separă detectarea intrării de logica jocului
- Face ușor de schimbat controalele mai târziu fără a afecta codul jocului
- Permite ca mai multe sisteme să răspundă la aceeași intrare
-
flowchart TD
A["Intrare de la tastatură"] --> B["Ascultător eveniment fereastră"]
B --> C["Emitator de evenimente"]
C --> D["EVENIMENT_TASTĂ_SUS"]
C --> E["EVENIMENT_TASTĂ_JOS"]
C --> F["EVENIMENT_TASTĂ_STÂNGA"]
C --> G["EVENIMENT_TASTĂ_DREAPTA"]
D --> H["Mișcarea Eroului"]
D --> I["Sistem de sunet"]
D --> J["Efecte vizuale"]
E --> H
F --> H
G --> H
style A fill:#e1f5fe
style C fill:#e8f5e8
style H fill:#fff3e0
-
Creează o clasă EventEmitter pentru a publica și abona mesaje:
class EventEmitter { constructor() { this.listeners = {}; } on(message, listener) { if (!this.listeners[message]) { this.listeners[message] = []; } this.listeners[message].push(listener); }
-
Adaugă constante și configurează EventEmitter-ul:
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();
Înțelegerea setărilor:
- Definește constante de mesaje pentru a evita greșelile de tastare și pentru a face refactorizarea mai ușoară
- Declară variabile pentru imagini, contextul canvas-ului și starea jocului
- Creează un event emitter global pentru sistemul pub-sub
- Initializează un array pentru a ține toate obiectele jocului
-
Inițializează jocul
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; });
-
Configurează bucla jocului
Restructurează funcția
window.onloadpentru a inițializa jocul și a seta o buclă de joc la un interval potrivit. Vei adăuga și un fascicul laser: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); };
Înțelegerea configurării jocului:
- Așteaptă ca pagina să se încarce complet înainte de a începe
- Ia elementul canvas și contextul său de randare 2D
- Încarcă toate resursele de imagine asincron folosind
await - Pornește bucla jocului care rulează la intervale de 100ms (10 FPS)
- Șterge și redesenează întregul ecran la fiecare cadru
-
Adaugă cod pentru a mișca inamicii la un anumit interval
Restructurează funcția
createEnemies()pentru a crea inamicii și a-i împinge în noua clasă gameObjects: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); } } }
Ce face crearea inamicilor:
- Calculează pozițiile pentru a centra inamicii pe ecran
- Creează o grilă de inamici folosind bucle imbricate
- Atribuie imaginea inamicului fiecărui obiect inamic
- Adaugă fiecare inamic în array-ul global de obiecte de joc
și adaugă o funcție
createHero()pentru a face un proces similar pentru erou.function createHero() { hero = new Hero( canvas.width / 2 - 45, canvas.height - canvas.height / 4 ); hero.img = heroImg; gameObjects.push(hero); }
Ce face crearea eroului:
- Poziționează eroul în partea de jos, în centru pe ecran
- Atribuie imaginea eroului obiectului erou
- Adaugă eroul în array-ul de obiecte de joc pentru redare
și în final, adaugă o funcție
drawGameObjects()pentru a începe desenarea:function drawGameObjects(ctx) { gameObjects.forEach(go => go.draw(ctx)); }
Înțelegerea funcției de desenare:
- Parcurge toate obiectele de joc din array
- Apelează metoda
draw()pe fiecare obiect - Transmite contextul canvas pentru ca obiectele să se poată reda singure
Înțelegere completă a sistemului jocului: Verifică stăpânirea ta asupra întregii arhitecturi:
- ✅ Cum permite moștenirea ca Hero și Enemy să împartă proprietăți comune GameObject?
- ✅ De ce face pattern-ul pub/sub codul tău mai ușor de întreținut?
- ✅ Ce rol are bucla jocului în crearea unei animații fluide?
- ✅ Cum conectează event listener-ele intrarea utilizatorului la comportamentul obiectelor de joc?
Integrarea sistemului: Jocul tău demonstrează acum:
- Design orientat pe obiecte: Clase de bază cu moșteniri specializate
- Arhitectură bazată pe evenimente: Pattern pub/sub pentru cuplare slabă
- Cadru de animație: Buclă de joc cu actualizări consistente ale cadrelor
- Gestionare intrări: Evenimente de tastatură cu prevenirea comportamentului implicit
- Gestionare resurse: Încărcare imagini și redare sprite-uri
Pattern-uri profesionale: Ai implementat:
- Separarea responsabilităților: Intrări, logică și redare separate
- Polimorfism: Toate obiectele de joc împart interfață comună de desenare
- Transmiterea mesajelor: Comunicare curată între componente
- Gestionare resurse: Manipulare eficientă a sprite-urilor și animațiilor
Inamicii tăi ar trebui să înceapă să avanseze către nava ta erou! } }
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); }și în final, adaugă o funcție
drawGameObjects()pentru a începe desenarea:function drawGameObjects(ctx) { gameObjects.forEach(go => go.draw(ctx)); }
Inamicii tăi ar trebui să înceapă să avanseze către nava ta erou!
Iată o provocare care va îmbunătăți rafinamentul jocului tău: adăugarea limitelor și controalelor fluide. În prezent, eroul tău poate ieși de pe ecran, iar mișcarea poate părea sacadată.
Misiunea ta: Fă ca nava ta spațială să se simtă mai realistă implementând limite de ecran și o mișcare fluidă. Este similar cu modul în care sistemele de control al zborului NASA împiedică navele spațiale să depășească parametrii operaționali siguri.
Ce trebuie să construiești: Creează un sistem care să țină nava erou pe ecran și fă controalele să fie fluide. Când jucătorii țin apăsată o tastă săgeată, nava ar trebui să alunece continuu, nu să se miște prin pași discreți. Ia în considerare adăugarea unui feedback vizual când nava atinge limitele ecranului – poate un efect subtil pentru a indica marginea zonei de joc.
Află mai multe despre agent mode aici.
Organizarea codului devine din ce în ce mai importantă pe măsură ce proiectele cresc. Probabil ai observat că fișierul tău s-a aglomerat cu funcții, variabile și clase amestecate. Aceasta îmi amintește de cum inginerii care au organizat codul misiunii Apollo au trebuit să creeze sisteme clare și întreținute, la care mai multe echipe puteau lucra simultan.
Misiunea ta: Gândește ca un arhitect software. Cum ți-ai organiza codul astfel încât peste șase luni, tu (sau un coleg) să poată înțelege ce se întâmplă? Chiar dacă totul rămâne într-un fișier deocamdată, poți crea o organizare mai bună:
- Gruparea funcțiilor conexe cu antete clare de comentarii
- Separarea responsabilităților - păstrează logica jocului separată de redare
- Folosirea convențiilor consistente de denumire pentru variabile și funcții
- Crearea de module sau namespace-uri pentru organizarea diferitelor aspecte ale jocului
- Adăugarea de documentație care explică scopul fiecărei secțiuni majore
Întrebări de reflecție:
- Care părți din cod îți sunt cele mai greu de înțeles când te întorci la ele?
- Cum ai putea organiza codul pentru a face mai ușoară contribuția altora?
- Ce se întâmplă dacă vrei să adaugi noi funcționalități precum power-up-uri sau tipuri diferite de inamici?
Am construit totul de la zero, ceea ce e minunat pentru învățare, dar iată un mic secret – există niște framework-uri JavaScript uimitoare care pot gestiona mult din munca grea pentru tine. Odată ce te simți confortabil cu fundamentele parcurse, merită să explorezi ce e disponibil.
Gândește-te la framework-uri ca la o cutie de unelte bine aprovizionată în loc să faci fiecare unealtă manual. Ele pot rezolva multe dintre provocările organizării codului de care am vorbit, plus oferă funcții care ți-ar lua săptămâni să le construiești singur.
Lucruri demne de explorat:
- Cum organizează motoarele de jocuri codul – vei fi uimit de pattern-urile inteligente pe care le folosesc
- Trucuri de performanță pentru a face jocurile pe canvas să ruleze foarte fluent
- Funcționalități moderne JavaScript care pot face codul tău mai curat și întreținut
- Abordări diferite pentru gestionarea obiectelor de joc și relațiile lor
timeline
title Progresul Învățării Animației și Interacțiunii în Jocuri
section Fundamentele Mișcării (20 de minute)
Principii de Animație: Animație bazată pe cadre
: Actualizări de poziție
: Sisteme de coordonate
: Mișcare fluidă
section Sisteme de Evenimente (25 de minute)
Input Utilizator: Gestionarea evenimentelor de la tastatură
: Prevenirea comportamentului implicit
: Proprietăți ale obiectului de eveniment
: Ascultare la nivel de fereastră
section Arhitectura Jocului (30 de minute)
Proiectarea Obiectelor: Modele de moștenire
: Crearea clasei de bază
: Comportamente specializate
: Interfețe polimorfe
section Modele de Comunicare (35 de minute)
Implementarea Pub/Sub: Emisii de evenimente
: Constante de mesaje
: Cuplaj redus
: Integrare de sistem
section Stăpânirea Bucla Jocului (40 de minute)
Sisteme în Timp Real: Controlul ratei cadrelor
: Ciclu actualizare/render
: Gestionarea stării
: Optimizarea performanței
section Tehnici Avansate (45 de minute)
Funcții Profesionale: Detectarea coliziunilor
: Simularea fizicii
: Automate de stare
: Sisteme de componente
section Concepte Ale Motorului de Joc (1 săptămână)
Înțelegerea Framework-ului: Sisteme entitate-componentă
: Grafice de scenă
: Pipeline-uri de asset-uri
: Profilarea performanței
section Abilități de Producție (1 lună)
Dezvoltare Profesională: Organizarea codului
: Colaborare în echipă
: Strategii de testare
: Optimizarea implementării
După finalizarea acestei lecții, ai stăpânit acum:
- Principii de animație: Mișcare bazată pe cadre și tranziții fluide
- Programare bazată pe evenimente: Gestionarea input-ului de tastatură cu management corect al evenimentelor
- Design orientat pe obiecte: Ierarhii de moștenire și interfețe polimorfice
- Pattern-uri de comunicare: Arhitectură pub/sub pentru un cod ușor de întreținut
- Arhitectura buclei jocului: Ciclu de actualizare și randare în timp real
- Sisteme de input: Maparea controalelor utilizatorului cu prevenirea comportamentului implicit
- Gestionarea resurselor: Încărcarea sprite-urilor și tehnici eficiente de randare
- Deschide consola browser-ului și încearcă
addEventListener('keydown', console.log)pentru a vedea evenimente de tastatură - Creează un element div simplu și mută-l folosind tastele săgeată
- Experimentează cu
setIntervalpentru a crea mișcare continuă - Încearcă să previi comportamentul implicit cu
event.preventDefault()
- Finalizează quiz-ul post-lectură și înțelege programarea bazată pe evenimente
- Construiește nava erou cu mișcare completă la tastatură
- Implementează modele fluide de mișcare pentru inamici
- Adaugă limite pentru a preveni ieșirea obiectelor de pe ecran
- Creează detecție de coliziune de bază între obiectele jocului
- Finalizează jocul complet spațial cu mișcări și interacțiuni rafinate
- Adaugă modele avansate de mișcare: curbe, accelerare și fizică
- Implementează tranziții fluide și funcții easing
- Creează efecte de particule și sisteme de feedback vizual
- Optimizează performanța jocului pentru rulare fluentă la 60fps
- Adaugă controale tactile pentru mobil și design responsive
- Construiește aplicații interactive complexe cu sisteme avansate de animație
- Învață biblioteci de animație precum GSAP sau creează-ți propriul motor de animație
- Contribuie la proiecte opensource de dezvoltare jocuri și animație
- Stăpânește optimizarea performanței pentru aplicații grafice intensive
- Creează conținut educațional despre dezvoltarea jocurilor și animație
- Construiește un portofoliu demonstrativ pentru abilități avansate de programare interactivă
Aplicații în lumea reală: Abilitățile tale de animație în jocuri se aplică direct la:
- Aplicații web interactive: Dashboard-uri dinamice și interfețe în timp real
- Vizualizare de date: Grafice animate și grafică interactivă
- Software educațional: Simulări interactive și instrumente de învățare
- Dezvoltare mobilă: Jocuri cu control tactil și gesturi
- Aplicații desktop: Aplicații Electron cu animații fluide
- Animații web: Biblioteci CSS și JavaScript pentru animații
Competențe profesionale dobândite: Acum poți:
- Proiecta sisteme bazate pe evenimente care se scalează cu complexitatea
- Implementa animații fluide folosind principii matematice
- Depana sisteme complexe de interacțiune cu unelte de dezvoltare browser
- Optimiza performanța jocului pe diverse dispozitive și browsere
- Concepe structuri de cod întreținute folosind pattern-uri dovedite
Concepte de dezvoltare joc stăpânite:
- Gestionarea ratei de cadre: Înțelegerea FPS și controlul temporizării
- Gestionarea input-ului: Sisteme de tastatură și evenimente cross-platform
- Ciclul de viață al obiectelor: Modele de creare, actualizare și distrugere
- Sincronizarea stărilor: Menținerea consistenței stării jocului între cadre
- Arhitectura evenimentelor: Comunicare decuplată între sisteme de joc
Nivel următor: Ești gata să adaugi detecție coliziuni, sisteme de punctaj, efecte sonore sau să explorezi framework-uri moderne de jocuri ca Phaser sau Three.js!
🌟 Realizare deblocată: Ai construit un sistem complet interactiv de joc cu pattern-uri profesionale de arhitectură!
Declinare de responsabilitate: Acest document a fost tradus folosind serviciul de traducere AI Co-op Translator. Deși ne străduim pentru acuratețe, vă rugăm să rețineți că traducerile automate pot conține erori sau inexactități. Documentul original în limba sa nativă trebuie considerat sursa autorizată. Pentru informații critice, se recomandă traducerea profesională realizată de un specialist uman. Nu ne asumăm responsabilitatea pentru orice neînțelegeri sau interpretări greșite care pot apărea în urma utilizării acestei traduceri.