Kuidas kodeerida oma protseduuriline lohekaardigeneraator juhusliku jalutuskäigu algoritmi abil

Tehnoloogia arenedes ja mängude sisu algoritmilisemaks genereerimisel ei ole keeruline ette kujutada, et luuakse igale mängijale ainulaadsete kogemustega elutruu simulatsioon.

Tehnoloogilised läbimurded, kannatlikkus ja viimistletud oskused saavad meid sinna juurde, kuid esimene samm on protseduurilise sisu genereerimise mõistmine.

Kuigi kaartide genereerimiseks on olemas palju väliseid lahendusi, õpetab see õpetus teid JavaScripti abil nullist oma kahemõõtmelise koopakaardigeneraatori valmistama.

Kahemõõtmelisi kaarditüüpe on palju ja neil kõigil on järgmised omadused:

1. Juurdepääsetavad ja ligipääsmatud alad (tunnelid ja seinad).

2. Ühendatud marsruudil, mida mängija saab navigeerida.

Selle õpetuse algoritm pärineb juhusliku jalutuskäigu algoritmist, mis on üks kaartide genereerimise lihtsamaid lahendusi.

Pärast seinakujulise ruudustikukaardi tegemist algab see algoritm kaardi juhuslikust kohast. Soovitud tunnelite arvu täitmiseks jätkub tunnelite tegemine ja juhuslike pöörete tegemine.

Demo nägemiseks avage allpool CodePeni projekt, klõpsake uue kaardi loomiseks kaardil ja muutke järgmisi väärtusi:

  1. Mõõdud: kaardi laius ja kõrgus.
  2. MaxTunnels: suurim arv pöördeid, mida algoritm kaardi koostamisel võib võtta.
  3. MaxLength: algoritm valib enne horisontaalse või vertikaalse pöörde tegemist iga tunneli suurima pikkuse.

Märkus: mida suurem on maxTurn mõõtmetega, seda tihedam on kaart. Mida suurem on maxLength mõõtmetega, seda tunnelilisem y välja näeb.

Järgnevalt vaatame läbi kaardi genereerimise algoritmi, et näha, kuidas see:

  1. Teeb kahemõõtmelise seinte kaardi
  2. Valib kaardil juhusliku lähtepunkti
  3. Kuigi tunnelite arv pole null
  4. Valib maksimaalse lubatud pikkuse hulgast juhusliku pikkuse
  5. Valib juhusliku suuna, kuhu pöörata (paremale, vasakule, üles, alla)
  6. Joonistab selles suunas tunneli, vältides samal ajal kaardi servi
  7. Vähendab tunnelite arvu ja kordab samasilmust
  8. Tagastab muudatustega kaardi

See ring jätkub, kuni tunnelite arv on null.

Algoritm koodis

Kuna kaart koosneb tunneli- ja seinaelementidest, võiksime seda kirjeldada nullidena ja kahemõõtmelises massiivis järgmistena:

kaart = [[1,1,1,1,0],
       [1,0,0,0,0],
       [1,0,1,1,1],
       [1,0,0,0,1],
       [1,1,1,0,1]]

Kuna iga lahter on kahemõõtmelises massiivis, pääseme selle väärtusele juurde, teades selle rida ja veerge, näiteks kaarti [rida] [veerg].

Enne algoritmi kirjutamist vajate abistajafunktsiooni, mis võtab märgiks ja mõõtmeks argumendid ning tagastab kahemõõtmelise massiivi.

