Eine Highscore Liste für JavaScript-Spiele erstellen

Eintrag von Jan,

Vor kurzem wurde ich per E-Mail gefragt, wie man denn eine Highscore Liste in ein HTML5 Spiel einbauen könnte. Die Antwort ist etwas länger geworden und ich dachte mir, dass sie vielleicht dem ein oder anderen helfen könnte.

Gleich vorweg: Ich habe vieles stark vereinfacht beschrieben, um einen schnellen Einstieg in die verschiedenen Technologien zu geben, damit die Highscore Liste auch ohne Vorwissen programmiert werden kann.

Leider funktioniert eine Highscore Liste nicht nur alleine mit JavaScript. Das würde sonst dafür sorgen, dass jeder Zugriff auf die Liste hat und sie beliebig verändern kann, denn JavaScript wird im Browser des Benutzers ausgeführt, und kann theoretisch beliebig verändert werden. Wenn der Browser Zugriff auf die Highscore Liste (Datenbank) hat, muss also auch der Benutzer Zugriff haben.

Der Server Teil (PHP)

Um diesem Problem aus dem Weg zu gehen, kommt eine Programmiersprache für Server dazu (PHP). PHP läuft nur auf dem Server und kann vom Benutzer nicht eingesehen oder verändert werden. Erst einmal vorweg: Die Highscore Liste, die wir hier erstellen ist leider auch nicht viel sicherer. Es gibt aber Möglichkeiten die Highscore mit PHP noch einmal zu überprüfen.

Der Server

Da PHP eine Programmiersprache für Server ist, brauchst du natürlich auch einen Server auf dem der Quellcode ausgeführt werden kann. Zum Glück ist PHP sehr verbreitet und deswegen gibt es sogar mehrere Möglichkeiten einfach einen Server zu bekommen.

Webspace

