Anzeige
Tutorialbeschreibung

Memoryspiel mit Actionscript - Teil 2

Memoryspiel mit Actionscript - Teil 2

Achtung: dieses Tutorial setzt zwingend den ersten Teil voraus!

Um die Karten umdrehen zu können, müssen sie zunächst die Rückseite anzeigen.

  1. Ändern Sie daher innerhalb der Schleife mit attachMovie die Zeile obj.gotoAndStop(obj._totalframes); einfach in:

obj.stop();

Die Karten wenden sich nun verschämt von ihnen ab.

Das Umdrehen erfolgt nach einem Mausklick. Das entsprechende Ereignis besteht bereits, nur der Befehl zum Umdrehen muß noch ergänzt werden. Aus Gründen der Übersicht empfiehlt es sich, von der Logik her zusammenhängende Befehlsblöcke in eigenständigen Funktionen zu erfassen.

  1. Daher schreiben Sie in das onPress-Ereignis von obj:

box.umdrehen(this);

Damit wird bei Mausklick auf eine der Karten eine Funktion aufgerufen und ihr als Parameter das Objekt mitgegeben, das angeklickt wurde.

  1. Ganz am Ende des Skriptes fügen Sie nach der letzten schließenden Klammer die Funktionsdefinition von umdrehen() ein:

box.umdrehen = function (welche){
          welche.play();
}

Bei jedem Mausklick dreht sich nun die angeklickte Karte, allerdings ohne wieder anzuhalten. Dazu muß jede Karte explizit angewiesen werden, bei Erreichen ihres letzten Frames stehen zu bleiben.

  1. Erweitern Sie die Funktionsdefinition nach der play-Methode:

welche.onEnterFrame = function(){
          if(this._currentframe >= this._totalframes){
                    this.stop();
                    delete this.onEnterFrame;
          }
}

Bei jedem Mausklick wird der betreffenden Karte ein enterFrame-Ereignis zugewiesen, das andauernd die aktuelle Framenummer kontrolliert. Wenn diese gleich der Gesamtanzahl der Frames ist, stoppt die Animation und das enterFrame-Ereignis wird gelöscht, da wir es nicht weiter benötigen. Auf diese Weise wird die 9 Frames umfassende Animation einmal abgespielt. Allerdings startet nach wie vor jeder Mausklick auf dieselbe Karte die Animation.

Am Anfang wurden drei Fallunterscheidungen getroffen, die bei Mausklick zu beachten sind: vorher keine Karte ausgewählt, dieselbe Karte angeklickt, eine andere Karte angeklickt. Um Karten vergleichen oder feststellen zu können, ob bereits vorher eine ausgewählt wurde, benötigt Flash eine Variable.

  1. Fügen Sie daher unmittelbar vor box.aTempNums = [] folgende Zeile ein:

box.karte1 = „“;

  1. Die Funktionsdefinition von umdrehen() muß ebenfalls erweitert werden (Fettdruck):

box.umdrehen = function (welche){
          if(box.karte1 == welche){
                    return;
          }
          welche.play();
          welche.onEnterFrame = function() {
                    if (this._currentframe>=this._totalframes) {
                              this.stop();
                              delete this.onEnterFrame;
                    }
          };
          if(box.karte1==““){
                    box.karte1 = welche;
          }
}

Zum Testen klicken Sie bitte zweimal auf dieselbe Karte. Die Animation wird dann nur ein einziges Mal abgespielt. Beachten Sie, daß dies momentan nur für die erste angeklickte Karte funktioniert!

Da am Anfang noch keine Karte ausgewählt ist, weisen wird der Variablen box.karte1 einen leeren String zu. Beim Ausführen der Funktion umdrehen() schaut Flash nach, ob in dieser Variablen der Name der angeklickten Karte steht; dieser Name wird ja im Parameter welche übergeben. Ist das der Fall, bricht die weitere Ausführung der Funktion durch return ab. Return bewirkt an dieser Stelle also einfach das Verlassen des in umdrehen() definierten Befehlsblocks.

