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/lt/6-space-game/3-moving-elements-around
localizeflow[bot] 29493713ca
chore(i18n): sync translations with latest source changes (chunk 1/1, 291 changes)
7 months ago
..
README.md chore(i18n): sync translations with latest source changes (chunk 1/1, 291 changes) 7 months ago
assignment.md chore(i18n): sync translations with latest source changes (chunk 1/1, 291 changes) 7 months ago

README.md

Sukurkite kosminį žaidimą 3 dalis: Pridedame judėjimą

journey
    title Jūsų žaidimo animacijos kelionė
    section Judesio pagrindai
      Suprasti judesio principus: 3: Student
      Išmokti koordinatų atnaujinimus: 4: Student
      Įgyvendinti pagrindinį judėjimą: 4: Student
    section Žaidėjo valdikliai
      Tvarkyti klaviatūros įvykius: 4: Student
      Užkirsti kelią numatytiems veiksmams: 5: Student
      Kurti reaguojančius valdiklius: 5: Student
    section Žaidimo sistemos
      Kurti žaidimo ciklą: 5: Student
      Valdyti objektų gyvavimo ciklą: 5: Student
      Įgyvendinti pub/sub modelį: 5: Student

Pagalvokite apie savo mėgstamus žaidimus kas juos daro patrauklius, tai ne tik graži grafika, bet ir tai, kaip viskas juda ir reaguoja į jūsų veiksmus. Šiuo metu jūsų kosminis žaidimas tarsi gražus paveikslas, bet mes ruošiamės pridėti judėjimą, kuris suteiks jam gyvybės.

Kai NASA inžinieriai programavo Apollo misijų orientacijos kompiuterį, jie susidūrė su panašia problema: kaip priversti kosminį laivą reaguoti į piloto komandą ir tuo pačiu automatiškai išlaikyti kursų korekcijas? Principai, kuriuos šiandien išmoksime, atspindi tuos pačius konceptus žaidėjo valdomo judėjimo ir automatinio sistemos elgesio valdymą.

Šiame pamokoje sužinosite, kaip priversti erdvėlaivius slysti ekranu, reaguoti į žaidėjo komandas ir sukurti sklandžius judėjimo modelius. Viską suskaidysime į lengvai suprantamus konceptus, kurie natūraliai remiasi vienas kitu.

Pamokos pabaigoje žaidėjai skraidys savo herojų laivu po ekraną, o priešiški laivai patruliuos viršuje. Dar svarbiau, suprasite pagrindinius principus, kurie valdo žaidimų judėjimo sistemas.

mindmap
  root((Žaidimo animacija))
    Movement Types
      Player Controlled [Žaidėjo valdomi]
      Automatic Motion [Automatinis judėjimas]
      Physics Based [Fizika pagrįsti]
      Scripted Paths [Scenarijumi nustatytos trajektorijos]
    Event Handling
      Keyboard Input [Klaviatūros įvestis]
      Mouse Events [Pelės įvykiai]
      Touch Controls [Jutiklinio valdymo elementai]
      Default Prevention [Numatytųjų veiksmų stabdymas]
    Game Loop
      Update Logic [Logikos atnaujinimas]
      Render Frame [Kadro atvaizdavimas]
      Clear Canvas [Drobelės išvalymas]
      Frame Rate Control [Kadro dažnio kontrolė]
    Object Management
      Position Updates [Pozicijos atnaujinimai]
      Collision Detection [Susidūrimų aptikimas]
      Lifecycle Management [Gyvavimo ciklo valdymas]
      State Tracking [Būsenos sekimas]
    Communication
      Pub/Sub Pattern [Pub/Sub modelis]
      Event Emitters [Įvykių skleidėjai]
      Message Passing [Žinučių perdavimas]
      Loose Coupling [Silpnas sujungimas]

Įvadinis testas prieš paskaitą

Prieš paskaitą testas

Supratimas apie žaidimo judėjimą

Žaidimai atgyja, kai pradeda judėti objektai, ir yra iš esmės du tokių judėjimų tipai:

  • Žaidėjo valdoma judėjimas: Kai paspaudžiate klavišą arba spustelėjate pelę, kažkas juda. Tai tiesioginis ryšys tarp jūsų ir žaidimo pasaulio.
  • Automatinis judėjimas: Kai pats žaidimas nusprendžia ką nors judinti pavyzdžiui, tie priešų laivai, kurie turi patruliuoti ekranu, nesvarbu, ar jūs ką nors darote, ar ne.

Objektų judėjimas kompiuterio ekrane yra paprastesnis, nei galite pagalvoti. Prisiminkite tas x ir y koordinates iš matematikos pamokų? Būtent su tuo čia dirbame. Kai Galilėjus 1610 m. stebėjo Jupiterio palydovus, jis iš esmės darė tą patį braižė pozicijas laikui bėgant, norėdamas suprasti judėjimo modelius.