Es gibt bereits viele fertige, teilweise kostenlose Server (meistens Webspace genannt). Du musst nur darauf achten, dass PHP und MySQL auch dabei ist. Zugriff bekommt man dann meist über einen FTP Zugang. Lade dir dafür am besten ein Programm wie Filezilla herunter und gib die FTP-Daten ein. Du solltest dich dann verbinden können und eine Ordnerstruktur sehen. Versuche einfach mal eine HTML Seite hochzuladen und versuch die dann mal über deine Internetadresse im Browser aufzurufen (z.B. http://deine-seite.bplaced.de/deine-datei.html). (Wenn du die HTML-Seite index.html nennst, sollte die sich sogar automatisch öffnen, wenn du nur die Adresse eingibst). Den Webspace kannst du dann sogar benutzen, um das Spiel dauerhaft online verfügbar zu haben.

Xampp

Alternative gibt es auch das Programm Xampp, dass automatisch auf deinem PC einen PHP Server installiert. Aber der ist dann nur für dich sichtbar und Highscores können deshalb nicht von anderen Spielern gespeichert werden. Aber weil PHP Dateien direkt nach Speichern aufgerufen werden können, eignet sich diese Lösung besser für das Testen. Wenn Xampp gestartet ist, kannst du alle HTML und PHP Dateien in dem htdocs Ordner platzieren. Die sollte dann angezeigt werden, sobald du http://localhost/deine-datei.html in deinem Browser eingibst.

Das erste kleine PHP Script

Jetzt, wo der Server bereit ist, können wir ja mal testen, ob PHP auch richtig funktioniert. Also erstellen wir eine neue Datei mit der Endung .php. Ich nenne sie mal highscore.php.

Datei: highscore.php

<?php

$text = 'Test';
echo $text;

?>

Das <?php sagt dem Server, dass es sich um PHP Quelltext handelt. Also wird alles danach als PHP behandelt. $text ist dann gleich die erste Variable. In PHP werden Variablen statt mit var mit einem $ markiert. Im Gegensatz zu JavaScript muss das $ aber immer vor einer Variable stehen. Egal ob sie schon einmal benutzt wurde oder nicht. Die Variable $text bekommt dann den Wert "test" und in der nächsten Zeile wird dieser text mit echo einfach ausgegeben. ?> beendet PHP wieder.

Platziere diese Datei dann auf deinem Server und rufe sie auf. (http://localhost/highscore.php bei Xampp oder z.B. http://deine-seite.bplaced.de/highscore.php bei Webspace)

Du solltest jetzt nichts weiter als „Test“ auf der Seite sehen. Wenn nicht, prüfe nochmal, dass die Datei richtig platziert ist und PHP verfügbar ist.

GET Variablen

Es gibt zwei Möglichkeiten Daten an PHP zu übermitteln: POST und GET. GET wird innerhalb der Adresse übergeben. Also, wenn man die highscore.php mit der Adresse http://deine-seite.de/highscore.php?score=100 aufruft, wird eine GET Variable namens $_GET['score'] erstellt und auf 100 gesetzt. Mal ein Beispiel:

Datei: highscore.php

<?php

$score_exists = isset($_GET['score']);

if ($score_exists == true)
    echo 'Der Score ist ' . $_GET['score'];
else
    echo 'Keine Score angegeben!';

?>

In Zeile 3 siehst du direkt wieder eine Variable. Diesmal wird dieser Variable der Rückgabewert von der Funkion isset() zugewiesen. isset() prüft, ob die angegebene Variable gesetzt ist und gibt dann je nachdem true oder false zurück. Wenn man diese Prüfung weg lassen würde, gäbe es einen Fehler, falls man in der Adresse mal das "?score=100" weglässt. In der nächsten Zeile prüfen wir dann nur noch, ob die isset() Funktion jetzt true oder false zurückgegeben hat und geben dann der Score mit echo aus. Hier wird im Gegensatz zu JavaScript ein Punkt statt einem Plus als Verbindung zwischen Text und Variable benutzt. Falls das "?score" weggelassen wird, gibt es eine Fehlermeldung.

Wenn du jetzt http://deine-seite.de/highscore.php?score=eine-zahl aufrufst, wird der Score automatisch ausgegeben.

POST Variablen

POST Variablen funktionieren genauso wie GET, außer in einer Sache: Sie werden nicht in der Adresse übertragen (?score=…) sondern im Hintergrund über den Browser. Das wird meistens für Passwörter benutzt, weil die ja nicht einfach in der Adresse stehen sollen. Ändern wir zuerst einmal alle $_GET in $_POST um:

Datei: highscore.php

<?php

$name_exists = isset($_POST['name']);
$score_exists = isset($_POST['score']);

if ($score_exists == true && $name_exists == true)
    echo 'Die Score für ' . $_POST['name'] . ' ist ' . $_POST['score'];
else
    echo 'Keine Score oder Name angegeben!';

?>

Ich habe mal noch zusätzlich die Variable $name hinzugefügt und wieder eine Prüfung, ob der Name übergeben wurde.

Wenn du die Seite jetzt aufrufst, wird jedes mal der Fehlertext („Keine Score angegeben“) ausgegeben. Wir müssen dem Browser dieses mal sagen, dass er etwas über POST übertragen soll. Dafür nehmen wir erst einmal nur HTML und erstellen ein Formular:

Datei: formular.html

<!DOCTYPE html>
<html>
<head>
     <title>Test Formular</title>
</head>
<body>
    <form action='highscore.php' method='POST'>
        Score: <input type='text' name='score'>
        Name: <input type='text' name='name'>
        <input type='submit'>
    </form>
</body>
</html>

Zuerst einmal siehst du das normale HTML Gerüst, dass dir vielleicht schon aus dem JavaScript Spiel bekannt ist. Im <body> gibt es dann ein Element namens <form>. Das sagt dem Browser, dass alles innerhalb dieses Elements zu einem Formular gehört und übertragen werden soll. action gibt die Datei an, an die übertragen werden soll (in unserem Fall die highscore.php) und method die Art der Übertragung (POST oder GET). Das nächste Element <input> sagt dem Browser, dass hier ein Textfeld (type='text') erscheinen soll. name='score' gibt diesem Textfeld noch einem Namen, damit der Inhalt dann in PHP als $_POST['score'] gesehen wird. Dasselbe passiert danach noch für den Namen.

Wenn du diese HTML-Datei hochlädst und aufrufst, kannst du eine Score eingeben, die dann über POST an die highscore.php gesendet wird.

Eine Datenbank (MYSQL) vorbereiten

Jetzt weißt du schon mal, wie du Daten (z.B. eine Highscore) an PHP senden kannst. Aber bisher wird die Highscore ja nur kurz ausgeben und direkt wieder gelöscht. Wir brauchen eine Möglichkeit alle Highscores, die jemals gesendet wurden, dauerhaft zu speichern. Dafür gibt es Datenbanken.

Eine Datenbank erstellen

Bevor wird die Daten speichern können, brauchen wir natürlich erst einmal eine Datenbank. Dafür gibt es ein praktisches Tool namens „phpMyAdmin“. Damit kann man ganz einfach eine Datenbank erstellen und manuell Einträge (Highscores) erstellen/bearbeiten und natürlich angucken. Auf bplaced, musst du bevor du phpmyadmin verwenden kannst erst einmal eine Datenbank anlegen (User Control Panel unter "MySQL-Datenbanken"). Dann findest du phpmyadmin unter http://phpmyadmin.deine-seite.bplaced.de (Eine Anleitung gibt es auch noch hier: http://eass.bplaced.net/127-Datenbankverwaltung) In Xampp befindet sich phpmyadmin unter http://localhost/phpmyadmin (MySQL muss vorher gestartet werden). Nach Login kann die Datenbank erstellt werden (Datenbanken ? Neue Datenbank anlegen ? Kollation)

Eine Tabelle erstellen

Eine Datenbank kann aus vielen verschiedenen Tabelle bestehen. Wir brauchen für die Highscore nur eine Tabelle. Wähle phpMyAdmin deine Datenbank aus und es müsste direkt nach einem Namen für eine neue Tabelle gefragt werden. Ich nenne diese Tabelle einfach mal „highscore“. Spalten nehmen wir erst einmal 3. Nach klick auf "Ok" werden wir nach Spalten gefragt. Füll die Werte einfach so aus, wie im Bild:

Zur Erklärung: Die erste Spalte wird "id" heißen. Jedem Highscore Eintrag wird damit eine eindeutige ID zugewiesen. Der Typ der der ID wird auf INT (Integer) gesetzt, was für eine ganze Zahl steht. Als Länge nehmen wir 255. Also kann die ID maximal 255 Stellen lang sein. Das entspricht auch direkt dem Maximalwert und sorgt dafür, dass wir nie zu wenig Ids haben. Das Attribut UNSIGNED schließt negative Zahlen aus. Index PRIMARY setzt die ID als Standard, um die Einträge zu identifizieren und A_I (Auto Increment) erhöht die ID automatisch bei jedem Eintrag um 1, damit wir uns darum nicht mehr kümmern müssen.

Die zweite Spalte "name" wird den Namen der Highscore enthalten und ist vom Typ VARCHAR, was ermöglicht beliebige Zeichen zu benutzen. Ich habe einfach mal 40 als Länge genommen, wodurch Namen maximal 40 Zeichen haben können.

Als letztes noch "score", was die Score als Zahl enthält. Deshalb wieder INT als Typ. Die Länge von 10 kannst du, je nach maximalen Stellen der Score anpassen. Hier auch wieder das Attribut UNSIGNED weil die Score nicht negativ werden kann.

Nach Klick auf Speichern wird die Tabelle erstellt und direkt angezeigt. Bei Klick auf Anzeigen werden die Einträge angezeigt. (Derzeit gibt es ja noch keine). Hier kannst du immer wieder zurück kommen und prüfen, ob Highscores eingetragen wurden.

Die Datenbank in PHP verwenden

Jetzt müssen wir die Datenbank nur noch in PHP benutzten, um die Highscores zu speichern.

Verbindung aufbauen

Als ersten Schritt bauen wir erst einmal eine Verbindung zu MySQL auf:

Datei: highscore.php

<?php

$db = new mysqli('localhost', 'dein-benutzer', 'dein-passwort', 'deine-datenbank');
if($db->connect_errno > 0)
{
    die('Konnte nicht mit MySQL verbinden. Fehler: ' . $db->connect_error);
}

$name_exists = isset($_POST['name']);
$score_exists = isset($_POST['score']);

if ($score_exists == true && $name_exists == true)
    echo 'Die Score für ' . $_POST['name'] . ' ist ' . $_POST['score'];
else
    echo 'Keine Score oder Name angegeben!';

?>

In Zeile 3 wird die Verbindung mit new mysqli aufgebaut und in $db gespeichert. Hier musst natürlich deine eigenen Daten eingeben. Das erste Argument "localhost" kannst du eigentlich so lassen. Hier muss nämlich die MySQL Adresse hinein, die auch bei bplaced "localhost" ist.

In der nächsten Zeile überprüfen wir, ob eine Verbindung aufgebaut werden konnte, oder es einen Fehler gab. Wenn es einen Fehler gab, wird das PHP-Skript sofort beendet (die) und die Fehlermeldung ausgegeben.

Das wars eigentlich auch schon. Ruf die highscore.php (ohne GET oder POST) mal direkt auf und guck, ob es einen MySQL Fehler gibt. Wenn nicht, dann hast du dich erfolgreich zu MySQL verbunden.

Tabelle füllen

Jetzt, wo die Verbindung zu MySQL aufgebaut ist, kannst du die Highscore in der Tabelle speichern

Datei: highscore.php

<?php

$db = new mysqli('localhost', 'dein-benutzer', 'dein-passwort', 'deine-datenbank');
if($db->connect_errno > 0)
{
    die('Konnte nicht mit MySQL verbinden. Fehler: ' . $db->connect_error);
}

$score_exists = isset($_POST['score']);
$name_exists = isset($_POST['name']);

if ($score_exists == true && $name_exists)
{
    $sql ="INSERT INTO highscore (name, score)
                VALUES (?, ?)";
    $stmt = $db->prepare($sql);

    if ($stmt === false)
        die('MySQL Fehler: ' . $db->error);

    $stmt->bind_param('si', $_POST['name'], $_POST['score']);
    $stmt->execute();

    echo 'Die Score für ' . $_POST['name'] . ' ist ' . $_POST['score'];
}
else
    echo 'Keine Score oder Name angegeben!';

?>

MySQL wird leider wieder mit einer anderen Sprache namens SQL angesprochen. Zum Glück ist die aber relativ leicht verständlich. In Zeile 14 schreiben wir die SQL Anweisung. Dieser SQL Text lässt sich fast 1 zu 1 ins Deutsche übersetzten (INSERT INTO highscore wird zu „füge in highscores ein“). Dann werden die Namen der Spalten in Klammern geschrieben (name,score) und dannach mit VALUES die Werte geschrieben. Eigentlich würden hier direkt die Werte auftauchen, aber hier werden die Werte einfach durch einen Fragezeichen Platzhalter ersetzt. Vielleicht hast du schon mal was von SQL-Injection gehört. Das könnte genau hier auftreten, wenn wir die Variablen direkt eingegeben hätten. Ein Angreifer könnte sonst einfach beliebige SQL Anweisungen hinein schreiben.

Aus diesem Grund verwenden wir erst einmal Platzhalter und lassen MySQL in der nächsten Zeile mit „prepare“ diese vorläufige Anweisung verarbeiten. Wenn hier ein Fehler auftritt, gibt die Funktion false zurück und wir geben wieder eine Fehlermeldung mit die() aus.

Jetzt können wir die Platzhalter von MySQL mit bind_param() ersetzen lassen. Der erste Parameter ('si') wirkt erst einmal verwirrend, ist aber eigentlich nur eine Abkürzung für die Art der Variablen, die wir ersetzten wollen. s steht für String (Text), weil der Name ja Text sein soll, und i für Integer (ganze Zahl), weil die Score eine Zahl ist. Daraus wird 'si'. Dann werden die Parameter in der Reiehenfolge in der sie die ? ersetzen sollen übergeben. Das erste ? Sollte der der Name (also $_POST['name']) sein und der zweite die Score.

Jetzt ist das SQL-Statement endlich komplett und kann mit execute() ausgeführt werden.

Wenn du in der formular.html jetzt einen Namen und eine Score auswählst, müsste der Eintrag in phpMyAdmin, nach Klick auf „Anzeigen“, angezeigt werden.

Der JavaScript Teil

Jetzt kann die Highscore durch ein Formular abgespeichert werden kann und im letzten Schritt können wir dieses Formular durch eine JavaScript Funktion ersetzten.

AJAX

Zur Verbindung zwischen JavaScript und PHP kommt AJAX in Spiel. Auch wenn die Verbindung einen Namen hat, ist sie trotzdem ziemlich kurz und einfach:

Datei: game.js

function save_highscore(score)
{
    var name = prompt('Dein Name:');

    var xhttp = new XMLHttpRequest();
    xhttp.onreadystatechange = function()
    {
        if (xhttp.readyState == 4 && xhttp.status == 200)
        {
           alert(xhttp.responseText);
        }
    };
    xhttp.open('POST', 'highscore.php', true);
    xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded")
    xhttp.send('name=' + name + '&score=' + score);
}

Als erstes fragt die Funktion mit „prompt“ nach dem Namen des Spielers und erstellt dann einen „XMLHttpRequest“. Das ist nichts anderes als eine Verbindung zu einer Datei, oder in unserem Fall zum PHP Skript. Im nächsten Schritt sagen wir dem Browser, dass er die Antwort vom PHP Skript ausgeben soll (alert), sobald die Verbindung einen neuen Status hat (onreadystatchange) und das PHP Skript fertig ist (readyState == 4 && xhttp.status == 200).

Füge diese Funktion einfach ein dein Spiel ein und rufe die Funktion auf, sobald das Spiel zu Ende ist.

Das wars eigentlich auch schon, du kannst jetzt erfolgreich Highscores in einer Datenbank speichern. Jetzt fehlt nur noch eine Liste mit vorhanden Highscores, die im Spiel angezeigt werden kann. Highscore Liste anzeigen Für die Anzeige können wir diesmal einen einfache GET Request benutzen. Es müssen ja keine Informationen übertragen werden, außer evtl. die Seite.

Datei: highscore.php

<?php

$db = new mysqli('localhost', 'dein-benutzer', 'dein-passwort', 'deine-datenbank');
if($db->connect_errno > 0)
{
    die('Konnte nicht mit MySQL verbinden. Fehler: ' . $db->connect_error);
}

if (isset($_GET['show']))
{
    $sql = "SELECT * from highscore ORDER BY score DESC";
    $highscores = $db->query($sql);

    if ($highscores  ===  false)
    die('MySQL Fehler: ' . $db->error);

    while ($highscore = $highscores->fetch_object())
    {
        echo $highscore->name . ": " . $highscore->score;
        echo "<br>";
    }
}
else
{
     $score_exists = isset($_POST['score']);
     $name_exists = isset($_POST['name']);

     if ($score_exists == true && $name_exists)
     {
         $sql ="INSERT INTO highscore (name, score)
                    VALUES (?, ?)";
        $stmt = $db->prepare($sql);

        if ($stmt === false)
             die('MySQL Fehler: ' . $db->error);

        $stmt->bind_param('si', $_POST['name'], $_POST['score']);
        $stmt->execute();

        echo 'Die Score für ' . $_POST['name'] . ' ist ' . $_POST['score'];
    }
    else
        echo 'Keine Score oder Name angegeben!';
}

?>

Alle Änderungen sind im if Block (if (isset($_GET['show']))), Der Rest ist jetzt im else Block und gleich geblieben. Dadurch wird die Highscore wie gewohnt gespeichert, wenn das PHP-Skript nicht gerade mit "highscore.php?show" aufgerufen wird. Denn nur dann wird die Highscore Liste angezeigt.

Zuerst erstellen wir wieder eine SQL Abfrage. Diesmal rufen wir alle vorhanden Einträge mit SELECT * from highscore auf. Wir möchten die Liste dann noch sortieren, so dass die höchste Score oben ist (ORDER BY score DESC). Das DESC steht für Absteigend. Diesmal brauchen wir die Abfrage mit mit prepare() vorbereiten, weil es keine Variablen im SQL gibt. Wir führen die Anweisung also direkt mit query() aus.

Wenn es einen Fehler gab, wird der Fehler wieder mit die() ausgegeben und das Skript abgebrochen. Sonst gehen wir alle Highscore Einträge in einer Schleife durch und geben sie mit echo aus.

Wenn du die das Skript jetzt mit http://deine-seite/highscore.php?show aufrufst, müssten alle aktuellen Einträge ausgegeben werden. Also die selben, die auch in phpmyadmin zu sehen sind. Im Spiel kannst du dann auf diese Seite verweisen.

Damit funktioniert alles und die Highscore Liste kann benutzt werden.

Um Kommentare schreiben zu können, musst du eingeloggt sein!

Login
17.07.2016 12:38
Kim
Vielen Dank. Hat mir sehr weitergeholfen :)
27.08.2016 10:26
Louis
Sry, aber bei mir klappt es nicht. Ich verliere die Übersicht bei Sachen wie MySQL :(. Der sagt immer dass es einen Fehler gab beim Verbindungsaufbau
27.08.2016 10:52
Jan
@Louis Hört sich so an als ob MySQL nicht gestartet/verfügbar ist. Konntest du dich denn mit phpmyadmin verbinden?
27.08.2016 10:59
Louis
@Jan ja also ich habe alles befolgt wie es im Tutorial stand und dann habe ich halt benutzer und passwort und so in der .php Datei verändert aber es kommt immer folgende Meldung:


Warning: mysqli::__construct(): (HY000/2002): Ein Verbindungsversuch ist fehlgeschlagen, da die Gegenstelle nach einer bestimmten Zeitspanne nicht richtig reagiert hat, oder die hergestellte Verbindung war fehlerhaft, da der verbundene Host nicht reagiert hat. in C:\xampp\htdocs\highscore.php on line 3
Konnte nicht mit MySQL verbinden. Fehler: Ein Verbindungsversuch ist fehlgeschlagen, da die Gegenstelle nach einer bestimmten Zeitspanne nicht richtig reagiert hat, oder die hergestellte Verbindung war fehlerhaft, da der verbundene Host nicht reagiert hat.
27.08.2016 11:44
Jan
@Louis Hmm, es könnte vielleicht noch sein das die Firewall den Zugriff blockt. Aber dann sollte eigentlich phpmyadmin auch nicht gehen. Hast du als Adresse das "localhost" gelassen?
27.08.2016 14:39
Louis
@Jan ja habe ich. Bin ich vllt zu dumm dafür? Muss man vllt doch noch irgendetwas anders machen? Kenne mich leider NULL mit php aus, habe auch schon im Internet nach php geguckt. Muss ich evtl noch etwas ändern?
27.08.2016 17:13
Louis
@Jan soll ich dir vllt mal einen screenshot schicken damit du gucken kannst ob irgendwo ein Fehler ist? Ich habe ihn jedenfalls nicht gefunden!
27.08.2016 19:10
Jan
Sende am besten mal Screenshots vom xampp control panel, der fehlermeldung und der php datei an jan@nexttrex.de