MMProg: Praktikum: WiSe 2017/18: Ball03b

aus GlossarWiki, der Glossar-Datenbank der Fachhochschule Augsburg

Dieser Artikel erfüllt die GlossarWiki-Qualitätsanforderungen nur teilweise:

Korrektheit: 3
(zu größeren Teilen überprüft)
Umfang: 4
(unwichtige Fakten fehlen)
Quellenangaben: 3
(wichtige Quellen vorhanden)
Quellenarten: 5
(ausgezeichnet)
Konformität: 3
(gut)

MMProg-Praktikum

Inhalt | Game Loop 01 | Ball 02 | Ball 03 | Ball 03b | Pong 01

Musterlösung: SVN-Repository

Ziel

In diesem Praktikum wird die im dritten Teils des Tutoriums begonnene Modularisierung des Projektes aus dem zweiten Teils des Tutoriums weitergeführt.

Aufgaben

Laden Sie das leere Projekt WK_Ball03b_empty auf Ihren Rechner. Installieren Sie aber nicht die Node.js-Module, das machen Sie später. Sie finden das leere Projekt im Repository-Pfad https://glossar.hs-augsburg.de/beispiel/tutorium/es6 im Unterordner empty.

Erstellen Sie ein neues Projekt praktikum03b und kopieren Sie die Ordner src und web (samt Inhalt) sowie alle Dateien, die Sie im Wurzelverzeichnis des Projektes WK_Ball03b_Empty finden, mittels Crtl-/Apfel-C Crtl-/Apfel-V in Ihr eigenes Projekt. (Die Frage, ob WebStorm seinen eigenen File Watcher zum Übersetzen von ES6-Code in ES5-Code verwenden soll, beantworten Sie bitte mit „No“. Das erledigt Webpack für Sie.)

Sie können Ihr Projekt zur Übung auch im Subversion-Repository speichern. Das ist aber nicht so wichtig.

Nun können Sie in Ihrem eigenen Projekt die benötigten Node.js-Module installieren: npm i.

In Ihrem Projekt finden Sie wiederum mehrere Web-Anwendungen: index01.html verwendet die gepackte Version von app01.js, die ihrerseits das Spiel game01/game.js einbindet. Et cetera. Die Web-Anwendung app00 basiert auf dem nicht-modularen Spiel game00.js, das in der vorherigen Praktikumsaufgabe teilweise modularisiert wurde. Eine Musterlösung der Praktikumsaufgabe MMProg: Praktikum: WiSe 2017/18: Ball03 finden Sie im Ordner src/js/app/game01 vor. Sie können zur Lösung der nachfolgenden Aufgaben natürlich auch auf IHre eigene Lösung der letzten PRaktikumsaufgabe zurückgreifen.

Schreiben Sie Ihre Lösungen der Aufgabe $i$ in die Ordner game$i$.js. Versuchen Sie möglichst viele Module der jeweils vorangegangenen Aufgabe wiederzuverwenden.

Aufgabe 1: Modularisierung des Modells

Klassendiagramm von app00 Klassendiagramm von app01
Klassendiagramm von app00
Klassendiagramm von app01

Machen Sie sich noch einmal klar, wie sich die Web-Anwendungen app00 und app01 unterscheiden.

Da der Code für beide Anwendungen in Ihrem Projekt bereits enthalten ist, brauchen Sie hier nichts zu implementieren.

Aufgabe 2: Modularisierung des Modells

Klassendiagramm von app01 Klassendiagramm von app02
Klassendiagramm von app01
Klassendiagramm von app02

Diese Aufgabe verfolgt zwei Ziele: Zum einen soll die Moularisierung voranschreiten und zum anderen soll JSON zum Initialisieren der Anwendung zum Einsatz kommen.

Klassendiagramm von app02 (mit Properties)

Beginnen Sie mit der Modularisierung. Wenn Sie die beiden obigen Diagramme vergleichen, stellen Sie fest, dass drei zusätzliche Module eingeführt werden: modelUpdate, viewUpdate und die Klasse Movable.

