Wiki-Push: Spiele mit JavaScript
Matthias Scharwies
- javascript
- spass
Servus!
ich hatte es schon lange im Test-Wiki und jetzt rübergezogen:
JavaScript/Tutorials/Spiele/Tic-Tac-Toe
Meine Version des Tutorials hat nur noch 23KB Text (60% gekürzt) und kümmert sich
<button aria-label="x" disabled>A1</button>
)Ich hoffe, dass das sowohl fachlich richtig als auch didaktisch verständlich geworden ist.
Jetzt geht es um die anderen Kapitel:
Das Ganze soll jetzt betonen, wie man Elemente mit DOM-Methoden erzeugt und löscht - die Spielidee an sich ist aber nicht so intuitiv. Hat jemand einen besseren Vorschlag? einen, den er womöglich selbst umsetzen möchte?
Das ist wohl etwas, was es in HTML ohne Frameworks nicht gibt.
Wer hat Lust evtl. erst ein Lückentext-Quiz und dann irgendetwas grafisches zu erstellen?
Herzliche Grüße
Matthias Scharwies
Lieber Matthias,
JavaScript/Tutorials/Spiele/Tic-Tac-Toe
Meine Version des Tutorials hat nur noch 23KB Text (60% gekürzt)
sieht gut aus! Wenn ich aber die großen if
-Statements lese, frage ich mich, ob das auch leserlicher geht.
// 3 senkrecht
if (fields[0 + i].getAttribute('aria-label') != ''
&& fields[0 + i].getAttribute('aria-label') == fields[3 + i].getAttribute('aria-label')
&& fields[3 + i].getAttribute('aria-label') == fields[6 + i].getAttribute('aria-label')
)
Diese Bedingungen prüfen doch auf den Wert des aria-label
-Attributs. Da könnte man doch eine kürzere Schreibweise verwenden:
function mark (node) {
if (node.hasAttribute('aria-label')) {
return node.getAttribute('aria-label');
}
}
if (mark(fields[0 + i])
&& mark(fields[0 + i]) == mark(fields[3 + i])
&& mark(fields[3 + i]) == mark(fields[6 + i])
)
Ob das jetzt unbedingt besser ist, mag eine Frage der Betrachtungsweise und der persönlichen Vorlieben sein.
Liebe Grüße
Felix Riesterer
Hallo Felix,
den Vorschlag mit der Accessor-Funktion mark
sollte man auf jeden Fall aufgreifen. Sie muss aber vervollständigt werden - für den Fall, dass das aria-label nicht existiert, sollte ein definierter Wert zurückgegeben werden. JS würde jetzt undefined
liefern, aber ich halte es für schlechten Stil, einen Pfad durch eine Funktion, von der ein Wert erwartet wird, nicht auf return
enden zu lassen. Das mögen andere anders sehen.
Man kann dabei ausnutzen, dass getAttribute("foo") laut aktueller Spec null
liefert und laut alter Spec den leeren String ""
, die beide falsy sind.
fields
ist eine globale Variable, bzw. in einem Spielobjekt wäre das eine Instanzvariable - da kann man auch einfach die Zellindizes als Parameter durchreichen und den Zugriff auf fields
intern behandeln.
function getMark(cell) {
return fields[cell].getAttribute("aria-label") || "";
}
Dazu noch zwei weitere Helper
function checkForVictory(cell1, cell2, cell3) {
let mark1 = getMark(cell1),
win = mark1 && mark1 == getMark(cell2) && mark1 == getMark(cell3);
if (!win) return "";
highlightCell(cell1);
highlightCell(cell2);
highlightCell(cell3);
return mark1;
}
function highlightCell(cell) {
fields[cell].classList.add('highlighted');
}
Und die eigentliche Abfrage würde ich dann stumpf runterprogrammieren statt aufwändig Schleifen zu bauen. Das ist natürlich anders, wenn man größere Felder implementieren will - aber ein TicTacToe mit 3 Gewinnfeldern im 4x4 Raster ist meines Wissens unspielbar (wer anfängt, gewinnt) und läuft eher auf Vier Gewinnt hinaus.
let winner = checkForVictory(0,3,6) || checkForVictory(1,4,7) || checkForVictory(2,5,8) ||
checkForVictory(0,1,2) || checkForVictory(3,4,5) || checkForVictory(6,7,8) ||
checkForVictory(0,4,8) || checkForVictory(2,4,6);
Rolf
@@Felix Riesterer
function mark (node) {
Meine erste Intuition war, die Funktion label
zu benennen, weil sie ebendas zurückliefert. Aber bei dem Spiel ist das ja Kreuz oder Kreis … Da finde ist Rolfs Vorschlag getMark
gar nicht schlecht.
if (node.hasAttribute('aria-label')) { return node.getAttribute('aria-label'); } }
Die Abfrage ist wohl überflüssig. Wenn das Ding kein solches Attribut hat, liefert node.getAttribute('aria-label')
auch null
, was gleich als Rückgabewert verwendet werden kann.
Ich finde null
auch passender als ''
; ich denke, dabei kann man es belassen:
function getMark(node) {
return node.getAttribute('aria-label');
}
😷 LLAP
@@Gunnar Bittersmann
Die Abfrage ist wohl überflüssig. Wenn das Ding kein solches Attribut hat, liefert
node.getAttribute('aria-label')
auchnull
, was gleich als Rückgabewert verwendet werden kann.
Wenn man da was abfragen sollte, dann, ob der übergebene node
tatsächlich existiert:
function getMark(node) {
return node?.getAttribute('aria-label');
}
Bei der Spiellogik ist wohl aber sichergestellt, dass es das Argument wirklich gibt; die Abfrage also nicht nötig.
Die würde im Rahmen des Tutorials eher verwirren. Zumal man auch noch erklären müsste, wie das für Uralt-Browser zu übersetzen wäre.
😷 LLAP
Hallo Matthias,
zum Thema Drag und Drop: Das Wiki zitiert einen ziemlich unflätigen Peter-Paul Koch, dass drag und dragover das Gleiche seien, und empfiehlt dann, dass man dragover nicht nutzen solle.
Es brummt der A-Bär: Entweder verstehe ich da was grundsätzlich falsch, oder PPK hat sich in seinem Zorn schwer vergaloppiert. ODER aber er moppert nur dann zu Recht, wenn mal ein Browser das dropzone Attribut implementiert.
Denn es gibt zwei entscheidendende Unterschiede: Das Event Target. Beim drag Event ist das Target das bewegte Element. Und bei dragover ist des das Element, über dem man gerade mit dem bewegten Element schwebt. Das ist ein entscheidender Unterschied, denn in dragover kann ich prüfen, ob auf diese Weise kann ich prüfen, ob ich gerade über einem drop-fähigen Element schwebe (mangels droppable-Attribut) und entsprechend den dropEffect setzen. In dragstart und dragenter gelingt mir das nicht.
Hinzu kommt: Ohne einen preventDefault-Aufruf im dragover Event ist es unmöglich, irgendwas zu droppen. Der Mauszeiger bleibt auf "Stop". Die Frickl-Beispiele machen das ebenfalls.
Also - PPK redete Unfug und der wurde unreflektiert nachgeplappert, oder ich plappere hier unverstandenen Käu daher. Was ist richtig?
Rolf
Servus!
Hallo Matthias,
zum Thema Drag und Drop: Das Wiki zitiert einen ziemlich unflätigen Peter-Paul Koch, dass drag und dragover das Gleiche seien, und empfiehlt dann, dass man dragover nicht nutzen solle.
Es brummt der A-Bär: Entweder verstehe ich da was grundsätzlich falsch, oder PPK hat sich in seinem Zorn schwer vergaloppiert. ODER aber er moppert nur dann zu Recht, wenn mal ein Browser das dropzone Attribut implementiert.
Ich kann nur sagen: 2015! Da hab ich versucht, das Wiki zu füllen. Sorry! Gerade bei Drag und drop gab es viele Teaser-Artikel und eigentlich keinen Anwendungszweck (außer D&D bei File-Upload).
Wsl. hat PPK da eben auch auf die Schnelle etwas versucht und ist am Fehlen des dropzone-Attributs gescheitert.
Denn es gibt zwei entscheidendende Unterschiede: Das Event Target. Beim drag Event ist das Target das bewegte Element. Und bei dragover ist des das Element, über dem man gerade mit dem bewegten Element schwebt. Das ist ein entscheidender Unterschied, denn in dragover kann ich prüfen, ob auf diese Weise kann ich prüfen, ob ich gerade über einem drop-fähigen Element schwebe (mangels droppable-Attribut) und entsprechend den dropEffect setzen. In dragstart und dragenter gelingt mir das nicht.
Hinzu kommt: Ohne einen preventDefault-Aufruf im dragover Event ist es unmöglich, irgendwas zu droppen. Der Mauszeiger bleibt auf "Stop". Die Frickl-Beispiele machen das ebenfalls.
Also - PPK redete Unfug und der wurde unreflektiert nachgeplappert, oder ich plappere hier unverstandenen Käu daher. Was ist richtig?
Ja, ich habe deine Erkenntnisse in den Artikel integriert:
Die ersten 2 Beispiele sind aktualisiert; bei den Drag-Events muss wsl. noch etwas erklärt werden.
Das (sinnfreie) Beispiel mit den Kugeln steht als "muss überarbeitet werden" unten drunter.
Vor allem kann man die Kugeln( p-Absätze) nicht nur in die div-Elemente ablegen, sondern auch in die p-Absätze?!?
[EDIT] Ein paar Zeilen weiter steht's: "Ist Ihnen aufgefallen, dass man im oberen Beispiel eine Kugel auch innerhalb einer anderen Kugel ablegen konnte? Das lag nur daran, dass in der Funktion ablegen() das target nicht explizit auf das div eingestellt worden war - was sich mit zwei zusätzlichen Zeilen problemlos beheben lässt:"
Das ändert nichts am fehlenden Sinn. Eigentlich müsste man hier schon ein kleines Rätsel stellen.
[/EDIT]
Es bleibt viel zu tun!
(Ich kümmer mich jetzt mal um das Zahlenspiel "Sum-Up")
Herzliche Grüße
Matthias Scharwies
Moin,
wollte an der Stelle mal eins los werden
MEGA COOOOL !!
Auch wenn es nicht zum Thema passt. Ich finde eure Bemühungen super! Ich weiß noch zu meiner Anfangszeit waren solche Seiten Gold wert, aber leider noch zu selten. Deshalb - weiter machen ! Ich mag was ihr da so alles fabriziert !
Gruß Fan T-Rex
Hallo T-Rex,
wollte an der Stelle mal eins los werden
MEGA COOOOL !!
Vielen Dank!
Deshalb - weiter machen ! Ich mag was ihr da so alles fabriziert !
Du kannst dich gern beteiligen.
Bis demnächst
Matthias