Judėjimas ekrane yra tarsi animacijos knygelė reikia atlikti tris paprastus veiksmus:

flowchart LR
    A["Kadras N"] --> B["Atnaujinti pozicijas"]
    B --> C["Išvalyti drobę"]
    C --> D["Nupiešti objektus"]
    D --> E["Kadras N+1"]
    E --> F{Tęsti?}
    F -->|Taip| B
    F -->|Ne| G["Žaidimas baigtas"]
    
    subgraph "Animacijos ciklas"
        H["1. Apskaičiuoti naujas pozicijas"]
        I["2. Ištrinti ankstesnį kadrą"]
        J["3. Atvaizduoti naują kadrą"]
    end
    
    style B fill:#e1f5fe
    style C fill:#ffebee
    style D fill:#e8f5e8
  1. Atnaujinti poziciją Pakeisti, kur objektas turėtų būti (galbūt perkelti jį 5 pikseliais į dešinę)
  2. Ištrinti seną kadrą Išvalyti ekraną, kad nematytumėte vaiduoklių takų visur
  3. Nupiešti naują kadrą Padėti objektą naujoje vietoje

Atlikus tai pakankamai greitai, štai gaunate sklandų judėjimą, kuris žaidėjams atrodo natūralus.

Štai kaip tai gali atrodyti kode:

// Nustatyti herojaus vietą
hero.x += 5;
// Išvalyti stačiakampį, kuriame yra herojus
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Perpiešti žaidimo foną ir herojų
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = "black";
ctx.drawImage(heroImg, hero.x, hero.y);

Štai ką daro šis kodas:

  • Atnaujina herojaus x koordinatę 5 pikseliais, kad jis judėtų horizontaliai
  • Išvalo visą drobės plotą, kad pašalintų ankstesnį kadrą
  • Užpildo drobę juodu fonu
  • Nupiešia herojaus paveikslėlį naujoje vietoje

Ar galite pagalvoti, kodėl per daug dažnas herojaus perkūrimas kas sekundę gali sumažinti našumą? Sužinokite apie alternatyvas šiam modeliui.

Klaviatūros įvykių valdymas

Čia mes sujungiame žaidėjo įvestį su žaidimo veiksmais. Kai kas nors paspaudžia tarpą, kad paleistų lazerį, arba spaudžia rodyklių klavišus, kad išvengtų asteroido, žaidimas turi aptikti ir sureaguoti į tą įvestį.

Klaviatūros įvykiai vyksta lango lygiu, tai reiškia, kad visas naršyklės langas klausosi tų klavišų paspaudimų. Pelės spragtelėjimai, kita vertus, gali būti susieti su tam tikrais elementais (pvz., paspaudimu ant mygtuko). Mūsų kosminiame žaidime dėmesį skirsime klaviatūros valdymui, nes tai suteikia klasikinį arkadinių žaidimų pojūtį.

Tai primena kaip XIX a. telegrrafo operatoriai turėjo išversti morzės kodą į prasmingas žinutes mes darome kažką panašaus, verčiame klavišų paspaudimus į žaidimo komandas.

Norint valdyti įvykį, reikia naudoti lango addEventListener() metodą ir jam pateikti du parametrus. Pirmasis parametras yra įvykio pavadinimas, pavyzdžiui, keyup. Antras parametras yra funkcija, kuri turi būti iškviečiama įvykio metu.

Štai pavyzdys:

window.addEventListener('keyup', (evt) => {
  // evt.key = raktas kaip eilutės atvaizdas
  if (evt.key === 'ArrowUp') {
    // daryti kažką
  }
});

Išskaidymas, kas čia vyksta:

  • Klauso klaviatūros įvykių visame lange
  • Gauna įvykio objektą, kuriame yra informacija apie paspaustą klavišą
  • Tikrina ar paspaustas klavišas atitinka konkretų klavišą (šiuo atveju rodyklę į viršų)
  • Vykdo kodą, kai sąlyga įvykdoma

Klavišų įvykiams yra du savybių būdai sužinoti, kuris klavišas buvo paspaustas:

  • key - tai klavišo pavadinimo eilutė, pvz., 'ArrowUp'
  • keyCode - tai skaičius, pvz., 37, reiškiantis ArrowLeft

Klavišų įvykių valdymas yra naudingas ne tik žaidimų kūrimui. Kokius kitus panaudojimo būdus galite įsivaizduoti šiai technikai?

sequenceDiagram
    participant User
    participant Browser
    participant EventSystem
    participant GameLogic
    participant Hero
    
    User->>Browser: Paspaudžia rodyklės aukštyn klavišą
    Browser->>EventSystem: keydown įvykis
    EventSystem->>EventSystem: preventDefault()
    EventSystem->>GameLogic: emit('KEY_EVENT_UP')
    GameLogic->>Hero: hero.y -= 5
    Hero->>Hero: Atnaujinti poziciją
    
    Note over Browser,GameLogic: Įvykio srautas užkerta kelią naršyklės standartams
    Note over GameLogic,Hero: Pub/sub modelis leidžia sklandų bendravimą