Ist das nicht der Fall, wird wie zuvor die Animation abgespielt und anschließend der Name der angeklickten Karte in box.karte1 gespeichert, falls die Variable noch leer ist.

Enthält box.karte1 bereits einen Wert, dann wissen wir, es wurde zuvor bereits eine andere Karte angeklickt. Damit ist es an der Zeit, beide miteinander zu vergleichen. Wie bei umdrehen() wollen wir das Vergleichen in eine eigene Funktion auslagern.

  1. Erweitern Sie die Funktion umdrehen() (Fettdruck):

if (box.karte1 == "") {
          box.karte1 = welche;
}else{
          pauseInterv = setInterval(box.pruefen,1000,welche);
}

Die Schleife zum Anzeigen der Karten sieht jetzt so aus:

Bilder
 

Und die Funktionsdefinition von umdrehen():

Bilder

Um dem Anwender die Möglichkeit zu geben, die Karten selbst zu vergleichen, definieren wir mit der Funktion setInterval eine kleine Pause. Die Parameter in der Klammer definieren, wie setInterval auszuführen ist: es wird die Funktion pruefen() aufgerufen, sobald 1000 Millisekunden vergangen sind, und zum Ausführen von pruefen() wird welche übergeben. Anders formuliert: Damit setInterval korrekt abläuft, muß als erster Parameter die aufzurufende Funktion genannt werden, dann folgt die Zeitspanne, nach der diese Funktion ausgeführt wird, und anschließend können bei Bedarf weitere Informationen mitgegeben werden. Da setInterval ein zäher Bursche ist, den man so leicht nicht wieder los wird, weisen wir den Aufruf der Variablen pauseInterv zu. Dann können wir bei Bedarf einfach pauseInterv löschen und setInterval wird nicht mehr weiter ausgeführt. Andernfalls würde jeweils im Abstand von einer Sekunde pruefen() aufgerufen. SetInterval wird also ähnlich wie das enterFrame-Ereignis permanent ausgeführt.

Offen ist noch die Definition des eigentlichen Vergleichsvorgangs.

  1. Schreiben Sie ganz am Ende des Skripts nach der letzten schließenden Klammer folgende Zeilen:

box.pruefen = function (wen){
          var eins = String(box.karte1).lastIndexOf("_");
          var zwei = String(wen).lastIndexOf("_");
          if (String(wen).substring(zwei+1) == String(box.karte1).substring(eins+1)) {
                    box.karte1.removeMovieClip();
                    wen.removeMovieClip();
                    box.karte1 = „“;
          }
          clearInterval(pauseInterv);
}

Wir hatten beim Erzeugen der Karteninstanzen dafür gesorgt, daß Paare durch eine gleiche Nummer identifiziert werden, die sich ganz am Ende des Namens, abgetrennt durch einen Unterstrich, befindet. Für den Vergleich muß also lediglich auf diese Zahl zugegriffen werden. Das erfolgt in zwei Schritten: da die Nummer ein- oder, wenn Sie mehr als 9 Paare haben, auch zweistellig sein kann, muß zunächst die Position des letzten Unterstrichs im Namen ermittelt werden. Alles, was sich dahinter befindet, stellt die gesuchte Zahl dar. Die String-Methode lastIndexOf() gibt den Index, der wie bei Arrays mit 0 beginnt, des letzten Auftretens des angegebenen Zeichens wieder. Wenn wir in „h_seldon“ nach dem Unterstrich suchen würden, gäbe („h_seldon“).lastIndexOf(„_“) die 1 zurück, da er sich an Indexposition 1 befindet. Die lokalen Variablen eins und zwei speichern also bei den Instanznamen der aufgedeckten Karten das letzte Auftreten des Unterstrichs.