createArray (arv, mõõtmed) {
    var massiiv = [];
    jaoks (var i = 0; i 

Juhusliku jalutuskäigu algoritmi rakendamiseks määrake kaardi mõõtmed (laius ja kõrgus), muutuja themaxTunnels ja muutuja themaxLength.

createMap () {
 las mõõtmed = 5,
 maxTunnels = 3,
 maksimaalne pikkus = 3;

Järgmisena tehke kahemõõtmeline massiiv, kasutades eelnevalt määratletud abistaja funktsiooni (kahemõõtmeline massiiv neist).

lase map = createArray (1, mõõtmed);

Esimese tunneli juhusliku lähtepunkti loomiseks seadke juhuslik veerg ja juhuslik rida.

lase currentRow = Math.floor (Math.random () * mõõtmed),
    currentColumn = Math.põrand (Math.random () * mõõtmed);

Diagonaalsete pöörde keerukuse vältimiseks peab algoritm täpsustama horisontaalse ja vertikaalse suuna. Iga lahter paikneb kahemõõtmelises massiivis ja seda oli võimalik tuvastada selle rea ja veeruga. Seetõttu võiks suunad määratleda lahutustena ja / või täiendustena veeru- ja reanumbrite järgi.

Näiteks lahtri [2] [2] ümber asuvasse lahtrisse minemiseks võiksite teha järgmisi toiminguid:

  • üles minemiseks lahutage 1 selle realt [1] [2]
  • alla minna, lisage selle reale 1 [3] [2]
  • paremale minemiseks lisage selle veergu 1 [2] [3]
  • vasakule minemiseks lahutage veerust 1 [2] [1]

Järgmine kaart illustreerib neid toiminguid:

Juhiste kuvamine kaardil.

Nüüd määrake suuna muutuja järgmisteks väärtusteks, mille hulgast algoritm valib enne iga tunneli loomist:

laske suunad = [[-1, 0], [1, 0], [0, -1], [0, 1]];

Lõpuks käivitage randomDirection muutuja juhusliku väärtuse hoidmiseks suuna massiivist ja määrake muutuja lastDirection tühjaks massiiviks, mis hoiab vanemat randomDirection väärtust.

Märkus. LastDirection massiiv on esimesel silmusel tühi, kuna vanemat randomDirection väärtust pole.

lase lastDirection = [],
    randomDirection;

Järgmisena veenduge, et maxTunnel pole null ja mõõtmed ning maxLengthäärtused on kätte saadud. Jätkake juhuslike juhiste leidmist, kuni leiate suuna, mis pole vastupidine või identne lastDirectioniga. See toimib, samas kui silmus aitab vältida hiljuti joonistatud tunneli ülekirjutamist või kahe tunneli tagurpidi joonistamist.

Näiteks kui teie lastTurn on [0, 1], takistab tegemise aeg funktsiooni edasiliikumist, kuni randomDirection on seatud väärtusele, mis pole [0, 1] ega vastupidine [0, -1].

tee {
randomDirection = juhised [Math.põrand (Math.random () * suunad.pikkus)];
} while ((randomDirection [0] === -lastDirection [0] &&
          randomDirection [1] === -lastDirection [1]) ||
         (randomDirection [0] === lastDirection [0] &&
          randomDirection [1] === lastDirection [1]));

Aktiivsuse ahelas on kaks peamist tingimust, mis jagatakse || -ga (VÕI) märk. Tingimuse esimene osa koosneb ka kahest tingimusest. Esimene kontrollib, kas randomDirectioni esimene üksus on lastDirectioni esimese üksuse tagurpidine element. Teine kontrollib, kas randomDirectioni teine ​​üksus on viimase pöörde teise üksuse tagurpidine element.

Näiteks, kui lastDirection on [0,1] ja randomDirection on [0, -1], kontrollib tingimuse esimene osa, kas randomDirection [0] === - lastDirection [0]), mis võrdub 0 == = - 0 ja on tõsi.

Seejärel kontrollib, kas (randomDirection [1] === - lastDirection [1]) võrdub (-1 === -1) ja on ka tõene. Kuna mõlemad tingimused on tõesed, läheb algoritm tagasi teise randomDirectioni leidmiseks.

Tingimuse teises osas kontrollitakse, kas mõlema massiivi esimene ja teine ​​väärtus on samad.

Pärast tingimustele vastava randomDirection valimist määrake muutuja, et valida pikkus juhuslikult maxLength hulgast. Seadke iteraatorina tunnelLength muutuja nulliks.

lase randomLength = Math.ceil (Math.random () * maxLength),
    tunnelPikkus = 0;

Tehke tunnel, keerates lahtrite väärtuse ühelt nullini, samal ajal kui tunnelLength on väiksem kui randomLength. Kui tunnel tabab silmuse piires kaardi servi, peaks silmus katkema.

while (tunnelLength 

Else seab kaardi praeguse lahtri nulli, kasutades currentRow ja currentColumn. Lisage väärtused randomDirection massiivi, seadistades currentRow ja currentColumn seal, kus nad peavad eeldatavas silmuse iteratsioonis olema. Nüüd suurendage tunneli pikkuse iteraatorit.

veel {
  kaart [currentRow] [currentColumn] = 0;
  currentRow + = randomDirection [0];
  currentColumn + = randomDirection [1];
  tunnelPikkus ++;
 }
}

Pärast seda, kui silmus on teinud tunneli või purunenud, vajutades kaardi servale, kontrollige, kas tunnel on vähemalt ühe ploki pikk. Kui jah, siis määrake lastDirection väärtuseks randomDirection ja vähendage maxTunnels ning minge tagasi teise randomDirectioni abil tunneli loomiseks.

if (tunnelLength) {
 lastDirection = randomDirection;
 maxTunnels--;
}

See IF-lause väldib for loop-i, mis tabab kaardi serva ega teinud vähemalt ühest lahtrist tunneli, et vähendada maxTunneli ja muuta viimast suunda. Kui see juhtub, otsib algoritm jätkamiseks veel ühe randomDirectioni.

Kui see on tunnelite joonistamise lõpetanud ja maxTunnels on null, tagastage saadud kaart koos kõigi pöördete ja tunnelitega.

}
 tagastuskaart;
};

Täielikku algoritmi näete järgmises lõigus:

Õnnitleme teid selle õppematerjali lugemise puhul. Olete nüüd hästi varustatud oma kaardigeneraatori loomiseks või selle versiooni parendamiseks. Vaadake projekti CodePenis ja GitHubis kui reageerimisrakendust.

Ärge unustage oma projekte kommentaaride jaotises jagada. Kui teile see projekt meeldis, siis palun andke sellele mõned näpunäited ja jälgige mind sarnaste õpetuste jaoks.

Eriline tänu Tomile (@ moT01 Gitteril) selle artikli kaastöö kirjutamise eest.