Specialūs klavišai: įspėjimas!

Kai kurie klavišai turi naršyklės numatytus veiksmus, kurie gali trukdyti jūsų žaidimui. Rodyklių klavišai leidžia puslapiui slinkti, o tarpo klavišas nuskrolina žemyn tokio elgesio nenorite, kai kažkas valdo kosminį laivą.

Galime užkirsti kelią šiems numatytiems veiksmams ir leisti žaidimui pačiam valdyti įvestį. Tai panašu į tai, kaip ankstyvieji programuotojai turėjo perrašyti sistemos pertraukimus, kad sukurtų pritaikytą elgesį mes tai darome naršyklės lygiu. Štai kaip:

const onKeyDown = function (e) {
  console.log(e.keyCode);
  switch (e.keyCode) {
    case 37:
    case 39:
    case 38:
    case 40: // Rodyklės klavišai
    case 32:
      e.preventDefault();
      break; // Tarpas
    default:
      break; // neblokuoti kitų klavišų
  }
};

window.addEventListener('keydown', onKeyDown);

Supratimas apie šią prevencijos kodo dalį:

  • Tikrina konkrečius klavišų kodus, kurie gali sukelti nepageidaujamą naršyklės elgesį
  • Užkerta kelią numatytam naršyklės veiksmui rodyklių klavišams ir tarpui
  • Leidžia kitus klavišus naudoti kaip įprasta
  • Naudoja e.preventDefault(), kad sustabdytų naršyklės numatytą elgesį

🔄 Pedagoginis tarpinis patikrinimas

Įvykių valdymo supratimas: Prieš pereinant prie automatinio judėjimo, įsitikinkite, kad galite:

  • Paaiškinti skirtumą tarp keydown ir keyup įvykių
  • Suprasti, kodėl užkertame kelią naršyklės numatytiems veiksmams
  • Apibūdinti, kaip įvykių klausytojai jungia vartotojo įvestį su žaidimo logika
  • Nustatyti, kurie klavišai gali trukdyti žaidimo valdymui

Greitas savitestavimas: Kas nutiktų, jei neužkertate kelio numatytiems veiksmams rodyklių klavišams? Atsakymas: Naršyklė slinktų puslapį, trukdydama žaidimo judėjimui

Įvykių sistemos architektūra: Dabar suprantate:

  • Langų lygio klausymą: įvykių gaudymą naršyklės lygiu
  • Įvykio objekto savybes: key eilutės ir keyCode skaičiai
  • Numatyto veikimo prevenciją: nepageidaujamų naršyklės veiksmų sustabdymą
  • Salyginę logiką: reakciją į specifinius klavišų derinius

Žaidimo sukeliamas judėjimas

Dabar aptarkime objektus, kurie juda be žaidėjo įvesties. Pagalvokite apie priešų laivus, kurie plaukioja ekranu, kulkas, skrendančias tiesiomis linijomis, arba debesys, dreifuoja fone. Šis autonominis judėjimas daro žaidimo pasaulį gyvą net kai niekas nelies valdiklių.

Naudojame JavaScript įmontuotus laikmačius, kad reguliariai atnaujintume pozicijas. Ši koncepcija panaši į svyravimo laikrodžius reguliari sistema, kuri sukelia nuoseklius, laiku paskirstytus veiksmus. Štai kaip paprastai tai gali atrodyti:

const id = setInterval(() => {
  // Perkelkite priešą y ašyje
  enemy.y += 10;
}, 100);

Štai ką daro šis judėjimo kodas:

  • Sukuria laikmatį, kuris vyksta kas 100 milisekundžių
  • Atnaujina priešo y koordinatę 10 pikselių kiekvieną kartą
  • Išsaugo intervalo ID, kad vėliau galėtume jį sustabdyti, jei reikės
  • Automatiškai perkelia priešą žemyn ekrane

Žaidimo ciklas

Štai konceptas, kuris sujungia viską žaidimo ciklas. Jei jūsų žaidimas būtų filmas, žaidimo ciklas būtų kino projektorius, rodomas kadrą po kadro taip greitai, kad viskas atrodo sklandžiai judančiai.

Kiekvienas žaidimas turi tokį ciklą, veikiančią fone. Tai funkcija, kuri atnaujina visus žaidimo objektus, perkrauna ekraną ir kartoja šį procesą nuolat. Ji prižiūri jūsų herojų, visus priešus, bet kokius skriejančius lazerius visą žaidimo būseną.

Šis konceptas primena, kaip ankstyvieji animatorių filmuotojai, tokie kaip Walt Disney, turėjo vėl ir vėl piešti personažus kadrą po kadro, kad sukurtų judėjimo iliuziją. Mes darome tą patį, tik su kodu vietoje pieštukų.

Štai kaip žaidimo ciklas dažniausiai gali atrodyti kode:

flowchart TD
    A["Pradėti žaidimo ciklą"] --> B["Išvalyti drobę"]
    B --> C["Užpildyti foną"]
    C --> D["Atnaujinti žaidimo objektus"]
    D --> E["Nupiešti herojų"]
    E --> F["Nupiešti priešus"]
    F --> G["Nupiešti sąsajos elementus"]
    G --> H["Laukti kito kadro"]
    H --> I{Žaidimas veikia?}
    I -->|Taip| B
    I -->|Ne| J["Baigti žaidimą"]
    
    subgraph "Kadrai per sekundę kontrolė"
        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);

Suprantame žaidimo ciklo struktūrą:

  • Išvalo visą drobę, kad pašalintų ankstesnį kadrą
  • Užpildo foną vientisa spalva
  • Nupiešia visus žaidimo objektus jų dabartinėse pozicijose
  • Kartoja šį procesą kas 200 milisekundžių, kad sukurtų sklandžią animaciją
  • Valdo kadrų dažnį reguliuodamas intervalų laiką

Toliau tęsiame kosminį žaidimą

Dabar pridėsime judėjimą prie statinės scenos, kurią sukūrėte ankstesnėje pamokoje. Paversime ekrano paveikslėlį interaktyvia patirtimi. Dirbsime žingsnis po žingsnio, kad kiekviena dalis natūraliai papildytų ankstesnę.

Pasiimkite kodą iš ten, kur sustojome ankstesnėje pamokoje (arba pradėkite nuo II dalies pradinio katalogo, jei norite pradėti nuo nulio).

Štai ką šiandien kursime:

  • Herojaus valdymas: rodyklių klavišais valdysite savo kosminį laivą po ekraną
  • Priešo judėjimas: tie ateivių laivai pradės savo judėjimą

Pradėkime įgyvendinti šias funkcijas.

Rekomenduojami žingsniai

Suraskite failus, kurie jums buvo paruošti your-work aplanke. Juose turėtų būti:

-| assets
  -| enemyShip.png
  -| player.png
-| index.html
-| app.js
-| package.json

Projektą pradėkite your-work kataloge įvykdydami:

cd your-work
npm start

Ši komanda daro:

  • Pereina į jūsų projekto katalogą
  • Paleidžia HTTP serverį adresu http://localhost:5000
  • Pateikia jūsų žaidimo failus, kad galėtumėte juos testuoti naršyklėje

Tai paleis HTTP serverį adresu http://localhost:5000. Atidarykite naršyklę ir įveskite tą adresą, šiuo metu jis turėtų atvaizduoti herojų ir visus priešus; tačiau niekas dar nejuda!

Pridėkite kodą

  1. Sukurkite atskirus objektus hero, enemy ir game object, kurie turėtų turėti x ir y savybes. (Prisiminkite skyrių apie paveldėjimą ar kompoziciją).

    PATARIMAS game object turėtų būti tas, kuris turi x, y ir geba pats save nupiešti ant drobės.

    Patarimas: Pradėkite sukurti naują GameObject klasę su žemiau pateiktu konstruktoriaus aprašymu ir nupieškite ją drobėje:

    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);
      }
    }
    

    Supratimas apie pagrindinę klasę:

    • Apibrėžia bendras savybes, kurias dalijasi visi žaidimo objektai (pozicija, dydis, paveikslėlis)
    • Turi dead žymę, padedančią sekti, ar objektą reikia pašalinti
    • Pateikia draw() metodą, kuris nupiešia objektą ant drobės
    • Nustato numatytąsias visų savybių reikšmes, kurias gali perrašyti vaikinės klasės
classDiagram
    class GameObject {
        +x: number
        +y: number
        +dead: boolean
        +type: string
        +width: number
        +height: number
        +img: Image
        +draw(ctx)
    }
    
    class Hero {
        +speed: number
        +type: "Herojus"
        +width: 98
        +height: 75
    }
    
    class Enemy {
        +type: "Priešas"
        +width: 98
        +height: 50
        +setInterval()
    }
    
    GameObject <|-- Hero
    GameObject <|-- Enemy
    
    class EventEmitter {
        +listeners: objektas
        +on(žinutė, klausytojas)
        +emit(žinutė, duomenys)
    }
Dabar išplėskite `GameObject` ir sukurkite `Hero` ir `Enemy` klasės:

```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);
  }
}
```