Extrahiert wird die gesuchte Zahl mit der String-Methode substring(), die einen String, also Text, zurückgibt. Sie benötigt als Parameter den Beginn und das Ende des erwünschten Strings, jeweils (wie beim Array) als Indexwert angegeben. Wird das Ende nicht mitgegeben, gibt substring den vollständigen String vom ersten angegebenen Index bis zum Ende wieder. („h_seldon“).substring(2) würde also „seldon“ zurückgeben. Wenn wir dagegen die Zeichen nach dem letzten Unterstrich brauchen, müssen wir als Parameter nur die jeweils um 1 inkrementierten, eben ermittelten Variablen übergeben. Wenn wir beide Variablen unverändert nehmen, ist der Unterstrich im substring mit enthalten.

Dementsprechend fragt obige if-Bedingung nach, ob es wahr ist, das die letzten Zeichen der Instanznamen der angeklickten Karten identisch sind.

Da String-Operationen notwendigerweise nur mit Strings möglich sind, in unseren Variablen bzw. Parametern box.karte1 und wen aber Objekte enthalten sind (genau genommen: Referenzen auf MovieClips), müssen diese erst temporär, also nur für den Zeitpunkt dieser einen Codezeile, in Strings umgewandelt werden. Das geschieht durch den Ausdruck String(wen) bzw. String(box.karte1).

Wenn ein Paar gefunden wurde, wird es einfach mit Hilfe von removeMovieClip() gelöscht und der Variablen karte1 ein leerer String zugewiesen. Anschließend löschen wir auch das Interval, denn die Funktion pruefen soll immer nur einmal pro Mausklick ausgeführt werden.

  1. Testen, ob es soweit schon funktioniert, können Sie nur, wenn Sie wissen, wo sich welches Bild befindet. Dazu läßt sich das Skript temporär anpassen. Fügen Sie vor dem obj.onPress-Ereignis folgende Zeilen ein:

//test paar
obj.onRollOver = function(){
          trace(this._name);
}
//ende test

Bevor Sie auf eine Karte klicken, lassen Sie sich im Nachrichtenfenster bei Rollover die Instanznamen ausgeben. So können Sie feststellen, welche Karten zusammengehören. Sobald Sie ein Paar gefunden haben, wählen Sie die betreffenden Karten aus. Das Skript müßte jetzt wie gewünscht funktionieren.

Sind die Karten verschieden, sollen sie wieder verdeckt werden. Das geschieht, indem wir einfach die Animation zum Aufdecken rückwärts abspielen.

  1. Ergänzen Sie die pruefen-Funktion wie folgt (Fettdruck):

box.pruefen = function (wen){
          var eins …
          var zwei …
          if(derGanzeBandwurm){
                    …
          }else{
                    box.karte1.onEnterFrame = function(){
                    if(this._currentframe > 1){
                              this.gotoAndStop(this._currentframe-1);
                    }else{
                              this.stop();
                              box.karte1 = “”;
                              delete this.onEnterFrame;
                    }
          }
          wen.onEnterFrame = function(){
                    if(this._currentframe > 1){
                              this.gotoAndStop(this._currentframe-1);
                    }else{
                              this.stop();
                              delete this.onEnterFrame;
                    }
          }
}
clearInterval(pauseInterv);
}

Wählen Sie beim Testen verschiedene Karten aus, dann werden diese nach einer kurzen Wartezeit wieder umgedreht. Der else-Fall definiert, was zu geschehen hat, wenn die if-Bedingung nicht zutrifft. Beiden aufgedeckten Karten wird ein enterFrame-Ereignis zugewiesen, das jeweils kontrolliert, ob deren aktueller Frame größer als 1 ist. Wenn ja, dann ist die Animation noch nicht vollständig zurück gespult und der MovieClip geht zu der Framenummer, die 1 kleiner als die aktuelle Nummer ist. Damit bewegt sich der Abspielkopf auf der Zeitleiste nach links und die Animation läuft rückwärts. Ist der erste Frame erreicht, stoppt die Zeitleiste, die Variable karte1 wird wieder geleert und die enterFrame-Ereignisse beider MovieClips werden gelöscht.

