2024. április 19., péntek

Gyorskeresés

Építsünk Tetris Játékot JavaScript alapokon I - Rajzoljunk Tetromino-t

Írta: | Kulcsszavak: JavaScript . HTML . Webfejlesztés . Játék . Tetrisz

[ ÚJ BEJEGYZÉS ]

Készítettem egy Tetris játékot JavaScript programnyelven , ami alatt rengeteg sok dolgot tanultam, sok minden amit eddig nem láttam az körvonalazódni kezdett, illetve nagyon sok minden teljesen kivilágosodott számomra. Ezért szeretnélek téged is végigvinni ezen a folyamaton, a játék kódjainak bemutatásával.

A cikk több részes lesz, mert az anyag nagyon terjedelmes, nem fér bele egy teljes cikkbe, illetve így az egész cucc emészthetőbb lesz.

Hol is kezdjük?
Elsőként készítsük el magát a játék teret.
A Tetris játék fő játéktere egy téglalap, amiben különböző alakú objektumok haladnak felülről lefelé. Ha a leérkezett objektumokból kirakunk egy teljes sort, a sor eltűnik és pontot kapunk. De most nem azért vagyunk itt, hogy a játék menetét ismertessem.
Ha már foglalkoztál HTML-el, vélhetően rögtön beugrik, hogy a téglalap fő játéktér kivitelezhető egy <div>-vel, a benne lévő alakzatok rácsba rendezett div-ek színezésével kirajzolható. Tehát lesz egy fő téglalap alakú div-ünk, benne négyzet alakú div-ekkel.

Én a fő játék teret .grid osztálynak neveztem el, ami 250px széles 525px magas. A benne lévő grid divek 25-25px szélesek és magasak. Ebből könnyen megkapjuk, hogy egy sorban 10darab négyzet div fér el (250/25 = 10) és egy oszlopban 21 darab. De én 24-et csináltam, mivel a felső kettőt hidden osztályba tettem, illetve az alsót "taken" osztályba. Később ezáltal fogja érzékelni a játék, ha az alján van a Tetromino (azaz a Tetris elem). A felső két rejtett sor azért kell, hogy a dobott Tetromino beúszás szerűen jelenjen meg. De erről majd később.

Ha megnyitjuk a böngésző devtools-át, akkor ki tudjuk jelölni a grid div négyzeteket, de ha JavaScript kódunkba teszünk egy let squares = Array.from(document.querySelectorAll(".grid div")); sort, akkor a devtools-ban squares[x] vagy grid.children[x] parancsokkal is ki tudjuk kérni az adott grid div négyzetet, ahol az x a tömb x-edik eleme.

A let squares = Array.from(document.querySelectorAll(".grid div")); sor hatására egy tömböt kapunk a squares nevű változóba. Ezt beírva a devtools-ba kiírja a tömböt, amiben benne lesz mind a 10*24=240 darab grid divünk, amivel ezután squares[adott grid div kulcs]-al műveleteket tudunk végrehajtani. Például megváltoztathatjuk majd a színét, ami a játékmenet nagyon fontos része.

squares["35"]-t beírva a devtoolsba, megkapjuk az adott grid divet . A képen úgy is tűnhetne, hogy ez a 15-dik , de ne felejtsük el, hogy az első 2 sor rejtett.

Dolgozzunk a squares tömbbel

A squares["A GRID DIV KULCSA"].style.backgroundColor = "SZÍN NEVE" parancsot a devtoolsban megadva az adott kulccsal kiválasztott négyzet divet színezhetjük egy általunk választott színnel.
A fenti példában a 35-ös kulcsú négyzetet pirosra, a 45-öst kékre, az 55-öst zöldre, a 66-ost barnára, a 76-ost sárgára színeztem. De akár írhatunk is bele. a squares[X].innerHTML = "valami" paranccsal, ahol az X az adott squares kulcsát jelöli továbbra is.

forEach ciklussal például beszámozhatjuk az összes grid divünket. Így az tartalmazza a saját tömb szerinti kulcsát.

A Tetromino
A Tetris játék elemét Tetromino-nak hívjuk. Ezt az elemet 4 féle állásba tudjuk forgatni, meg tudjuk határozni, hogy a Tetromino az alap pozíciójához képest melyik square[x] grid divet tölti ki. Ezeket az adatokat tömbben tudjuk tárolni. Pontosabban a korrekciós adatokat kell tárolni az aktuális pozícióhoz képest, a többi adat számítható.

Így néz ki az lTetromino változónk, ami az L-alakú Tetromino 4 pozícióját tárolja a current pozícióhoz képest. A width értéke 10-mivel a következő sort a squares 10-es különbségekkel adhatjuk meg. Például a squares["44"] alatt a squares["54"] van, azaz a különbség 10

