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

Wenn du hinter einem Webfilter bist, stelle sicher, dass die Domänen *. kastatic.org und *. kasandbox.org nicht blockiert sind.

Hauptinhalt

Memory: Kacheln umdrehen

Gut, jetzt haben wir also ein Raster mit Kacheln, die wir mit der Oberseite nach oben oder unten anzeigen können. Aber wir können noch gar nicht spielen. Zur Erinnerung, so funktioniert das Spiel:
  • Zu Spielbeginn zeigen alle Kacheln mit der Oberseite nach unten.
  • Der Spieler dreht dann zwei Karten um, indem er sie anklickt.
  • Wenn die zwei Kacheln das gleiche Bild zeigen, bleiben sie aufgedeckt liegen. Ansonsten werden sie nach kurzer Zeit wieder umgedreht.

Kacheln zum Umdrehen anklicken

Im Moment haben wir ein Programm, das ein Raster von Kacheln zeichnet und dannn nie mehr etwas anderes. Nun wollen wir aber, dass unser Programm während dem Spiel verschiedene Dinge zeichnet. Es beginnt mit dem Zeichnen von umgedrehten Kacheln, aber dann soll es angeklickte Kacheln anzeigen, und wenn für den Spieler alles gut geht (Finger gekreuzt!), wird es einen Sieges-Bild anzeigen.
Wir wollen also unseren gesamten Zeichencode in die Funktion draw von ProcessingJS verschieben. Der Computer ruft weiterhin draw() auf, während das Programm läuft, so dass die Kacheln weiter gezeichnet werden, je nachdem, ob das Bild nach oben oder nach unten zeigt:
draw = function() {
    background(255, 255, 255);
    for (var i = 0; i < tiles.length; i++) {
        tiles[i].draw();
    }
};
Lass uns ein paar Kacheln umdrehen! Um eine Kacheln umzudrehen, muss der Spieler darauf klicken. Damit ProcessingJS-Programme auf einen Klick reagieren, können wir eine Funktion mouseClicked definieren. Dieser Code wird jedes Mal ausgeführt, wenn die Maus angeklickt wird.
mouseClicked = function() {
  // verarbeiten den Klick
};
Wenn unser Programm erkennt, dass der Spieler irgendwo hin geklickt hat, wollen wir mithilfe von mouseX und mouseY überprüfen, ob er auf eine Kachel geklickt hat. Wir beginnen indem wir eine Funktion isUnderMouse zu Tile hinzufügen, welche true zurückgibt, wenn x und y innerhalb der Fläche eine Kachel liegen.
So wie wir die Kacheln zeichnen, entsprechen x und y der linken oberen Ecke der Kachel. Wir müssen daher nur dann true zurückgeben, wenn x zwischen this.x und this.x + this.size und y zwischen this.y und this.y + this.size liegt.
Tile.prototype.isUnderMouse = function(x, y) {
    return x >= this.x && x <= this.x + this.size  &&
        y >= this.y && y <= this.y + this.size;
};
Mit dieser Methode können wir nun eine for-Schleife in mouseClicked verwenden, um zu prüfen, ob jede Kachel unter mouseX und mouseY liegt. Wenn ja, setzen wir isFaceUp auf true:
mouseClicked = function() {
  for (var i = 0; i < tiles.length; i++) {
    if (tiles[i].isUnderMouse(mouseX, mouseY)) {
      tiles[i].isFaceUp = true;
    }
  }
};
So sieht das dann aus. Klicke auf ein paar Kacheln und schau was passiert:

Beschränkung des Drehens der Kacheln

Ist dir etwas aufgefallen? Wir implementieren einen Aspekt des Spielverlaufs, nämlich dass der Spieler die Kacheln drehen kann, vergessen aber ein wichtige Einschränkung: Es sollte nicht möglich sein, mehr als zwei Kacheln auf einmal umzudrehen.
Wir müssen also irgendwie speichern, wie viele Kacheln umgedreht sind. Eine einfache Art wäre es, eine globale Variable numFlipped einzuführen, die wir jedes Mal hochzählen, wenn der Spieler eine Karte umdreht. Wir drehen eine Kachel nur dann um, wenn numFlipped kleiner als 2 ist und das Bild nicht nach oben zeigt:
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++;
            }
        }
    }
};

Kacheln zeitverzögert umdrehen

OK, unsere Logik zum Umdrehen von zwei Kacheln ist fertig. Was kommt jetzt? Erinnern wir uns noch mal an die Spielregeln:
Wenn die zwei Kacheln das gleiche Bild haben, bleiben sie aufgedeckt liegen. Ansonsten drehen sich die Kacheln nach einiger Zeit automatisch wieder um.
Wir implementieren zuerst den zweiten Teil, bei dem die Kacheln automatisch wieder umgedreht werden. Es wird sonst schwierig, den ersten Teil zu testen, wenn wir nicht nach neuen Paaren suchen können.
Wir wissen, wie man Kacheln mit zurückdreht, indem man isFaceUp auf false setzt, aber wie machen wir das nach einiger Zeit? Jede Sprache und Umgebung hat eine andere Herangehensweise, wenn es darum geht, Code zeitverzögert auszuführen. Wir müssen also herausfinden, wie das in ProcessingJS funktioniert. Wir brauchen eine Möglichkeit, die Zeit aufzuzeichnen (zur Prüfung, ob die Zeitverzögerung schon abgelaufen ist) und eine Möglichkeit, zur vorgegebenen Zeit den Code aufzurufen. Ich würde Folgendes vorschlagen:
  • Wir legen eine globale Variable namens delayStartFC an, die anfänglich Null ist.
  • Direkt nachdem wir eine zweite Kachel umgedreht haben, speichern wir in der Funktion mouseClicked den aktuellen Wert von frameCount in delayStartFC. An dieser Variable sehen wir, wie viele Frames durchgelaufen sind, seitdem unser Programm gestartet wurde. Dies ist eine Art, in Programmen die Zeit zu erfassen.
  • In der Funktion draw prüfen wir, ob der neue Wert von frameCount deutlich höher liegt als der alte. Wenn ja, drehen wir alle Kacheln um und setzen numFlipped auf 0. Ebenso setzen wir delayStartFC auf null zurück.