Damit ist es bereits spielbar. Es gibt allerdings noch kleinere Ungenauigkeiten. Wer einen nervösen Finger hat und direkt drei verschiedene Karten auswählt, bringt das Programm aus dem Tritt. Daher wollen wir dafür sorgen, daß genau zwei Karten wählbar sind und in der Pause während des Vergleichens keine weitere Auswahl möglich ist. Auch hier bedienen wir uns einer Variablen, die einen bestimmten Programmzustand festhält.

  1. Fügen Sie vor box.karte1=““ folgende Zeile ein:

box.warten = false;

  1. Das obj.onPress muß erweitert werden (Fettdruck; bei dieser Gelegenheit löschen Sie bitte den trace-Aufruf):

obj.onPress = function() {
          if(!box.warten){
                    box.umdrehen(this);
          }
};

Der Ausdruck !box.warten ist eine Kurzform für box.warten == false. Es wird also gefragt, ob der Inhalt der Variablen box.warten false beträgt. Nach dieser Änderung hängt das Umdrehen einer Karte von box.warten ab. Da die Variable mit false initialisiert wird, kann man eine Karte mit dem ersten Klick aufdecken. Jetzt müssen wir nur noch dafür sorgen, daß sie irgendwann auf true gesetzt wird. Das geschieht beim Aufdecken der zweiten Karte.

  1. Fügen Sie innerhalb der Funktionsdefinition von umdrehen() im else-Fall unmittelbar vor dem Setzen des Intervals mit pauseInterv = usw folgende Zeile ein:

box.warten = true;

  1. Damit man nach dem Vergleich noch Karten anklicken kann, muß innerhalb der Funktionsdefinition von pruefen() an zwei Stellen der ursprüngliche Wert der Variablen wieder hergestellt werden. Fügen Sie innerhalb der if-Abfrage mit dem Bandwurm direkt vor box.karte1.removeMovieClip() die entsprechende Zeile ein:

box.warten = false;

  1. Die gleiche Zeile fügen Sie in den else-Fall des enterFrame-Ereignisses von box.karte1 irgendwo vor der Zeile mit delete ein. Hier ist die genaue Position wichtig: erst nach Ende der Animation darf die Variable wieder auf false gesetzt werden. Andernfalls kann während des Verdeckens eine weitere Karte aufgedeckt werden, es wären also zu einem Zeitpunkt drei Karten oder mehr sichtbar.

Gönnen Sie sich jetzt eine Runde Spiel und testen Sie es, bis alle Karten verschwunden sind.

Was jetzt noch fehlt, ist das unvernmeidliche Ende. Das kontrollieren wir einfach mit einer bereits vorhandenen Variable.

  1. Ergänzen Sie die Funktionsdefinition von pruefen() (Fettdruck):

box.pruefen = function (wen){
          var eins …
          var zwei …
          if(derGanzeBandwurm){
                    box.warten = false;
                    box.karte1.removeMovieClip();
                    wen.removeMovieClip();
                    box.karte1 = "";
                    box.anzahl--;
                    if(box.anzahl < 1){
                              trace(“Spielende”);
                              box.removeMovieClip();
                    }

          }
}

Das Spiel ist zu Ende, wenn alle Paare gefunden wurden. Deren Anzahl haben wir ganz am Anfang des Codes in der Variablen box.anzahl mit 8 festgelegt. Daher müssen wir nur bei jedem Auffinden eines Paares diese Variable um eins dekremenieren, also 1 subtrahieren, um herauszufinden, ob bereits alle Karten aufgedeckt wurden. Ist das der Fall, wird der MovieClip box – und damit alle zugewiesenen Variablen – gelöscht. Hier könnte dann noch eine Auswertung mit dem entsprechenden Feedback für den Spieler erfolgen (z.B. Anzahl der benötigten Klicks, Zeitdauer), die wir uns aber sparen wollen. Wir begnügen uns in aller Bescheidenheit mit einem „Spielende“. Achtung: in einem swf unabhängig von der Flash-Autorenumgebung funktioniert die trace-Anweisung natürlich nicht mehr, da das Nachrichtenfenster dort nicht geöffnet wird.