**Svarbiausios idėjos šiose klasėse:**
- **Paveldi** iš `GameObject`, naudojant `extends` raktažodį
- **Kvies** tėvinį konstruktorių su `super(x, y)`
- **Nustato** specifinius dydžius ir savybes kiekvienam objektų tipui
- **Įgyvendina** automatinį judėjimą priešams, naudojant `setInterval()`
  1. Pridėkite klavišų įvykių valdymą, kad valdytumėte herojaus judėjimą aukštyn/žemyn/į kairę/į dešinę.

    ATKARTOTI: tai yra Dekartinis koordinatės sistema, viršutinis kairys kampas yra 0,0. Taip pat nepamirškite pridėti kodo, kuris sustabdo numatytą elgesį.

    Patarimas: Sukurkite onKeyDown funkciją ir prijunkite ją prie lango:

    const onKeyDown = function (e) {
      console.log(e.keyCode);
      // Pridėkite aukščiau esančio pamokos kodo, kad sustabdytumėte numatytąjį elgesį
      switch (e.keyCode) {
        case 37:
        case 39:
        case 38:
        case 40: // Rodyklių klavišai
        case 32:
          e.preventDefault();
          break; // Tarpas
        default:
          break; // neblokuoti kitų klavišų
      }
    };
    
    window.addEventListener("keydown", onKeyDown);
    

    Šis įvykio valdiklis daro:

    • Klauso klavišų nuspaudimų visame lange
    • Rašo į konsolę nuspausto klavišo kodą, kad galėtumėte sekti aktyvumą
    • Užkerta kelią numatytiems naršyklės veiksmams rodyklių klavišams ir tarpui
    • Leidžia naudoti kitus klavišus kaip įprasta

    Patikrinkite savo naršyklės konsolę šiame etape ir stebėkite registruojamus klavišų paspaudimus.

  2. Įgyvendinkite Pub sub modelį, tai padės išlaikyti jūsų kodą tvarkingą tolimesniuose žingsniuose.

    Publish-Subscribe modelis padeda organizuoti kodą, atskiriant įvykių aptikimą nuo jų apdorojimo. Tai daro jūsų kodą moduliariu ir lengviau prižiūrimu.

    Norėdami padaryti paskutinį žingsnį, galite:

    1. Pridėti įvykių klausytoją langui:

      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);
        }
      });
      

    Ši įvykių sistema daro:

    • Aptinka klaviatūros įvestį ir paverčia ją pritaikytais žaidimo įvykiais
    • Atskiria įvesties aptikimą nuo žaidimo logikos
    • Leidžia lengvai pakeisti valdymą vėliau nekeisdami žaidimo kodo
    • Suteikia galimybę kelioms sistemoms reaguoti į tą pačią įvestį