Töltsük ki narancssárga L-tetromino 0. rotációs állásával a 45, 46, 55, 65-ös square-t.
Állítsuk a currentPosition változót t 44-re.
A colors változóba szín neveket tettem.
const colors = ["orange", "red", "purple", "green", "blue", "brown", "turquoise"];
Tehát az orange a 0. elem, azaz a colors["0"] lesz a narancssárga szín.
A tetromino konstansokat pedig a theTetrominoes tömbbe raktam
const theTetrominoes =
[lTetromino, zTetromino, tTetromino, oTetromino, iTetromino, liTetromino, ziTetromino];
Az L-alakú tetromino tehát a theTetrominoes["0"] lesz, az L-alakú tetromino a 0. rotációs pozícióban pedig a theTetrominoes["0"]["0"]
A current változót töltsük fel az lTetromino 0. állásával, azaz vagy lTetromino["0"]-val vagy theTetrminoes[0][0]-val.
A currentRotation értéke, alapból 0, így azt változtatni nem kell.
Ezután csak végig kell futtatni egy forEach ciklust, ami kirajzolja nekünk a tetrominot, az adott színnel és pozícióban.

current.forEach((index) => {
squares[currentPosition + index].classList.add("tetromino");
squares[currentPosition + index].style.backgroundColor = colors["0"];
});

Nézzük meg még egyszer a folyamatot képekben

Az utolsó képen látható, hogy a squares 45, 46, 55, 65 bekerült a tetromino osztályba és a háttér színe narancssárga. A későbbiekben ez fontos lesz, az ütközés detektálásnál. Ahol majd vizsgálni kell, hogy az adott squares[X] benne van e a tetromino vagy taken osztály valamelyikében.

És akkor vegyük át még egyszer, hogyan számoltuk ki.
Az L-tetromino 0 rotációs állásában található tömb értéke a [1, width + 1, width * 2 + 1, 2] . A width = 10, tehát a tömb [1, 11, 21, 2]. Ha a currentPosition a square[44], akkor a tetrominot a [44+1, 44+11, 44+21, 44+2] square-be kell tenni, azaz 45, 56, 66, 46-os kulcsú square-be. Ezen megyünk végig a fenti forEach ciklussal.

Adjunk hozzá még
Adjunk hozzá a játéktérhez további tetrominokat. Mondjuk legyen ez egy zöld négyzet , aminek minden rotációs állása ugyan az.

Tegyük a négyzet tetrominot- az oTetromino tömbbe.
Az oTetromino tömb így néz ki:

const oTetromino = [
[0, 1, width, width + 1],
[0, 1, width, width + 1],
[0, 1, width, width + 1],
[0, 1, width, width + 1]
];

Tehát

Ha lekérjük az oTetromino[0]-t azaz az O nevű tetrominot, a 0 rotációs állásban, akkor ezt kapjuk.
oTetromino[0] (4) [0, 1, 10, 11]
Azaz, ha az aktuális pozíció például 82, akkor a tetrominot a 82, 83, 92, 93-as squares pozícióba tudjuk kirajzolni.

A theTetrominoes és coloros tömbjeink mindig megvannak.
const theTetrominoes = [lTetromino, zTetromino, tTetromino, oTetromino, iTetromino, liTetromino, ziTetromino];
const tetrominoNames = ["L", "Z", "T", "O", "I", "L-INVERT", "Z-INVERT"];
const colors = ["orange", "red", "purple", "green", "blue", "brown", "turquoise"];

Ha azt szeretnénk, hogy az oTetromino legyen az aktuálisan kirajzolandó elem, akkor a current legyen = theTetrominoes[3][0] vagy oTetromino[0]. A zöld szín a color[3]. Tegyük ezt be mondjuk egy colorfornewtetromino változóba.
currentPosition = legyen 82-vel, és mehet rá a forEach ciklus.

A képen látható, hogy mi történt. Kirajzolódott a tetromino. Zöld és négyzet alakú. Hurrá.

Vaduljunk be.
Adjunk hozzá még négyzeteket különböző pozíciókban.

Töröljük ki a létrehozott tetrominokat

Ehhez csak vissza kell állítani az aktuális pozíciót, azaz a currentPosition-t és a currentet, és mehet rá a szín style eltávolító és tetromino classból kivevő ciklus

current.forEach((index) => {
squares[currentPosition + index].classList.remove("tetromino");
squares[currentPosition + index].style.backgroundColor = "";
})

A képen látható, hogy a végén a currentet vissza kellett állítanom a theTetrominoes[0][currentRotation]-ba, mivel ez egy másik alakzat. :) De sikeresen kiürítettem a játékteret.

A folytatásban
Ennyi mára. A következő írásban megmutatom, hogy hogyan lehet random tetrominokat kirajzolni és azokat rotálni, azaz forgatni.

Akit érdekel a Webfejlesztés
...az látogasson el a Webfejlesztés Tanulószoba Facebook csoportba
... vagy a JavaScript Hungary csoportba

Video
https://www.facebook.com/groups/webfejleszt/permalink/725897558292602

A Tetris játék DEMO kódja
A v28-as fejlesztői verzió a Codepen-en érhető el, ahol ki is próbálhatod a működést és megnézheted a teljes kódot.

Ha valami nem világos a cikk tartalmával kapcsolatban, nyugodtan kérdezz kommentben. Ha valami tárgyi tévedést találtál, azt is jelezheted.

Köszönöm a figyelmet.

Copyright © 2000-2024 PROHARDVER Informatikai Kft.