Hinweis: die Anzahl der benötigten Klicks läßt sich einfach durch Inkrementieren einer Variablen jedes mal dann, wenn zwei Karten miteinander verglichen wurden, erreichen. Eine zeitliche Begrenzung funktioniert über setInterval, das nach einer bestimmten Zeit automatisch ein Endeskript aufrufen könnte.

Halt, stellen Sie das Bier noch zurück, es fehlt eine Kleinigkeit!

Wenn wir uns das ganze Skript anschauen, dann sehen wir, daß sich der vollständige Code ausschließlich auf das Spiel bezieht. Wir können also alles in eine Funktion packen, die dann bei Bedarf aufgerufen werden kann. Damit ist es einfach möglich, auch zu einem späteren Zeitpunkt das Spiel wieder zu starten, ohne den Code per copy and paste irgendwo einfügen zu müssen.

  1. Fügen Sie vor der ersten Zeile eine neue Zeile ein:

function memory(){

  1. Die abschließende Klammer gehört in die allerletzte Zeile hinter das letzte Zeichen (es handelt sich dabei um die abschließende Klammer von pruefen()). Jetzt muß danach nur noch die Funktion aufgerufen werden:

memory();

Viel Spaß beim Spielen!

P.S.: Ein bißchen Aufräumarbeit ist noch notwendig: löschen Sie alle trace-Kommandos sowie das nur als temporär gedachte rollOver-Ereignis der Karten.

Wenn Sie den Programmcode verstanden haben, überlegen Sie sich Varianten und versuchen diese zu skripten. Learning by doing ist immer noch die beste Methode, eine Skript- oder Programmiersprache intensiv zu lernen!

Zur Kontrolle hier noch mal das ganze Skript:

function memory() {
          this.createEmptyMovieClip("box", 1);
          box._x = 100;
          box._y = 100;
          box.tiefe = 0;
          box.anzahl = 8;
          box.zeilen = 4;
          box.spalten = (box.anzahl*2)/box.zeilen;
          box.warten = false;
          box.karte1 = "";
          box.aTempNums = [];
          for (var i = 1; i<=box.anzahl; i++) {
                    for (var j = 1; j<=2; j++) {
                              box.aTempNums.push(i);
                    }
          }
          box.aKarten = [];
          while (box.aTempNums.length>0) {
                    var zufall = Math.floor(Math.random()*box.aTempNums.length);
                    box.aKarten.push(box.aTempNums[zufall]);
                    box.aTempNums.splice(zufall, 1);
          }
          for (var i = 0; i<box.zeilen; i++) {
                    for (var j = 0; j<box.spalten; j++) {
                              box.attachMovie("mc_k"+box.aKarten[box.tiefe], "k"+box.tiefe+"_"+box.aKarten[box.tiefe], box.tiefe);
                              var obj = box["k"+box.tiefe+"_"+box.aKarten[box.tiefe]];
                              obj.onPress = function() {
                                        if (!box.warten) {
                                                  box.umdrehen(this);
                                        }
                              };
                              obj.stop();
                              obj._x = j*(obj._width+2);
                              obj._y = i*(obj._height+2);
                              box.tiefe++;
                    }
          }
          box.umdrehen = function(welche) {
                    if (box.karte1 == welche) {
                              return;
                    }
                    welche.play();
                    welche.onEnterFrame = function() {
                              if (this._currentframe>=this._totalframes) {
                                        this.stop();
                                        delete this.onEnterFrame;
                              }
                    };
                    if (box.karte1 == "") {
                              box.karte1 = welche;
                    } else {
                              box.warten = true;
                              pauseInterv = setInterval(box.pruefen, 1000, welche);
                    }
          };
          box.pruefen = function(wen) {
                    var eins = String(box.karte1).lastIndexOf("_");
                    var zwei = String(wen).lastIndexOf("_");
                    if (String(wen).substring(zwei+1) == String(box.karte1).substring(eins+1)) {
                              box.warten = false;
                              box.karte1.removeMovieClip();
                              wen.removeMovieClip();
                              box.karte1 = "";
                    } else {
                              box.karte1.onEnterFrame = function() {
                                        if (this._currentframe>1) {
                                                  this.gotoAndStop(this._currentframe-1);
                                        } else {
                                                  box.warten = false;
                                                  this.stop();
                                                  box.karte1 = "";
                                                  delete this.onEnterFrame;
                                        }
                              };
                              wen.onEnterFrame = function() {
                                        if (this._currentframe>1) {
                                                  this.gotoAndStop(this._currentframe-1);
                                        } else {
                                                  this.stop();
                                                  delete this.onEnterFrame;
                                        }
                              };
                    }
                    clearInterval(pauseInterv);
          };
}
memory();


DVD-Werbung
Kommentare
Achtung: Du kannst den Inhalt erst nach dem Login kommentieren.
Alternative Portrait

-versteckt-(Autor hat Seite verlassen)

  • 31.10.2011 - 20:15

danke für die viele Arbeit

Portrait von thme
  • 31.05.2011 - 15:02

Dein Tutorial ist super geschrieben, auch wenn ich nicht alles zu 100% nachvollziehen kann habe ichs dank der guten Anleitung geschafft! *freu*

http://www.thme.ch/pics/anis/memory.html

Portrait von gundleyG
  • 31.12.2010 - 08:57

... wie schon der erste Teil - gut erklärt. Danke.

Portrait von isascha
  • 30.11.2010 - 13:57

Super! Es funktioniert!! Mein Tag ist gerettet!! 1.000 Dank! ;-)