flowchart TD
    A["Klaviatūros Įvestis"] --> B["Langų Įvykių Stebėtojas"]
    B --> C["Įvykių Paskleidėjas"]
    C --> D["MYGTUKO_ĮVYKIS_AUKŠTYN"]
    C --> E["MYGTUKO_ĮVYKIS_ŽEMYN"]
    C --> F["MYGTUKO_ĮVYKIS_KAIRĖN"]
    C --> G["MYGTUKO_ĮVYKIS_DEŠINĖN"]
    
    D --> H["Herojaus Judėjimas"]
    D --> I["Garso Sistema"]
    D --> J["Vizualiniai Efektai"]
    
    E --> H
    F --> H
    G --> H
    
    style A fill:#e1f5fe
    style C fill:#e8f5e8
    style H fill:#fff3e0
  1. Sukurkite EventEmitter klasę, kad skelbtumėte ir užsiprenumeruotumėte žinutes:

    class EventEmitter {
      constructor() {
        this.listeners = {};
      }
    
      on(message, listener) {
        if (!this.listeners[message]) {
          this.listeners[message] = [];
        }
        this.listeners[message].push(listener);
      }
    
    
  2. Pridėkite konstantas ir sukonfigūruokite EventEmitter:

    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();
    

Supratimas apie šį konfigūravimą:

  • Apibrėžia žinučių konstantas, kad sumažintų klaidų ir palengvintų kodo keitimą
  • Deklaruoja kintamuosius paveikslėliams, drobės kontekstui ir žaidimo būsenai
  • Sukuria globalų įvykių emitentą pub-sub sistemai
  • Inicializuoja masyvą, kuriame saugomi visi žaidimo objektai
  1. Inicializuokite žaidimą

    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;
      });
    
    
  2. Nustatykite žaidimo ciklą

    Pertvarkykite funkciją window.onload, kad inicializuotumėte žaidimą ir nustatytumėte žaidimo ciklą tinkamu intervalu. Taip pat pridėsite lazerio spindulį:

    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);
    };
    

    Žaidimo nustatymo supratimas:

    • Laukia, kol puslapis visiškai užsikraus prieš pradedant
    • Gauk drobės elementą ir jo 2D atvaizdavimo kontekstą
    • Asinchroniškai įkelia visus paveikslėlių išteklius naudodamas await
    • Pradeda žaidimo ciklą, vykstantį kas 100ms (10 FPS)
    • Išvalo ir perpiešia visą ekraną kiekviename kadre
  3. Pridėkite kodą, kad priešai judėtų tam tikru intervalu

    Pertvarkykite funkciją createEnemies(), kad sukurti priešus ir įtraukti juos į naują gameObjects klasę:

    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);
        }
      }
    }
    

    Ką daro priešų kūrimas:

    • Apskaičiuoja pozicijas, kad priešai būtų centruoti ekrane
    • Sukuria priešų tinklelį su įdėtais ciklais
    • Priskiria priešo paveikslėlį kiekvienam priešo objektui
    • Prideda kiekvieną priešą į bendrą žaidimo objektų masyvą

    ir pridėkite funkciją createHero(), kad atliktumėte panašų procesą herojui.

    function createHero() {
      hero = new Hero(
        canvas.width / 2 - 45,
        canvas.height - canvas.height / 4
      );
      hero.img = heroImg;
      gameObjects.push(hero);
    }
    

    Ką daro herojaus kūrimas:

    • Pozicionuoja herojų ekrano apačioje centre
    • Priskiria herojaus paveikslėlį herojui
    • Prideda herojų į žaidimo objektų masyvą atvaizdavimui

    ir galiausiai pridėkite funkciją drawGameObjects(), kad pradėtumėte piešimą:

    function drawGameObjects(ctx) {
      gameObjects.forEach(go => go.draw(ctx));
    }
    

    Piešimo funkcijos supratimas:

    • Eina per visus žaidimo objektus masyve
    • Iškviečia kiekvieno objekto draw() metodą
    • Pateikia drobės kontekstą, kad objektai galėtų patys save nupiešti

    🔄 Pedagoginis patikrinimas

    Pilnas žaidimo sistemos supratimas: Patikrinkite savo visos architektūros žinias:

    • Kaip paveldėjimas leidžia Hero ir Enemy dalintis bendromis GameObject savybėmis?
    • Kodėl pub/sub modelis daro jūsų kodą lengviau prižiūrimą?
    • Koks žaidimo ciklo vaidmuo kuriant sklandžią animaciją?
    • Kaip įvykių klausytojai jungia naudotojo įvestį su žaidimo objektų elgsena?

    Sistemos integracija: Jūsų žaidimas dabar demonstruoja:

    • Objektinį dizainą: Bazinės klasės su specializuotu paveldėjimu
    • Įvykių varomą architektūrą: Pub/sub modelis dėl silpno įsitraukimo
    • Animacijos sistemą: Žaidimo ciklas su nuolatiniais kadrų atnaujinimais
    • Įvesties apdorojimą: Klaviatūros įvykiai su numatyto elgesio prevencija
    • Išteklų valdymą: Paveikslėlių įkėlimas ir sprites atvaizdavimas

    Profesionalūs modeliai: Jūs įgyvendinote:

    • Rūšių atskyrimą: Įvestis, logika ir atvaizdavimas atskirti
    • Polimorfizmą: Visi žaidimo objektai dalinasi bendru piešimo interfeisu
    • Pranešimų siuntimą: Švari komunikacija tarp komponentų
    • Išteklų valdymą: Efektyvus sprite'ų ir animacijų tvarkymas

    Jūsų priešai turėtų pradėti judėti jūsų herojaus kosminio laivo link! } }

    
    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);
    }
    

    ir galiausiai pridėkite funkciją drawGameObjects(), kad pradėtumėte piešimą:

    function drawGameObjects(ctx) {
      gameObjects.forEach(go => go.draw(ctx));
    }
    

    Jūsų priešai turėtų pradėti judėti jūsų herojaus kosminio laivo link!


GitHub Copilot agento iššūkis 🚀

Štai iššūkis, kuris pagerins jūsų žaidimo kokybę: pridėti ribas ir sklandų valdymą. Šiuo metu jūsų herojus gali išeiti už ekrano ribų, o judėjimas gali atrodyti nelygus.

Jūsų užduotis: Padarykite, kad jūsų kosminis laivas būtų realistiškesnis įgyvendindami ekrano ribas ir sklandų judėjimą. Tai panašu į tai, kaip NASA skrydžio valdymo sistemos neleidžia kosminiams laivams viršyti saugių eksploatacijos parametrų.

Ką kurti: Sukurkite sistemą, kuri palaiko herojaus kosminį laivą ekrano ribose ir suteikia sklandų valdymą. Kai žaidėjas laiko nuspaustą rodyklių klavišą, laivas turėtų slysti nuolat, o ne judėti žingsniais. Apsvarstykite vizualinį efektą, kai laivas pasiekia ekrano ribas gal subtili indikacija play zonos krašte.

Daugiau apie agentų režimą sužinokite čia.

🚀 Iššūkis

Kodo organizacija tampa vis svarbesnė didėjant projektų apimtims. Gal pastebėjote, kad jūsų failas pildosi funkcijomis, kintamaisiais ir klasėmis. Tai primena, kaip inžinieriai, dirbę ties Apollo misija, turėjo sukurti aiškias, prižiūrimas sistemas, ant kurių galėtų dirbti keli kolektyvai vienu metu.

