Fő tartalom
Programozás
Tantárgy/kurzus: Programozás > 4. témakör
5. lecke: Memóriajáték készítéseMemóriajáték: Kártyák megfordítása
Most már megvannak a kártyáink, amiket felfele vagy lefele fordíthatunk, de játszani még nem tudunk. Emlékeztetőül a játékszabályok:
- A játék kezdetekor minden kártya lefelé van fordítva
- A játékos egérkattintással kiválaszt két kártyát, ezzel felfordítja ezeket.
- Ha ugyanaz a kép szerepel mindkét kártyán, akkor felfordítva maradnak. Ha nem egyeznek a képek, akkor rövid időn belül visszafordulnak.
Kattintásra megforduló kártyák
Most már van egy programunk, ami egy rács mentén kirajzolja a kártyákat, ezt követően nem rajzol semmi mást. A továbbiakban szeretnénk, ha a programunk idővel újabb dolgokat rajzolna – lefordított kártyák rajzolásából indulunk ki, majd megjelenítjük a kiválasztott kártyákat, továbbá, ha jól játszik a játékosunk (szurkoljunk neki!), akkor meg fog jeleníteni egy győztes képernyő is.
Mozgassuk át az összes rajzoló kódunkat a ProcessingJS
draw
függvényébe. A számítógép folyton meg fogja hívni a draw()
függvényt, amíg a programunk fut, így a kártyák folyton újra lesznek rajzolva attól függően, hogy felfele vagy lefele vannak-e fordítva:draw = function() {
background(255, 255, 255);
for (var i = 0; i < tiles.length; i++) {
tiles[i].draw();
}
};
Fordítsunk fel néhány kártyák! A megfordításához a felhasználónak rá kell kattintania a kártyára. A ProcessingJS programokban úgy tudunk kattintásra reagálni, ha definiáljuk a
mouseClicked
függvényt, amit a számítógép minden alkalommal végrehajt, ha az egérrel kattintanak.mouseClicked = function() {
// process click somehow
};
Amikor a programunk látja, hogy a játékos valahol kattintott, a
mouseX
és mouseY
értékét szeretnénk ellenőrizni, hogy kiderüljön, valamelyik kártyára kattintott-e. Készítsünk ehhez egy isUnderMouse
metódust a Tile
-hoz, ami true
(igaz) értékkel tér vissza, ha adott x és y a kártya területén belül helyezkedik el!Úgy rajzoltuk ki a kártyákat, hogy a kártya x és y értéke a bal felső sarkot jelenti, ezért akkor kellene igaz értékkel visszatérni, ha a megadott x érték
this.x
és this.x + this.size
között van, illetve a megadott y érték a this.y
és a this.y + this.size
között van:Tile.prototype.isUnderMouse = function(x, y) {
return x >= this.x && x <= this.x + this.size &&
y >= this.y && y <= this.y + this.size;
};
Most, hogy elkészültünk ezzel a metódussal, használjunk egy
mouseClicked
-en belüli for
-ciklust annak ellenőrzésére, hogy valamelyik kártya a mouseX
és mouseY
pozíción helyezkedik-e el. Amelyikre ez teljesül, arra állítsuk be az isFaceUp
tulajdonságot true
-ra:mouseClicked = function() {
for (var i = 0; i < tiles.length; i++) {
if (tiles[i].isUnderMouse(mouseX, mouseY)) {
tiles[i].isFaceUp = true;
}
}
};
Így fest most. Kattints rá pár kártyára, hogy lásd mi történik:
Kártyák megfordításának korlátozása
Feltűnt valami? Implementáltuk a játék azon aspektusát, hogy a játékos képes legyen a kártyákat megfordítani, de egy fontos korlátozást elfelejtettünk: kettőnél több kártyát nem szabadna egyszerre felfordítania.
Figyelnünk kell valahogy azt, hogy mennyi kártya lett felfordítva. Ennek egy egyszerű módja az lenne, ha bevezetnénk egy globális
numFlipped
változót, amit minden alkalommal növelünk, amikor a játékos felfordít egy kártyát. Csak akkor fordítunk fel egy újabb kártyát, ha a numFlipped
értéke 2-nél kisebb, és ha a kártya nincs már felfordítva:var numFlipped = 0;
mouseClicked = function() {
for (var i = 0; i < tiles.length; i++) {
var tile = tiles[i];
if (tiles.isUnderMouse(mouseX, mouseY)) {
if (numFlipped < 2 && !tile.isFaceUp) {
tile.isFaceUp = true;
numFlipped++;
}
}
}
};
Késleltetve visszaforduló kártyák
Rendben, most már a két-kártyát-megfordító logikánk elkészült. Mi a következő? Idézzük csak fel a játék szabályait:
Ha két kártyán ugyanaz a kép szerepel, felfordítva maradnak. Egyébként egy kis idő után visszafordulnak.
Először a második lépést implementáljuk, ami automatikusan visszafordítja a kártyákat, mert nehéz lesz tesztelni az első részt, ha nem tudunk új párokat keresni.
Tudjuk, hogyan az
isFaceUp
false
-ra állításával fordíthatunk vissza kártyákat, de azt hogyan érjük el, hogy ez egy kis idő után történjen meg? Minden programozási nyelvnek és környezetnek más megközelítése vannak arra, hogyan késleltessék a kód végrehajtását, és rá kell jönnünk, hogyan oldjuk ezt meg ProcessingJS-ben. Valahogyan figyelnünk kell az időt – azt, hogy a késleltetési idő letelt-e –, és ki kell találnunk azt, hogyan hívjuk meg a kódot, ha ez az idő letelt. Az alábbit javasoljuk:- Készítsünk egy globális változót
delayStartFC
néven, inicializáljuk null értékkel. - A
mouseClicked
függvényben rögtön a második kártya megfordítása után tároljuk el aframeCount
jelenlegi értékét adelayStartFC
-ben. Ez a változó mondja meg, hogy mennyi képkocka telt el, mióta a programunk fut, és ez az egyik módja annak, hogy az időt lekérdezzük a programunkban. - A
draw
függvényben vizsgáljuk meg, hogy aframeCount
értéke szignifikánsan nagyobb-e, mint a régi érték, és ha igen, akkor fordítsunk vissza minden kártyát, és állítsuk vissza anumFlipped
értékét 0-ra. AdelayStartFC
értékét is állítsuk visszanull
-ra.
Ez igazából egy egészen szép megoldás, és nem kell hozzá túl sok kódot írnunk. Hatékonyság szempontjából használhatjuk a
loop
és noLoop
függvényeket, így biztosítva, hogy a draw
kód csak akkor hívódjon meg, amikor késleltetés történik. Íme ez így mind együtt:var numFlipped = 0;
var delayStartFC = null;
mouseClicked = function() {
for (var i = 0; i < tiles.length; i++) {
var tile = tiles[i];
if (tile.isUnderMouse(mouseX, mouseY)) {
if (numFlipped < 2 && !tile.isFaceUp) {
tile.isFaceUp = true;
numFlipped++;
if (numFlipped === 2) {
delayStartFC = frameCount;
}
loop();
}
}
}
};
draw = function() {
if (delayStartFC &&
(frameCount - delayStartFC) > 30) {
for (var i = 0; i < tiles.length; i++) {
tiles[i].isFaceUp = false;
}
numFlipped = 0;
delayStartFC = null;
noLoop();
}
background(255, 255, 255);
for (var i = 0; i < tiles.length; i++) {
tiles[i].draw();
}
};
Fordíts fel néhány kártyát – egész menő, ahogy a kártyák automatikusan visszafordulnak, ugye? Hogy jobban megértsd, próbáld meg megváltoztatni azt, hogy meddig tart a késleltetés, és azt, hogy hány kártyát fordíthatsz fel, mielőtt a késleltetés megkezdődik.
Egyező párok vizsgálata
Ha találtál egyező párokat, akkor valószínűleg csalódtál, amikor visszafordultak, hiszen találtál egy párt! Itt az idő hát, hogy a játéknak az alábbi szabályát is megvalósítsuk:
Ha két kártya egyezik, akkor felfordítva maradnak.
Ez azt jelenti, hogy meg kell vizsgálnunk, hogy 2 felfordított kártya esetén egyeznek-e a felfordított kártyák képei, mielőtt beállítjuk a késleltetést. Így fest ennek a pszeudó-kódja:
if there are two tiles flipped over:
if first tile has same face as second tile:
keep the tiles face up
Már vizsgálatunk olyat, hogy két kártya van-e felfordítva (
numFlipped === 2
), de hogyan ellenőrizzük le azt, hogy a két kártyán ugyanaz a kép szerepel-e? Először is, hozzá kell férnünk valahogy a két felfordított kártyához. Hogy találjuk meg őket?Végigiterálhatunk a tömbünkön minden alkalommal, és megkereshetjük a kártyákat, amiknek az
isFaceUp
értéke igaz, és eltárolhatjuk ezeket egy tömbben.Egy egyszerűsítés ehhez: a könnyű hozzáférhetőség miatt mindig tároljuk el a felfordított kártyákat egy tömbben. Így nem kell mindig végigiterálnunk a teljes
tiles
tömbön, amikor a játékos megfordít egy kártyát.Első lépésként cseréljük ki a
numFlipped
-et egy tömbre, és használjunk mindenütt a flippedTiles.length
-et ott, ahol korábban a numFlipped
-et használtuk. A mouseClicked
függvényünk így néz ki most:var flippedTiles = [];
var delayStartFC = null;
mouseClicked = function() {
for (var i = 0; i < tiles.length; i++) {
var tile = tiles[i];
if (tile.isUnderMouse(mouseX, mouseY)) {
if (flippedTiles.length < 2 && !tile.isFaceUp) {
tile.isFaceUp = true;
flippedTiles.push(tile);
if (flippedTiles.length === 2) {
delayStartFC = frameCount;
loop();
}
}
}
}
};
Most rá kell jönnünk, hogy a
flippedTiles
tömbben levő két kártyán ugyanaz a kép van-e. Mi is a face
tulajdonság? Egy objektum. Az egyező kártyák képei ugyanarra az objektumra mutatnak, a számítógép memóriájának ugyanarra a pontjára. Ez azért van, mert minden kép objektumot egyszer hoztunk létre (getImage("avatars/old-spice-man")
), és ugyanazt a képet helyeztük el két kártya face tulajdonságában:var face = possibleFaces[randomInd];
selected.push(face);
selected.push(face);
JavaScriptben az egyenlőség operátor igaz értékkel tér vissza, ha két olyan változón használjuk, amik ugyanazon a memóriaterületen elhelyezkedő objektumra mutatnak. Ez azt jelenti, hogy a vizsgálat egyszerű – az egyenlőségjel operátort kell használnunk minden kártya
face
tulajdonságára:if (flippedTiles[0].face === flippedTiles[1].face) {
...
}
Ha találtunk egyező kártyákat, akkor felfele fordítva kell őket tartanunk. Jelenleg egy kis idő után visszafordulnak. Egyszerűen megtehetjük azt, hogy csak nem állítjuk be az animációt az ilyen esetekre, de ne feledd, későbbi körben lesz animáció, ami megfordít – ezért erre nem támaszkodhatunk.
Ehelyett valahogy tudnunk kell, hogy „hé amikor visszafordítjuk őket, nem szabad visszafordítanunk bizonyos kártyákat”. Ez nagyon úgy hangzik, mintha logikai értékű tulajdonságot használhatnánk itt! Adjunk is egy
isMatch
tulajdonságot a Tile
konstruktorához, és állítsuk át az isMatch
értékét true
-ra, az if
blokkban:if (flippedTiles[0].face === flippedTiles[1].face) {
flippedTiles[0].isMatch = true;
flippedTiles[1].isMatch = true;
}
Most már használhatjuk ezt a tulajdonságot arra, hogy eldöntsük, hogy vissza kell-e fordítanunk egy adott kártyát.
for (var i = 0; i < tiles.length; i++) {
var tile = tiles[i];
if (!tile.isMatch) {
tile.isFaceUp = false;
}
}
Játssz el az alábbival! Amikor megtalálsz két egyező párt, felfordítva kell maradniuk (a későbbi körökben is):
Szeretnél részt venni a beszélgetésben?
Még nincs hozzászólás.