Portrait von Lord_of_Hate
  • 10.07.2010 - 12:41

cooles teil thx werde das bestimmt noch oft brauche

Portrait von F1reF0x
  • 12.07.2009 - 22:21

Sehr gu erklärt habe mich doch relativ schnell zurecht gefunden pnwohl ich gar nicht so der flash mensch bin tolle sache

Alternative Portrait

-versteckt-(Autor hat Seite verlassen)

  • 02.12.2007 - 11:53

Hallo H_seldon

ein ganz tolles memoryspiel, ich glaube ganz viel gelernt zu haben. ich probiere bereits mein memory zu erweitern (ich muss ganz stolz sagen: den versuchszähler habe ich ganz alleine hinbekommen :D), allerdings mangelts bei was anderem. ich habe im forum gerade einen thread dazu erstellt (memory infotext nach aufgedecktem paar), wäre sehr froh wenn du dich dort äussern würdest!

liebe grüsse
radieschenfisch

Portrait von shivalena
  • 25.11.2007 - 23:45

Das Tutorials ist sehr gut erklärt, dennoch habe ich es nicht geschafft... Schon beim ersten Teil muss irgendwas schief gelaufen sein. Flash ist einfach zuz schwer...

Alternative Portrait

-versteckt-(Autor hat Seite verlassen)

  • 29.12.2006 - 13:09

Hallo h_seldon,

ich fand Dein Script für das Memoryspiel sehr toll erklärt!!!

Bin selber blutiger Anfänger in actionscripts, kenne mich aber ansonsten recht gut in Flash aus!

Es hat bei mir daher etwas länger gedauert... doch es hat sich gelohnt!!!!

Der zweite Teil ging dann aber sehr schnell!!!

Liebe Grüße

Barbara

Alternative Portrait

-versteckt-(Autor hat Seite verlassen)

  • 01.12.2006 - 11:45

echt ein super tutorial.

leider scheiter ich an einigen änderungen....vielleicht könnt ihr mir helfen.

ich möchte, dass ein individueller film startet wenn 2 gleiche karten aufgedeckt wurden (also zu jedem paar gibt es einen film).
danach sollen die karten verkleinert und links neben den karten abgelegt werden.
leider hab ich sowas noch nie in actionsscript umgesetzt.

ich hoffe, ihr habt eine lösung für mich. danke

Portrait von deburu
  • 18.06.2006 - 04:05

geil...

geiles tutorial

vielen dank ^^

Alternative Portrait

-versteckt-(Autor hat Seite verlassen)

  • 05.05.2006 - 19:45

TOP!!!

BIG THX :-D

x
×
×