Kopieren Sie zunächst Code aus den bereits vorhandenen Module aus game01 in die zugehörigen Dateien von game02:

  • Die Datei game01/model/collision.js können Sie vollständig übernehmen.
  • Die in der Klasse Circle (game01/model/Circle.js) enthaltenen Methoden können Sie ebenfalls übernehmen. Beacten Sie allerdings, dass die Klasse jetzt MovableCircle heißt. Sie dürfen in der Datei game01/model/MovableCircle.js den Klassennamen und den Export-Befehl nicht ändern. Sie sollten in den vorgegebenen Klassenrahmen lediglich die kopierten Funktionen einfügen. Wenn Sie nun Grunt laufen lassen, werden Sie feststellen, dass ein Fehler gemeldet wird. Der Grund dafür ist, dass MovableCircle als Subklasse von Movable deklariert wurde (MovableCircle extends Movable), Der Konstruktor einer Subklasse muss immer den Konstruktor der zugehörigen Superklasse aufrufen. Dieser Aufruf muss als erster Befehl im Konstruktor stehen. Fügen Sie also den Befehl super(); in den Konstruktor von MovableCircle ein. Jetzt sollte Grunt den Code wieder fehlerfrei übersetzen können.
  • Die Datei game01/model/Stage.js können Sie ebenfalls vollständig übernehmen. Diese Datei wird erst in der nächsten Aufgabe angepasst.
  • Ebenso können Sie die Datei game01/view/ViewCircle.js können Sie in das neue Projekt kopieren. Diese Datei wird im Folgenden noch etwas vereinfacht, aber notwendig ist das nicht unbedingt.
  • Zu guter Letzt können Sie die let-Anweisung und die drei Funktionsdefinitionrn init, modelUpdates und viewUpdates aus der Datei game01/game.js ind die Datei game02/game.js kopieren (ohne die Import- und den Exportbefehl zu verändern). Grunt sollte jetzt das Projekt übersetzen können, aber wenn Sie es starten, sehen Sie nur eine leere Bühne. Sie müssen in dieser Datei (game02/game.js) noch ein paar Anpassungen vornehmen:
    • new Stage muss durch new ModelStage ersetzt werden, da die Klasse Stage jetzt unter diesem Namen importiert wird.
    • new Circle muss durch new ModelCircle aus dem gleichen Grund ersetzt werden.
    • Die Init-Funktion muss angepasst werden:
      • Sie erwartet andere Parameter (vergleichen Sie die Parameterlisten von init in den Klassendiagrammen von app01 und app02). Ersetzen Sie also die Parameterliste von init durch die korrekte Parameterliste
        p_pixi, p_canvas, p_config, f_ready
        
        .
      • Sie Parameter p_pixi und p_canvas gibt es immer noch, der Parameter p_stage ist weggefallen (er hatte die Größenparameter der Bühne enthalten), dafür sind p_config und p_ready hinzugekommen. Im Parameter p_config übergibt die Hauptanwendung app02 den Inhalt der Konfigurationsdatei json/config02.json. In diesem Objekt sind insbesondere auch die Größenparameter der Bühne enthalten. Und die Funktion f_ready muss aufgerufen werden, sobald die Initialisierung vollständig erfolgt ist (vgl. Praktikumsausgabe „Ball02“, Aufgabe 3).
      • Passen Sie daher die die ersten beiden Befehle der Init-Funktion an:
        v_stage.width = p_config.model.stage.width;
        
        sowie
        v_stage.height = p_config.model.stage.height;
        
      • Fügen Sie nun noch den Aufruf f_ready(); als letzten Befehl in die Init-Funktion ein. Nun sollte die Anwendung (nach einer Übersetzung mittels Grunt) im Browser wieder laufen.