Jūsų užduotis: Mąstykite kaip programinės įrangos architektas. Kaip suorganizuotumėte savo kodą, kad po šešių mėnesių jūs ar jūsų komandos narys galėtumėte suprasti, kas vyksta? Net jei kol kas viskas būtų viename faile, galite sukurti geresnę organizaciją:

  • Grupuokite susijusias funkcijas aiškiai pažymėdami komentarais
  • Atskirkite atsakomybes žaidimo logiką atskirkite nuo atvaizdavimo
  • Naudokite nuoseklias vardų konvencijas kintamiesiems ir funkcijoms
  • Sukurkite modulius arba vardų erdves skirtingoms žaidimo dalims organizuoti
  • Pridėkite dokumentaciją, paaiškinančią kiekvienos didelės dalies paskirtį

Refleksijos klausimai:

  • Kokios kodo dalys sunkiausiai suprantamos, kai sugrįžtate?
  • Kaip galėtumėte organizuoti kodą, kad būtų lengviau kitiems prisidėti?
  • Kas nutiktų, jei norėtumėte pridėti naujų funkcijų kaip galios ženklus ar skirtingų priešų tipus?

Po paskaitos testas

Po paskaitos testas

Peržiūra ir savarankiškas mokymasis

Mes viską konstruojame nuo nulio, kas puiku mokantis, bet štai mažytė paslaptis yra nuostabių JavaScript sistemų, kurios gali daug ką palengvinti už jus. Kai įgysite pasitikėjimo pagrindais, verta pažvelgti, kas prieinama.

Sistemos yra kaip gerai aprūpintas įrankių dėžė, o ne rankų darbo kiekvienas įrankis. Jos gali išspręsti daugelį kodo organizacijos iššūkių, apie kuriuos kalbėjome, ir pasiūlyti funkcijas, kurių sukūrimas užtruktų savaites.

Verta išbandyti:

  • Kaip žaidimų varikliai organizuoja kodą būsite sužavėti jų sumaniais modeliais
  • Perfomanso triukai sklandžiam drobės žaidimui
  • Modernios JavaScript savybės, kurios pagyvina ir palengvina jūsų kodą
  • Skirtingi požiūriai į žaidimo objektų ir jų sąveikų valdymą

🎯 Jūsų žaidimo animacijos meistriškumo tvarkaraštis

timeline
    title Žaidimų animacijos ir sąveikos mokymosi eiga
    
    section Judesio pagrindai (20 minučių)
        Animacijos principai: Kadru pagrįsta animacija
                            : Padėties atnaujinimai
                            : Koordinačių sistemos
                            : Sklandus judėjimas
        
    section Įvykių sistemos (25 minutės)
        Vartotojo įvestis: Klaviatūros įvykių tvarkymas
                   : Numatytojo elgesio prevencija
                   : Įvykių objekto savybės
                   : Langų lygiu klausymas
        
    section Žaidimo architektūra (30 minučių)
        Objektų dizainas: Paveldėjimo modeliai
                     : Pagrindinės klasės kūrimas
                     : Specializuoti elgesiai
                     : Polimorfiniai sąsajos
        
    section Komunikacijos modeliai (35 minučių)
        Pub/Sub įgyvendinimas: Įvykių išsiuntėjai
                              : Žinučių konstantos
                              : Silpnas susiejimas
                              : Sistemos integracija
        
    section Žaidimo ciklo valdymas (40 minučių)
        Realaus laiko sistemos: Kadrų dažnio valdymas
                         : Atnaujinimo/atvaizdavimo ciklas
                         : Būsenos valdymas
                         : Veikimo optimizavimas
        
    section Pažangios technikos (45 minučių)
        Profesionalios funkcijos: Susidūrimų aptikimas
                             : Fizikos simuliacija
                             : Būsenų mašinos
                             : Komponentų sistemos
        
    section Žaidimų variklio koncepcijos (1 savaitė)
        Sistemos supratimas: Entity-komponentų sistemos
                               : Scenos grafikai
                               : Išteklių srautai
                               : Veikimo profilavimas
        
    section Produkcijos įgūdžiai (1 mėnuo)
        Profesionalus tobulėjimas: Kodo organizavimas
                                : Komandos bendradarbiavimas
                                : Testavimo strategijos
                                : Diegimo optimizavimas

🛠️ Jūsų žaidimo kūrimo įrankių santrauka

Po šio pamokymo jūs įgijote:

  • Animacijos principai: Kadrinių judėjimo ir sklandžių perėjimų pagrindai
  • Įvykių valdymas: Klaviatūros įvesties apdorojimas su teisingu valdymu
  • Objektinis dizainas: Paveldėjimo hierarchijos ir polimorfiniai interfeisai
  • Komunikacijos modeliai: Pub/sub architektūra prižiūrimam kodui
  • Žaidimo ciklo architektūra: Realio laiko atnaujinimas ir piešimas
  • Įvesties sistemos: Vartotojo valdymas su numatyto elgesio prevencija
  • Išteklų valdymas: Sprite'ų įkėlimas ir efektyvus atvaizdavimas

