jQuery und das Canvas-Element

Simon says
Kommentare

Ich kann mir an dieser Stelle noch einen kleinen Seitenhieb auf Microsofts Internet Explorer nicht verkneifen: Laut W3C-Definition feuern Events nicht erst auf dem innersten Element, von wo sie dann schrittweise

Ich kann mir an dieser Stelle noch einen kleinen Seitenhieb auf Microsofts Internet Explorer nicht verkneifen: Laut W3C-Definition feuern Events nicht erst auf dem innersten Element, von wo sie dann schrittweise hochgereicht werden, sondern durchlaufen zuerst noch eine capturing-Phase, in der der Event erst beim äußersten Element feuert und dann schrittweise nach innen wandert. Dies wurde von allen namhaften Browsern (und übrigens auch im Eventmodell von ActionScript) implementiert – mit der üblichen Ausnahme, inklusive deren aktueller Version 8.

Natürlich müssen wir nun noch wissen, welche der vier Tasten eigentlich gedrückt wurde. Wie wir im Codebeispiel sehen, erwartet die anonyme Funktion, die als Klick-Handler fungiert, einen Parameter e. Dieser enthält bei Aufruf ein Objekt vom Typ event, das uns weitere Informationen liefert; wir brauchen uns übrigens keine Gedanken darüber zu machen, dass dieses Objekt in verschiedenen Browsern unterschiedlich implementiert ist, da jQuery dessen Eigenschaften für uns normalisiert. Über die Eigenschaft target kommen wir an das Element, das den Event ursprünglich auslöste – die gedrückte Taste (andere Elemente besitzt unser Spiel nicht). Bevor wir den Event aber verarbeiten, überprüfen wir mit der Variablen disableUI noch, ob derzeit überhaupt eine Interaktion erlaubt ist. Wir vermeiden damit, dass der User auf die Tasten drücken kann, während der Computer die Farbabfolge vorspielt. Das Deaktivieren der Interaktionsmöglichkeit während dem Animationsablauf wird gerne vergessen; wenn man es unterlässt, muss man sich genau überlegen, wie man mit den Benutzereingaben zwischenzeitlich umgehen will (z. B. eine Animation an einem neuen Startpunkt ausrichten).

Da wir auch einen Weg brauchen, das Spiel zu starten, interpretieren wir einfach den ersten Klick in der Spielfläche als Startsignal – durch unseren zentralisierten Event Handler einfach umzusetzen. Um den aktuellen Spielzustand festzustellen, arbeiten wir mit der Variablen status, die zu Beginn wie nach Ende einer Spielrunde den Wert idle sowie während des Nachspielens durch den Benutzer den Wert user zugewiesen bekommt. Wir brauchen keinen eigenen Status für den Zeitraum, während der Computer am Zug ist – in dieser Zeit steht ohnehin disableUI auf true.

Zu Beginn des Spiels wird nun die Funktion initSequence aufgerufen, die einem Array für die Farbabfolge einen neuen, durch Zufall ermittelten Eintrag hinzufügt, und sodann eine weitere Methode aufruft, playSequence (Listing 1).

Listing 1

function playSequence() {
    if(seqPos == sequence.length) {
        seqPos = 0;
        status = 'user';
        disableUI = false;
        return;
    }
    $('#button_'+sequence[seqPos], $simon)
        .animate({opacity:1}, 200)
        .delay(200)
        .animate({opacity:0.5}, {duration:200, complete:playSequence});
    seqPos++;
}