Eigentlich ist das eine schöne Lösung, bei der man nicht sehr viel Code implementieren muss. Zur Optimierung der Performance können wir die Funktionen loop und noLoop verwenden, um sicherzustellen, dass der Code der Funktion draw nur aufgerufen wird, wenn es eine Verzögerung gibt. Hier ist der ganze Code:
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();
  }
};
Drehe nun unten ein paar Kacheln - es ist ziemlich cool wie die Kacheln automatisch zurückdrehen, nicht? Damit du dies besser verstehst, versuche doch die Verzögerung zum zurückdrehen anzupassen. Ebenfalls wieviele Kacheln gedreht werden können, bevor der delay startet.

Paare finden

Wenn es dir oben gelungen ist passende Paare zu finden, warst du wohl enttäuscht als diese wieder umgedreht wurden, denn hey, du hast ein Paar gefunden! Nun programmieren wir diesen Teil des Spiels:
Wenn zwei Kacheln ein passendes Paar bilden, sollten sie nach aufgedeckt bleiben.
Dies bedeutet, dass wir prüfen wollen, ob die Bilder zusammenpassen, wenn zwei umgedreht sind, und zwar bevor die Verzögerungszeit läuft. In Pseudo-code wäre dies:
zwei Kacheln umgedreht sind:
    wenn die erste Kachel das gleiche Bild hat wie die zweite:
       lass die Kacheln aufgedeckt
Es gibt schon eine Prüfung dafür, ob zwei Kacheln umgedreht sind (numFlipped === 2). Wie prüfen wir also, ob die Kacheln das gleiche Bild haben? Zuerst brauchen wir einen Weg um auf die zwei umgedrehten Kacheln zuzugreifen. Wie finden wir diese?
Wir könnten jedes mal durch unser Array iterieren, alle Kacheln mit isFaceUp auf true finden und diese dann in einem Array speichern.
Hier eine Abkürzung: Wir speichern einfach jedesmal die umgedrehten Kacheln in einem Array. So müssen wir nicht jedesm mal durch das ganze tiles-Array iterieren wenn der Spieler eine Kachel umdreht.
In einem ersten Schritt, können wir numFlipped mit einem Array ersetzen und dann überall da wo wir vorher numFlipped vewendet haben, einfach flippedTiles.length verwenden. Unsere Funktion mouseClicked sieht nun so aus:
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();
        }
      } 
    }
  }
};
Jetzt müssen wir herausfinden, ob die beiden Kacheln im Array flippedTiles wirklich das gleiche Bild haben. Was ist noch mal die Eigenschaft für face, das Bild? Es ist ein Objekt. Das Bild der zusammengehörigen Kacheln sollte als genau das gleiche Objekt haben, da die Variable für beide genau zum gleichen Speicherplatz auf dem Computer zeigt. Das liegt daran, dass wir nur ein Bildobjekt erzeugt haben (wie bei getImage("avatars/old-spice-man")) und es dann zwei Mal in das Array für die Bilder verschoben haben.
var face = possibleFaces[randomInd];
selected.push(face);
selected.push(face);
In JS ist der Gleichheitsoperator weiterhin wahr, wenn er bei zwei Variablen verwendet wird, die auf Objekte zeigen, und sich beide Variablen auf dasselbe Objekt im Speicher beziehen. Dies bedeutet, dass unsere Prüfung einfach wird. Wir müssen nur bei jeder Kachel den Gleichheitsoperator auf die Eigenschaft face anwenden.
if (flippedTiles[0].face === flippedTiles[1].face) {
  ...
}
Jetzt, da wir wissen dass die Kacheln zusammenpassen, müssen wir diese umgedreht lassen. Zurzeit werden nach der Verzögerung alle wieder umgedreht. Wir könnten einfach die Animation nicht ausführen, aber dann würden die Kacheln im nächsten Durchlauf einfach wieder umgedreht.
Stattdessen brauchen wir eine Möglichkeit, zu sagen: "Hey, wenn wir alle Kacheln umdrehen, sollten wir diese hier auslassen." Klingt nach einer guten Anwendung für eine weitere boolsche Eigenschaft! Wir fügen eine Eigenschaft isMatch zum Konstruktor von Tile hinzu und setzen isMatch nur innerhalb dieses if-Blocks auf true:
if (flippedTiles[0].face === flippedTiles[1].face) {
  flippedTiles[0].isMatch = true;
  flippedTiles[1].isMatch = true;
}
Jetzt können wir mit dieser Eigenschaft entscheiden, ob wir die Kacheln nach der Verzögerung umdrehen wollen.
for (var i = 0; i < tiles.length; i++) {
  var tile = tiles[i];
  if (!tile.isMatch) {
    tile.isFaceUp = false;
  }
}
Spiele nun unten! Wenn du nun zwei zusammenpassende Kacheln findest, sollten sie auch nach der Zeitverzögerung (und in späteren Zügen) umgedreht bleiben:

Willst du an der Diskussion teilnehmen?

Noch keine Beiträge.
Verstehst du Englisch? Klick hier, um weitere Diskussionen auf der englischen Khan Academy Seite zu sehen.