Wie man eine JSON-Datei lädt und darauf zugreift wurde ebenfalls schon in der Praktikumsausgabe „Ball02“, Aufgabe 3 behandelt. Allerdings wurde dort die JSON-Datei direkt von der Datei game01.js importiert. Hier wird die JSON-Datei json/config02.json dagegen von der App-Datei app02.js importiert und dann an die Init-Funktion in der Datei game02/game.js weitergegeben. Dieses Vorgehen bringt mehrere Vorteile mit sich:

  • Man kann auf spezielle Konfigurationsparameter wie p_stage verzichten. Die App-Datei übergibt alle Konfigurationsinformationen in einen einzigen Objekt (namens p_config) an die Init-Funktion.
  • Die App-Datei liest die Konfigurationsinformationen üblicherweise aus einer JSON-Datei ein. Sie kann das JSON-Objekt aber noch um Informationen ergänzen, die erst zu Laufzeit feststehen, wie z. B. die aktuelle Größe der Bühne. Schauen Sie sich die Datei json/config02.json einmal an. Darin stehen im Stage-Objekt keine knkreten Größenangaben, sondern die Zeichenketten "@width" und "@height". Diese werden, nachdem das JSON-Objekt innerhalb der Datei app02 geladen wurde, mit Hilfe der Funktion concretize („konkretisiere“) durch die aktuelle Größe des Browserfensters ersetzt. Diese Funktion finden Sie in der Datei lib/wk/Util.js. Sie ist noch wesentlich mächtiger, wie sie im Laufe des Praktikums lernen werden. Sie kann z. B. die Position, Geschwindigkeit oder Beschleunigung eines beweglichen Objektes mit zufälligen Werten initialisieren. Sehen Sie sich doch einfach einmal die anderen JSON-Dateien im Ordner json an, damit Sie einen Eindruck davon bekommen, für was man diese Funktion noch einsetzen kann. (Sie müssen die einzelnen @-Anweisungen jetzt noch nicht verstehen; geldulden Sie sich noch etwas.)
  • Man könnte problemlos eine zweite Anwendungsdatei app02a schreiben, die einfach eine andere JSON-Datei einliest, aber wieder dieselbe Datei game02/game.js einbindet, um das Spiel auszuführen. Das heißt, man kann game02/game.js für ganz viele verschiedene Konfigurationsdateien wiederverwenden, ohne in den Dateien im Ordner game02 eine einzige Zeile Code ändern zu müssen. Üblicherweise würde man natürlich nicht lauer verschiedene Anwendungsdateien app02a, app02b , app02c, app02d etc. erstellen, die jeweils nur eine andere JSON-Datei einlesen würde (das wäre wahrlich nicht DRY), sondern man würde einen Level-Mechanismus programmieren, der jedesmal, wenn ein Level fertiggespielt wurde, die JSON-Datei des nächsten Levels einlesen und dann das Spiel mit dieser Konfigurationsdatei neu starten würde.

Damit der soeben beschrieben Vorteil der Konfigurationsdatei config02.json auch zum tragen kommt, muss man die darin vorgegebene Werte natürlich auch in der Datei game.js verwenden.

Ersetzen Sie in der let-Anweisung die Definition

v_ball  = new ModelCircle(...)

durch

v_ball  = null

und fügen Sie dafür den Befehl

v_ball  = new ModelCircle(p_config.model.ball)

in die Initfunktion ein. Ersetzen Sie außerdem in der Initfunktion den Befehl

v_ball  = null

und fügen Sie dafür den Befehl

v_ball_view = new ViewCircle(p_pixi, p_canvas, v_ball, p_config.view.ball);

Nun können Sie die Werte in der Datei config02.json probehalber einmal ändern. Es sollte sich auch das Verhalten und oder das Aussehen des Balls auf der Bühne entsprechend ändern. Sie können versuchsweise auch einmal die Größe der Bühne auf feste Maße festlegen.

Jetzt können Sie versuchshalber eine Web-Anwendung index02a.html plus app02a erstellen, die dasselbe Spiel game02mit einer anderen JSON-Datei ausführt. Vergessen Sie nicht, diese Anwendung in die die Datei webpack.config.js einzutragen und Grunt anschließend neu zu starten. Sehen Sie sich einmal die Musterlösung zun dieser Aufgabe an. Dort wurde eine Bühne mit Rand defieniert, die mit Hilfe von CSS in die Mitte des Bildschirms verschoben wurde. Das funktioniert natürlich auch für eine Bühne fester Größe. (Nicht für jedes Spiel ist eine Bühne geeignet, deren Größe von der Größe des Brwoserfesnters abhängt.)

So, nun ist es an der Zeit, die fehlenden Module zu erstellen.

Quellen

  1. Kowarschick (MMProg): Wolfgang Kowarschick; Vorlesung „Multimedia-Programmierung“; Hochschule: Hochschule Augsburg; Adresse: Augsburg; Web-Link; 2018; Quellengüte: 3 (Vorlesung)