If you're seeing this message, it means we're having trouble loading external resources on our website.

Ha webszűrőt használsz, győződj meg róla, hogy a *.kastatic.org és a *.kasandbox.org nincsenek blokkolva.

Fő tartalom

Memó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 a frameCount jelenlegi értékét a delayStartFC-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 a frameCount é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 a numFlipped értékét 0-ra. A delayStartFC értékét is állítsuk vissza null-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.
Tudsz angolul? Kattints ide, ha meg szeretnéd nézni, milyen beszélgetések folynak a Khan Academy angol nyelvű oldalán.