Ką galite padaryti per artimiausias 5 minutes

  • Atidarykite naršyklės konsolę ir pabandykite addEventListener('keydown', console.log), kad pamatytumėte klaviatūros įvykius
  • Sukurkite paprastą div elementą ir perkelkite jį naudodami rodyklių klavišus
  • Eksperimentuokite su setInterval nuolatiniam judėjimui sukurti
  • Pamėginkite užkirsti kelią numatytajam veiksmui su event.preventDefault()

🎯 Ką galite pasiekti šią valandą

  • Užbaikite po paskaitos testą ir supraskite įvykių varomą programavimą
  • Sukurkite judantį herojų kosminį laivą su pilnu klaviatūros valdymu
  • Įgyvendinkite sklandžius priešų judėjimo modelius
  • Pridėkite ribas, kad žaidimo objektai neišeitų už ekrano
  • Sukurkite pagrindinę kolizijų aptikimą tarp žaidimo objektų

📅 Jūsų savaitės trukmės animacijos kelionė

  • Užbaikite visą kosmoso žaidimą su apgalvotu judėjimu ir sąveikomis
  • Pridėkite pažangius judėjimo modelius: kreives, pagreitį ir fizikos efektus
  • Implmentuokite sklandžius perėjimus ir lengvinimo funkcijas
  • Sukurkite dalelių efektus ir vizualinės grįžtamosios informacijos sistemas
  • Optimizuokite žaidimo veikimą 60 FPS sklandumui pasiekti
  • Pridėkite mobiliojo jutiklinio valdymo ir adaptaciją dizainui

🌟 Jūsų mėnesio trukmės interaktyvus vystymasis

  • Kurkite sudėtingas interaktyvias programas su pažangiomis animacijos sistemomis
  • Išmokite animacijos bibliotekas kaip GSAP arba sukurkite savo animacijos variklį
  • Prisidėkite prie atviro kodo žaidimų kūrimo ir animacijos projektų
  • Tobulinkite veikimą grafikos intensyvioms programoms
  • Kurkite edukacinį turinį apie žaidimų kūrimą ir animaciją
  • Sukurkite portfelį, demonstruojantį pažangias interaktyvaus programavimo įgūdžius

Realaus pasaulio panaudojimas: Jūsų žaidimo animacijos įgūdžiai tiesiogiai pritaikomi:

  • Interaktyvios interneto programos: Dinamiškos informacijos panelės ir realaus laiko sąsajos
  • Duomenų vizualizacija: Animacinės diagramos ir interaktyvi grafika
  • Edukacinė programinė įranga: Interaktyvios simuliacijos ir mokymosi įrankiai
  • Mobilios aplikacijos: Jutikliniai žaidimai ir gestų valdymas
  • Darbalaukio programos: Electron programos su sklandžiomis animacijomis
  • Interneto animacijos: CSS ir JavaScript animacijos bibliotekos

Įgyti profesiniai įgūdžiai: Dabar galite:

  • Architektūruoti įvykių valdymo sistemas, kurios plečiasi kartu su sudėtingumu
  • Įgyvendinti sklandžias animacijas taikant matematinius principus
  • Trikčių šalinimu sudėtingų sąveikų sistemose naudodami naršyklės kūrėjų įrankius
  • Optimizuoti žaidimų veikimą skirtingiems įrenginiams ir naršyklėms
  • Kurti prižiūrimą kodo struktūrą naudodami patvirtintus modelius

Įvaldytos žaidimų kūrimo koncepcijos:

  • Kadrijų dažnio valdymas: FPS ir laiko valdymo supratimas
  • Įvesties valdymas: Kryžminės platformos klaviatūros ir įvykių sistemų naudojimas
  • Objektų gyvavimo ciklas: Kūrimas, atnaujinimas ir naikinimas
  • Būsenos sinchronizavimas: Žaidimo būsenos nuoseklumas per kadrus
  • Įvykių architektūra: Atsietas komunikavimas tarp žaidimo sistemų

Kitas lygis: Jūs pasiruošę pridėti kolizijų aptikimą, taškų sistemą, garso efektus ar tyrinėti modernius žaidimų variklius kaip Phaser ar Three.js!

🌟 Pasiekimas atrakintas: Jūs sukūrėte pilną interaktyvią žaidimo sistemą su profesionaliais architektūros modeliais!

Užduotis

Komentuokite savo kodą


Atsakomybės apribojimas: Šis dokumentas buvo išverstas naudojant dirbtinio intelekto vertimo paslaugą Co-op Translator. Nors siekiame tikslumo, atkreipkite dėmesį, kad automatizuoti vertimai gali turėti klaidų ar netikslumų. Originalus dokumentas gimtąja kalba laikomas autoritetingu šaltiniu. Svarbiai informacijai rekomenduojamas profesionalus žmogaus vertimas. Mes neatsakome už bet kokius nesusipratimus ar klaidingus aiškinimus, kylantčius naudojantis šiuo vertimu.