Zu Beginn dieser Funktion steht lediglich eine Abbruchbedingung für den Fall, dass die Abfolge komplett ist, doch die darauffolgenden Zeilen wollen wir uns genauer ansehen. Hier wird erst über die gewohnte $ ()-Syntax ein jQuery-Objekt für die gerade aktuelle Taste in der Abfolge ermittelt. Des Weiteren wenden wir unter Einsatz des Chaining mehrer Methoden auf unser Objekt an – die Schreibweise, jede Methode in eine einzelne Zeile zu setzen, bietet sich der Übersichtlichkeit halber an. Wir simulieren hier ein Aufleuchten der Tasten durch das Verändern des Transparenzwertes, wobei uns die animate()-Methode behilflich ist. Diese kann nicht nur für Positionsveränderungen eingesetzt werden, sondern erlaubt es uns, sämtliche verfügbaren CSS-Eigenschaften schrittweise zu verändern; diese werden in einem Objekt gesammelt als erster Parameter übergeben. Wenn man die beiden aufeinanderfolgenden Aufrufe von animate() im Skript vergleicht, sieht man, dass für den zweiten Parameter zwei verschiedene Typen möglich sind: Eine Ganzzahl, die die Animationsdauer bestimmt, oder auch ein Objekt, das neben der Dauer noch die Angabe weiterer Optionen wie einer Callback-Funktion erlaubt, die nach beendeter Animation aufgerufen wird. Wir verwenden diese Möglichkeit, um quasi rekursiv stets wieder die playSequence– Methode aufzurufen, bis eine komplette Tastenabfolge vorgespielt ist.

Ähnliches geschieht in der clickedButton-Methode, die beim Nachspielen durch den Benutzer aufgerufen wird. Neben der Prüflogik, obwohl die der Reihenfolge entsprechend richtige Taste gedrückt wurde, enthält der Code wieder einen Abschnitt zu Tastenanimationen, wobei diesmal direkt eine anonyme Methode als Callback übergeben wird (Listing 2).

Listing 2

$button
    .animate({opacity:1}, 200)
    .delay(200)
    .animate({opacity:0.5}, {duration:200, complete:function(){
        seqPos++; 
        if(seqPos == sequence.length) {
            seqPos = 0;
            setTimeout(function(){initSequence();}, 1000);
        } else { 
            disableUI = false; 
        } 
    }});

Sollen nach beendeter Animation noch weitere Methoden auf demselben Objekt ausgeführt werden, müssen diese übrigens nicht in eine Callback-Funktion verpackt werden. Alle Aufrufe von animate innerhalb einer Chain warten stets das Ende der vorhergehenden Animation ab – wäre dem nicht so, würden in unserem Code ja Ein- und Ausblenden der Tasten parallel passieren. Eines habe ich noch nicht angesprochen: Die delay-Methode, die zwischen den Animationen platziert ist, wurde in jQuery 1.4 eingeführt und erlaubt es, Pausen zwischen den Animationen zu setzen. Manch einer mag in Versuchung geraten, diese für Verzögerungen zwischen Codeblöcken zu verwenden, davon ist jedoch abzuraten – in der Regel ist hier die gewohnte setTimeout-Methode besser geeignet, die in dem Codeausschnitt auch für das Erzwingen einer Pause zwischen dem letzten Spielzug des Benutzers und dem neuerlichen Abspielen der erweiterten Folge verwendet wird.

Geschafft!

Damit wäre unser Spiel komplett – dank jQuery mit nur wenigen Zeilen JavaScript-Code, und mithilfe des Canvas-Elements ohne ein einziges Byte an Bitmap-Grafiken zu verschwenden. Ob die Umsetzung dem Spieleklassiker der 80er gerecht wird, sei dahingestellt – auf jeden Fall hoffe ich, der Code lädt zum experimentieren und weiterbasteln ein. Viel Spaß!

alt=“Matthias Schelling“ width=“50″ />

Matthias Schelling ist Frontend Developer bei mira4.com, überzeugter jQuery-Nutzer der ersten Stunde und in unzähligen Debugging-Stunden gereifter scharfer Kritiker von Microsofts Internet Explorer.

Unsere Redaktion empfiehlt:

Relevante Beiträge

Meinungen zu diesem Beitrag

X
- Gib Deinen Standort ein -
- or -