MMProg: Praktikum: WiSe 2018/19: Ball01: Unterschied zwischen den Versionen

aus GlossarWiki, der Glossar-Datenbank der Fachhochschule Augsburg
Keine Bearbeitungszusammenfassung
Keine Bearbeitungszusammenfassung
(39 dazwischenliegende Versionen von 2 Benutzern werden nicht angezeigt)
Zeile 1: Zeile 1:
{{MMProg:Praktikum:WiSe 2018/19:Menü}}
{{MMProg:Praktikum:WiSe 2018/19:Menü}}


'''Musterlösung''': [https://glossar.hs-augsburg.de/beispiel/tutorium/es6/ball/WK_Ball01/ Git-Repository] ('''noch nicht online''')
'''Musterlösung''': [https://glossar.hs-augsburg.de/beispiel/tutorium/2018/ball/WK_Ball01/web/ Web-Auftritt] ([https://gitlab.multimedia.hs-augsburg.de/kowa/WK_Ball01.git Git-Repository])  
{{In Bearbeitung}}
==Vorbereitung==
==Vorbereitung==


Im Git-Repository finden Sie zwei WebStorm-Projekte zum Thema GameLoop:
Im Git-Repository finden Sie zwei WebStorm-Projekte zum Thema GameLoop:
* [https://gitlab.multimedia.hs-augsburg.de:8888/kowa/WK_GameLoop01.git WK_GameLoop01]
* [https://gitlab.multimedia.hs-augsburg.de/kowa/WK_GameLoop01.git WK_GameLoop01]
* [https://gitlab.multimedia.hs-augsburg.de:8888/kowa/WK_GameLoop02.git WK_GameLoop02]
* [https://gitlab.multimedia.hs-augsburg.de/kowa/WK_GameLoop02.git WK_GameLoop02]
 
Sie können diese Projekte folgendermaßen auf Ihrem Rechner installieren:
 
* <code>VCS</code> → <code>Checkout from Version Control</code> → <code>Subversion</code>
* Sofern noch nicht geschehen: Klick auf das grüne Plus-Symbol → Repository URL: <code>https://glossar.hs-augsburg.de/beispiel/tutorium/es6</code>
* Klick auf die Pfeilspitze vor diesem Pfad → Klick auf die Pfeilspitze vor <code>game_loop</code> → Klick '''auf''' <code>WK_GameLoop02</code>
* <code>Checkout</code> (<code>WK_GameLoop01</code> dient nur didaktischen Zwecken und wird für diese Praktikumsaufgabe nicht benötigt.)
* Speichern Sie das Projekt irgendwo auf Ihrem Rechner. '''Achtung: Speichern Sie das Projekt nicht innerhalb eines anderen Projektes (insbesondere nicht in Ihrem neuen Projekt) oder innerhalb eines Ordners, der bereits unter SVN-Kontrolle steht. Speichern meine Projekte in einem ganz anderen Ordner, der {{zB}} <code>KowaBeispiele</code> heißen könnte.'''
* Öffnen Sie das Projekt und geben Sie im WebStorm-Terminal <code>npm install</code> (oder kurz <code>npm i</code>) ein, um alle benötigten Node.js-Module zu installieren.


Machen Sie sich mit den Projekten vertraut. Die Web-Anwendung <code>src/js/app</code> des zweiten Projektes dient als Ausgangsbasis für diese Praktikumsaufgabe.     
Machen Sie sich mit den Projekten vertraut. Die Web-Anwendung <code>src/js/app</code> des zweiten Projektes dient als Ausgangsbasis für diese Praktikumsaufgabe.     
Zeile 24: Zeile 14:
Lösungen im Zusammenhang mit JavaScript-Animationen zu verdeutlichen.
Lösungen im Zusammenhang mit JavaScript-Animationen zu verdeutlichen.


Im zweiten Beispiel wurde eine einfache Game-Loop-Klasse realisiert, die sie für dieses Praktikum
Im zweiten Beispiel wurde eine Game-Loop-Klasse realisiert, die sie für dieses Praktikum
nutzen können und sollten. Diese Klasse basiert auf den Ergebnissen des ersten Projektes,
nutzen können und sollten. Diese Klasse basiert auf den Ergebnissen des ersten Projektes,
stellt aber – im Gegensatz zu einigen Web-Anwendungen des ersten Projekt – bislang keine Informationen  
stellt aber – im Gegensatz zu einigen Web-Anwendungen des ersten Projekt – bislang keine Informationen  
über die aktuelle Frame-Rate bereit. Dies ist aber für diese Praktikumsaufgabe nicht von Interesse.
über die aktuelle Frame-Rate bereit. Dies ist aber für diese Praktikumsaufgabe nicht von Interesse.


==Aufgaben==
Importieren Sie das leere Git-Projekt [https://gitlab.multimedia.hs-augsburg.de/kowa/Ball01.git Ball01] in WebStorm.
Laden Sie annschließend mittels <code>npm i</code> alle benötigten Node.js-Module in das Projekt.


Laden Sie das leere Projekt [https://glossar.hs-augsburg.de/beispiel/tutorium/es6/empty/WK_GameLoop02_Empty WK_GameLoop02_Empty] auf Ihren Rechner
Sie können Ihr Projekt zur Übung auch in Ihrem Git-Repository speichern. Das ist aber nicht so wichtig.
(am Besten in den zuvor angelegten Ordner <code>KowaBeispiele</code>).
Falls Sie dies machen möchten, müssen Sie es zuvor von meinem (schreibgeschützten) Repository lösen:
'''Installieren Sie diesmal aber nicht die Node.js-Module''', das machen Sie später. Sie finden das leere Projekt im zuvor aktivierten
Repository-Pfad <code>https://glossar.hs-augsburg.de/beispiel/tutorium/es6</code> im Unterordner <code>empty</code>.


Erstellen Sie ein neues Projekt <code>praktikum01</code> und kopieren Sie die Ordner <code>src</code> und <code>web</code> (samt Inhalt)
<source lang="javascript">
sowie alle Dateien, die Sie im Wurzelverzeichnis des Projektes <code>WK_GameLoop02_Empty</code>
git remote remove origin
finden, mittels <code>Ctrl-/Apfel-C</code> <code>Ctrl-/Apfel-V</code> in Ihr eigenes Projekt. (Die Frage, ob WebStorm seinen eigenen File Watcher zum
git remote add origin https://gitlab.multimedia.hs-augsburg.de/BENUTZER/Ball01.git
Übersetzen von ES6-Code in ES5-Code verwenden soll, beantworten Sie bitte mit „No“. Das erledigt Webpack für Sie.)
</source>


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


Nun können Sie in Ihrem eigenen Projekt die benötigten Node.js-Module installieren: <code>npm i</code>.
In Ihrem Projekt finden Sie 10 Web-Anwendungen vor: <code>index01.html</code> verwendet die JavaScript-Datei <code>app01.js</code>,
die ihrerseits das Spiel <code>ball01.js</code> einbindet. <code>index02.html</code>, <code>index03.html</code> etc. sind analog aufgebaut.
Wenn Sie irgendeine dieser Anwendungen im Browser öffnen, sehen Sie eine Eule in der linken oberen Bildschirmecke. Diese sollen
sie auf unterschiedliche Art und Weise animieren. Beachten Sie, dass im Folgenden der Avatar nicht „Eule“, sondern „Ball“ genannt wird.
Die Eule ist lediglich eine View des ballartigen Objektes.


In Ihrem Projekt finden Sie nun 10 Web-Anwendungen vor: <code>index01.html</code> verwendet die gepackte Version von <code>app01.js</code>,
Lösen Sie jede der folgenden Aufgaben in einer der vorgegebenen Apps.
die ihrerseits das Spiel <code>game01.js</code> einbindet. <code>index02.html</code>, <code>index03.html</code> etc. sind analog aufgebaut.
Wenn Sie irgendeine dieser Anwendungen im Browser öffnen, sehen Sie eine Eule in der linken oberen Bildschirmecke. Diese sollen
sie auf unterschiedliche Art und Weise animieren. Lösen Sie jede der folgenden Aufgaben in einer der vorgegebenen Apps.
Scheuen Sie sich nicht davor, eigene Experimente durchzuführen. Wenn die vorgegebenen Apps nicht ausreichen sollten, legen Sie einfach
Scheuen Sie sich nicht davor, eigene Experimente durchzuführen. Wenn die vorgegebenen Apps nicht ausreichen sollten, legen Sie einfach
noch ein paar an. (Vergessen Sie in diesem Fall nicht, <code>webpack.config.js</code> entsprechend zu erweitern.)
noch ein paar an.


Schreiben Sie Ihre Lösungen der Aufgabe $i$ in die Datei <code>game</code>$i$<code>.js</code>.
Schreiben Sie Ihre Lösungen der Aufgabe $i$ in die Datei <code>src/js/ball/ball</code>$i$<code>.js</code>.
Am einfachsten ist es, wenn Sie jeweils die Lösung der vorangegangenen Aufgabe kopieren und diese Kopie dann weiterentwickeln.
Am einfachsten ist es, wenn Sie jeweils die Lösung der vorangegangenen Aufgabe kopieren und diese Kopie dann weiterentwickeln.


===Aufgabe 1===
===Aufgabe 1===
Passen Sie zur Lösung dieser Aufgabe die Datei <code>src/js/ball/ball01.js</code> an.
Lassen Sie sich durch den Code der Datei <code>ball.js</code> aus dem Beispiel <code>WK_GameLoop02</code> inspirieren.
(Sie könnten auch <code>ball_interpolate.js</code> verwenden, aber das verwirrt Sie vermutlich zurzeit deutlich mehr, als dass es
Ihnen nützt.)


Lassen Sie die Eule horizontal vom linken bis zum rechten Fensterrand des Browsers fliegen.  
'''Lassen Sie den Ball horizontal vom linken bis zum rechten Fensterrand des Browsers fliegen.'''


Tipp: http://ryanve.com/lab/dimensions/
Tipp: http://ryanve.com/lab/dimensions/


Berücksichtigen Sie, dass die Eule 150 Pixel breit ist und das der Ankerpunkt im linken oberen Eck des zugehörigen Bildes liegt.  
Berücksichtigen Sie, dass der Ball 150 Pixel breit ist, {{dh}} einen Radius von 75 Pixel hat,
Sie müssen daher im Eulen-Objekt auch die Breite der Eule speichern und diese Breite bei der Kollissionserkennung
und dass der Ankerpunkt im linken oberen Eck des zugehörigen Bildes liegt.  
und -behandlung berücksichtigen.
Sie müssen im Ball-Objekt auch die Radius des Balls speichern und diesen Wert bei der Kollissionserkennung
und -behandlung berücksichtigen. Übrigens, wenn Sie <code>v_ball_view</code> wie in <code>ball.js</code>
von <code>WK_GameLoop02</code> definieren, können Sie mittels <code>v_ball_view.offsetWidth/2;</code>
die aktuelle Breite des Ballobjektes aus der View auslesen.


Beachten Sie bitte, dass Sie zur Lösung dieser Aufgabe einfach die Datei <code>game01.js</code> anpassen müssen.
Ein Tipp noch: Wenn Sie das Ball-Objekt zunächst als leeres Objekt definieren und danach in der
Lassen Sie sich durch den Code der Datei <code>owl.js</code> aus dem Beispiel <code>WK_GameLoop02</code> inspirieren.
Reset-Funktion initialisieren, funktionieren Ihre Anwendungen auch noch, wenn Sie später einen
(Sie können auch <code>owl_interpolate.js</code> verwenden, aber das verwirrt Sie vermutlich zurzeit mehr, als dass es
Start/Stopp- und einen Pause-Button einfügen (vgl. {{zB}} <code>index_start_stop_toggling.html</code> in <code>WK_GameLoop02</code>).  
Inhen nützt.) Eine Reset-Funktion, wie sie im genannten Beispiel definiert wird, brauchen Sie nicht zu implementieren,
Sollten Sie keine Buttons zur Steuerung einfügen wollen, können Sie die Objekte auch direkt bei
da Sie das „Spiel“ nicht mit Hilfe von irgendwelchen Buttons anhalten und zurücksetzen werden. Dies gilt auch für alle folgenden
der Definition initialisieren.
Aufgaben.


Vergessen Sie <code>grunt</code> oder besser noch <code>grunt watch</code> nicht. :-)
Vergessen Sie nicht, die Sourcen mittels <code>npm run watch</code> zu übersetzen. Und beachten Sie,
dass im Browser nur die Dateien <code>web/index</code>$i$<code>.html</code> funktionieren. Wenn Sie versuchen,
<code>src/index</code>$i$<code>.html</code> erhalten Sie im Browser einen leeren Screen und in der Browser-Konsole drei Fehlermeldungen,
dass gewissen Dateien nicht geladen werden können.


===Aufgabe 2===
===Aufgabe 2===


Lassen Sie die Eule nicht waagerecht, sondern in der horizontalen Mitte des Browserfensters senkrecht von Fenstrrand zu Fensterrand fliegen.
Lassen Sie den Ball nicht waagerecht, sondern in der horizontalen Mitte des Browserfensters senkrecht von Fensterrand zu Fensterrand fliegen.


Um die Aufgabe zu lösen, müssen Sie für die Eule zusätzlich eine y-Position und eine y-Geschwindigkeit definieren. Die Berechnung der aktuellen y-Position funktioniert
Um die Aufgabe zu lösen, müssen Sie für der Ball zusätzlich eine y-Position und eine y-Geschwindigkeit definieren. Die Berechnung der aktuellen y-Position funktioniert
analog zur Berechnung der aktuellen x-Position.  
analog zur Berechnung der aktuellen x-Position.  


Vergessen Sie nicht auch die Kollissionserkennung und -behandlung für die beiden Bildschirmseiten <code>top</code> und <code>botton</code>
Vergessen Sie nicht, auch die Kollissionserkennung und -behandlung für die beiden Bildschirmseiten <code>top</code> und <code>botton</code>
zu implementieren.
zu implementieren.


Und Sie müssen natürlich die Render-Funktion anpassen, sodass die aktuelle y-Position beim Rendern auch berücksichtigt wird.  
Und Sie müssen natürlich die Render-Funktion anpassen, sodass die aktuelle y-Position beim Rendern auch berücksichtigt wird.


===Aufgabe 3===
===Aufgabe 3===


Lassen Sie die Eule von der Browsermitte aus schräg über den Bildschirm fliegen. In x-Richtung soll sie doppelt so schnell sein (200 Pixel/s)
Lassen Sie der Ball von der Mitte des Browserfensters aus schräg über den Bildschirm fliegen. In x-Richtung soll er doppelt so schnell sein (200 Pixel/s)
wie in y-Richtung (100 Pixel/s).
wie in y-Richtung (100 Pixel/s).


===Aufgabe 4===
===Aufgabe 4===


Setzen Sie die x-Start-Position der Eule auf <code>-100</code> und starten Sie die Web-App. Den Effekt, den Sie sehen, nennt
Setzen Sie die x-Start-Position des Balls auf <code>-100</code> und starten Sie die Web-App. Den Effekt, den Sie sehen, nennt
man [[Kollisionserkennung und -behandlung|Penetration]]. Die Eule hängt in der Wand fest, da Sie in einem Schritt nicht den Kollissionsbereich
man [[Kollisionserkennung und -behandlung|Penetration]]. Die Eule hängt in der Wand fest, da sie nicht den Kollissionsbereich
(die linke Wand) verlässt. Daher besteht die Kollission fort und im nächsten Schritt ändert sie wieder ihre Flugrichtung.
(die linke Wand) in einem Schritt verlässt. Daher besteht die Kollission fort und im nächsten Schritt ändert sie wieder ihre Flugrichtung.


Verbessern Sie das, indem Sie die Kollisionserkennung und -behandlung verbessern:
Verbessern Sie das, indem Sie die Kollisionserkennung und -behandlung verbessern:


<source lang="javascript">
<source lang="javascript">
if (v_owl.x <= v_stage.left)
if (v_ball.x <= v_stage.left)
{
{ v_ball.vx = Math.abs(v_ball.vx);
  v_owl.vx = Math.abs(v_owl.vx);
}
}
if (v_owl.x >= v_stage.right - v_owl.width)
if (v_ball.x >= v_stage.right - 2*v_ball.r)
{
{ v_ball.vx = -Math.abs(v_ball.vx);
  v_owl.vx = -Math.abs(v_owl.vx);
}
}
</source>
</source>
Zeile 112: Zeile 109:
Passen Sie die Kollisionserkennung und -behandlung in y-Richtung analog an.  
Passen Sie die Kollisionserkennung und -behandlung in y-Richtung analog an.  


Sie können und sollten sogar noch einen Schritt weiter gehen und die Eule
Sie können und sollten sogar noch einen Schritt weiter gehen und den Ball
wieder zurück auf die Bühne schieben, wenn Sie in die Wand eingedrungen ist.
wieder zurück auf die Bühne schieben, wenn er in die Wand eingedrungen ist.
In die Wand einzudringen ist zwar physikalisch nicht möglich, aber leider in
In die Wand einzudringen ist zwar physikalisch nicht möglich, aber leider in
einer Simulation der physikalischen Welt nur schwer zu vermeiden, da die
einer Simulation der physikalischen Welt nur schwer zu vermeiden, da die
Position nur alle 16,7 ms berechnet wird. War die Eule zu einem Zeitpunkt
Position nur alle 16,7 ms berechnet wird. War der Ball zu einem Zeitpunkt
noch vor der Mauer, kann Sie beim nächsten Schritt schon drinnen stecken.
noch vor der Mauer, kann er beim nächsten Schritt schon drinnen stecken.
Insbesondere bei sehr schnellen Objekten kann das dann zu PEnetrations-Effekten führen.
Insbesondere bei sehr schnellen Objekten kann das dann zu den
beobachteten Penetrationseffekten führen.


Also schieben Sie die Eule besser zurück auf die Bühne.
Also schieben Sie den Ball besser zurück auf die Bühne.


<source lang="javascript">
<source lang="javascript">
if (v_owl.x <= v_stage.left)
if (v_ball.x <= v_stage.left)
{
{ v_ball.x = v_stage.left;
  v_owl.x = v_stage.left;
   v_ball.vx = Math.abs(v_ball.vx);
   v_owl.vx = Math.abs(v_owl.vx);
}
}
if (v_owl.x >= v_stage.right - v_owl.width)
if (v_ball.x >= v_stage.right - 2*v_ball.r)
{
{ v_ball.x = v_stage.right - 2*v_ball.r;
  v_owl.x = v_stage.right - v_owl.width;
   v_ball.vx = -Math.abs(v_ball.vx);
   v_owl.vx = -Math.abs(v_owl.vx);
}
}
</source>
</source>


Passen Sie die Kollisionserkennung und -behandlung in y-Richtung wiederum analog an.  
Passen Sie die Kollisionserkennung und -behandlung in y-Richtung wiederum analog an.


===Aufgabe 5===
===Aufgabe 5===


Ändern Sie die Kollisionserkennung und -behandlung so ab, dass die Eule ausgehend von der linken oberen Fensterecke
Ändern Sie die Kollisionserkennung und -behandlung so ab, dass sich der Ball ausgehend von der linken oberen Fensterecke
im Uhrzeigersinn sich immer entlang des Fensterrandes bewegt.
im Uhrzeigersinn immer entlang des Fensterrandes bewegt.


Beachten Sie bitte: Hier ist es besonders wichtig, dass Sie die Eule wieder auf die Bühne zurückbewegen, wenn sie mit einer
Beachten Sie bitte: Hier ist es besonders wichtig, dass Sie den Ball wieder auf die Bühne zurückschieben, wenn er mit einer
Wand kollidiert. Ansonsten verschwindet die Eule schnell im Nirgendwo.
Wand kollidiert. Ansonsten verschwindet der Ball schnell im Nirgendwo.


(Anmerkung: Dies war einmal eine Aufgabe im Rahmen des Prüfungspraktikums, wobei die Lösung zur 3. Aufgabe vorgegeben war.)
(Anmerkung: Dies war einmal eine Aufgabe im Rahmen des Prüfungspraktikums, wobei die Lösung zur 3. Aufgabe vorgegeben war.)
Zeile 149: Zeile 145:
===Aufgabe 6===
===Aufgabe 6===


Kopieren Sie diesmal nicht die Lösung von Aufgabe 5, sondern von Aufgabe 4. Im folgenden arbeiten Sie
Kopieren Sie diesmal nicht die Lösung von Aufgabe 5, sondern die von Aufgabe 4. Im Folgenden arbeiten Sie
wieder mit der normalen Kollissionserkennung und -behandlung. Positionieren Sie die Eule allerdings wieder im linken oberen Eck
wieder mit der normalen Kollissionserkennung und -behandlung. Positionieren Sie den Ball allerdings wieder im linken oberen Eck
(in Aufgabe 4 hatten Sie sie außerhalb der Bühne platziert).
(in Aufgabe 4 hatten Sie sie außerhalb der Bühne platziert).


Die neue Position der Eule berechnet man mit Hilfe der Geschwindigkeit (velocity). Doch auch die
Die neue Position des Balls berechnen Sie mit Hilfe der Geschwindigkeit (velocity, <code>vx</code>, <code>vy</code>). Doch auch die
Geschwindigkeit kann sich ändern. Dazu benötigt man die Beschleunigung (acceleration).
Geschwindigkeig kann sich im Laufe der Zeit ändern. Dazu benötigt man die Beschleunigung (acceleration, <code>ax</code>, <code>ay</code>).


Fügen Sie zu Ihrer Eule zwei weitere Attribute <code>ax</code> (Beschleunigung in x-Richtung) und  
Fügen Sie zu Ihrem Ball  zwei weitere Attribute <code>ax</code> (Beschleunigung in x-Richtung) und  
<code>ay</code> (Beschleunigung in y-Richtung) hinzu. Setzen Sie die Initialwerte auf
<code>ay</code> (Beschleunigung in y-Richtung) hinzu. Setzen Sie die Initialwerte auf
<code>400</code> (Pixel pro Sekunde) bzw. <code>200</code> (Pixel pro Sekunde). Das heißt, Sie möchten,
<code>400</code> (Pixel pro Sekunde) bzw. <code>200</code> (Pixel pro Sekunde). Das heißt, Sie möchten,
dass die Eule in jeder Sekunde um 400 bzw. 200 Pixel pro Sekunde mehr zurücklegt als zuvor.
dass der Ball in jeder Sekunde um 400 bzw. 200 Pixel pro Sekunde mehr zurücklegt als zuvor.


Wenn Sie jetzt die Web-App starten, beschleunigt die Eule allerdings noch nicht.
Wenn Sie jetzt die Web-App starten, beschleunigt der Ball allerdings noch nicht.


In Ihrem Code wird die Position 60 mal pro Sekunde mit Hilfe des folgenden Codes aktualisiert:
In Ihrem Code wird die Position 60 mal pro Sekunde mit Hilfe des folgenden Codes aktualisiert:


<source lang="javascript">
<source lang="javascript">
v_owl.x += v_owl.vx * p_frac_s;
v_ball.x += v_ball.vx * p_delta_s;
v_owl.y += v_owl.vy * p_frac_s;
v_ball.y += v_ball.vy * p_delta_s;
</source>
</source>


Die Geschwindigkeit wird zur Position hinzuaddiert. Allerdings ist die Geschwindigkeit
Die Geschwindigkeit wird zur Position hinzuaddiert. Allerdings ist die Geschwindigkeit
in Pixeln pro Sekunde angegeben. Die Modellaktualisierung passiert jedoch alle $0,0167$
in Pixeln pro Sekunde angegeben. Die Modellaktualisierung passiert jedoch alle $0,0167$
Sekunden. In dieser Zei bewegt sich die Eule nur um das $0,0167$-fache (= $1,67$%) der Sekundengeschwindigkeit weiter.
Sekunden. In dieser Zeit bewegt sich der Ball nur um das $0,0167$-fache (= $1,67$%) der Sekundengeschwindigkeit weiter.
Dieser Faktor ist im Attribut <code>p_delta_s</code> enthalten. Dieser wird mit
$1/60 = 0,0167$ initialisiert, sofern der Update-Methode kein anderer Wert übergeben wird.


Auf genau dieselbe Weise wird die aktuelle Geschwindigkeit mit Hilfe der Beschleunigung
Auf genau dieselbe Weise wird die aktuelle Geschwindigkeit mit Hilfe der Beschleunigung
Zeile 178: Zeile 176:


<source lang="javascript">
<source lang="javascript">
v_owl.vx += v_owl.ax * p_frac_s;
v_ball.vx += v_ball.ax * p_delta_s;
v_owl.vy += v_owl.ay * p_frac_s;
v_ball.vy += v_ball.ay * p_delta_s;
</source>
</source>


Fügen Sie diesen Code in Ihre Model-Update-Funktion ein und starten Sie die Eule erneut.
Fügen Sie diesen Code in Ihre Model-Update-Funktion ein und starten Sie den Ball erneut.
Wenn Sie jetzt Ihre We-App laufen lassen, stellen Sie fest, dass die Eule zunächst beschleunigt,
Wenn Sie jetzt Ihre Web-App laufen lassen, stellen Sie fest, dass der Ball zunächst beschleunigt,
nach eine Kollission aber wieder abbremst. NAch der nächsten Kollission beschleunigt sie wieder.
nach eine Kollision aber wieder abbremst. Nach der nächsten Kollision beschleunigt er wieder.


Um diesen Effekt zu vermeiden, müssen Sie jedes mal, wenn Sie bei der Kollissionsbehandlung das Vorzeichen
Um diesen Effekt zu vermeiden, müssen Sie jedes mal, wenn Sie bei der Kollissionsbehandlung das Vorzeichen
der Geschwindigkeit ändern, das Vorzeichen der zugehörigen Beschleunigung analog ändern.
der Geschwindigkeit ändern, das Vorzeichen der zugehörigen Beschleunigung analog ändern.


Beispielsweise mus der Code
Beispielsweise muss der Code


<source lang="javascript">
<source lang="javascript">
v_owl.vx = -Math.abs(v_owl.vx);
v_ball.vx = -Math.abs(v_ball.vx);
</source>
</source>


Zeile 198: Zeile 196:


<source lang="javascript">
<source lang="javascript">
v_owl.ax = -Math.abs(v_owl.ax);
v_ball.ax = -Math.abs(v_ball.ax);
</source>
</source>


Zeile 205: Zeile 203:
===Aufgabe 7===
===Aufgabe 7===


Schreiben Sie die Kollissionsbehandlung so um, dass im Falle einer Kollission der Eule
Schreiben Sie die Kollissionsbehandlung so um, dass im Falle einer Kollission des Balls
mit dem unteren Fensterrand sowohl die Geschwindigkeit als auch die Beschleunigung
mit dem unteren Fensterrand sowohl die Geschwindigkeit als auch die Beschleunigung
jeweils in x- und in y-Richtung auf Null gesetzt wird. Das heißt, die
jeweils in x- und in y-Richtung auf Null gesetzt wird. Das heißt, der
Eule bleibt bei einer Kollision mit dem unteren Rand stehen stehen.
Ball bleibt bei einer Kollision mit dem unteren Rand stehen.


===Aufgabe 8===
===Aufgabe 8===


Positionieren Sie die Eule im linken oberen Eck, geben Sie ihr eine Geschwindigkeit von  
Positionieren Sie der Ball im linken oberen Eck, geben Sie ihm eine Geschwindigkeit von  
300 Pixeln in x-Richtung und von 0 Pixeln in y-Richtung. Die Beschleunigung in x-Richtung beträgt 0,
300 Pixeln in x-Richtung und von 0 Pixeln in y-Richtung. Die Beschleunigung in x-Richtung beträgt 0,
die Beschleunigung in y-Richtung 800. (Diese Zahlen sind gut für meinen Monitor geeignet,
die Beschleunigung in y-Richtung 800. (Diese Zahlen sind gut für meinen Monitor geeignet,
Zeile 218: Zeile 216:
Monitor haben, müssen Sie die Zahlen evtl. anpassen.)
Monitor haben, müssen Sie die Zahlen evtl. anpassen.)


Welche Kurve beschreibt die Eule, wenn Sie die Web-App starten?
Welche Kurve beschreibt der Ball, wenn Sie die Web-App starten?


===Aufgabe 9===
===Aufgabe 9===


Positionieren Sie die Eule im linken unteren Eck, geben Sie ihr eine Geschwindigkeit von  
Positionieren Sie den Ball im linken unteren Eck, geben Sie ihm eine Geschwindigkeit von  
300 Pixeln in x-Richtung und von -400 Pixeln in y-Richtung. Die Beschleunigung in x-Richtung beträgt 0,
300 Pixeln in x-Richtung und von -400 Pixeln in y-Richtung. Die Beschleunigung in x-Richtung beträgt 0,
die Beschleunigung in y-Richtung 200.
die Beschleunigung in y-Richtung 200.


Welche Kurve beschreibt die Eule, wenn Sie die Web-App starten?
Welche Kurve beschreibt der Ball, wenn Sie die Web-App starten?
 
Allerdings ist es nicht ganz sauber, die Erdanziehung mittels <code>v_ball.ax</code> zu simulieren.
Diese Beschleunigung ist die Beschleunigung, die vom Ball selbst ausgeht (die also von der Eule
per Muskelkraft geleistet wird). Wenn der Ball seine Bewegungsrichtung ändert, ändert sich auch die Richtung der Beschleunigung (eine Eule beschleunigt immer in Flugrichtung, vgl. Aufgabe 6).
Die Richtung der Erbbeschleunigung ändert jedoch bei einer Kollision nicht.
 
Verbessern Sie daher Ihre Anwendung vorlgendermaßen:


Jetzt fehlt nur noch en Gummiband, mit dem Sie die Eule beschleunigen können. :-)
* Fügen Sie eine Variable <code>v_g = 981</code> in die <code>let</code>-Anweisung ein. (981 wurde in Anlehnung an die Gravitationskonstante der Erde gewählt.)
* Reduzieren Sie die Eigenbeschleunigung der Eule in $y$-Richtung auf <code>0</code>. (Jetzt sollte sich die Eule wieder geradlinig bewegen.)
* Ersetzen Sie un der Update-Funktion <source lang="javascript">v_ball.vy += v_ball.ay * p_delta_s;</source> durch <source lang="javascript">v_ball.vy += (v_ball.ay+v_g) * p_delta_s;</source>
 
Das heißt, berücksichtigen Sie bei der Berechnung der $y$-Geschwindigkeit des Balles zusätzlich die Erdanziehungskraft. Nun sollte die Eule wieder einen sauberen Parabelflug vollführen.
Alles, was jetzt noch fehlt, ist ein Gummiband, mit dem Sie die Eule beschleunigen können. :-)


===Aufgabe 10===
===Aufgabe 10===


Machen Sie eigene Experimente. Bringen Sie {{zB}} die Eule dazu, wie ein Flummi
Machen Sie eigene Experimente. Bringen Sie {{zB}} den Ball dazu, wie ein Flummi
zu springen, indem sie ihre Geschwindigkeit in x- und y-Richtung bei einem Bodenkontakt
zu springen, indem sie seine Geschwindigkeit in x- und y-Richtung bei einem Bodenkontakt
um einen gewissen Prozentsatz reduzieren, aber nicht gleich auf null setzen.
um einen gewissen Prozentsatz reduzieren, aber nicht gleich auf null setzen.
(Die Beschleunigung, die die Erdanziehung simuliert, bleibt die ganze Zeit über gleich).
(Die Beschleunigung, die die Erdanziehung simuliert, bleibt die ganze Zeit über gleich).
Achtung: Bei einem Bodenkontakt, dreht sich das Vorzeichen der y-Geschwindigkeit um,  
Achtung: Bei einem Bodenkontakt, dreht sich das Vorzeichen der y-Geschwindigkeit um,  
das der x-Geschwindigkeit bleibt gleich.
das der x-Geschwindigkeit ändert sich dagegen nicht.


Nervig ist, dass die Eule zum Schluss immer noch ganz leicht hüpft und gar nicht
Nervig ist, dass der Ball zum Schluss immer noch ganz leicht hüpft und gar nicht
zur Ruhe kommt. Vielleicht können Sie auch dieses Problem beheben.
zur Ruhe kommt. Vielleicht können Sie auch dieses Problem beheben.


Oder probieren Sie etwas ganz anderes aus.
Oder probieren Sie etwas ganz anderes aus.
==Quellen==
==Quellen==
<references/>
<references/>

Version vom 15. Oktober 2019, 15:08 Uhr

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)

Vorlesung MMProg

Inhalt | EcmaScript01 | EcmaScript02 | EcmaScript03 | Ball 01| Ball 02 | Ball 03 | Pong 01

Musterlösung: Web-Auftritt (Git-Repository)

Vorbereitung

Im Git-Repository finden Sie zwei WebStorm-Projekte zum Thema GameLoop:

Machen Sie sich mit den Projekten vertraut. Die Web-Anwendung src/js/app des zweiten Projektes dient als Ausgangsbasis für diese Praktikumsaufgabe.

Im ersten Beispiel finden Sie diverse Game-Loop-Varianten. Schrittweise werden potentielle Probleme behoben. Dieses Projekt verfolgt das didaktische Ziel, Ihnen die Probleme und potentielle Lösungen im Zusammenhang mit JavaScript-Animationen zu verdeutlichen.

Im zweiten Beispiel wurde eine Game-Loop-Klasse realisiert, die sie für dieses Praktikum nutzen können und sollten. Diese Klasse basiert auf den Ergebnissen des ersten Projektes, stellt aber – im Gegensatz zu einigen Web-Anwendungen des ersten Projekt – bislang keine Informationen über die aktuelle Frame-Rate bereit. Dies ist aber für diese Praktikumsaufgabe nicht von Interesse.

Importieren Sie das leere Git-Projekt Ball01 in WebStorm. Laden Sie annschließend mittels npm i alle benötigten Node.js-Module in das Projekt.

Sie können Ihr Projekt zur Übung auch in Ihrem Git-Repository speichern. Das ist aber nicht so wichtig. Falls Sie dies machen möchten, müssen Sie es zuvor von meinem (schreibgeschützten) Repository lösen:

git remote remove origin
git remote add origin https://gitlab.multimedia.hs-augsburg.de/BENUTZER/Ball01.git

Aufgaben

In Ihrem Projekt finden Sie 10 Web-Anwendungen vor: index01.html verwendet die JavaScript-Datei app01.js, die ihrerseits das Spiel ball01.js einbindet. index02.html, index03.html etc. sind analog aufgebaut. Wenn Sie irgendeine dieser Anwendungen im Browser öffnen, sehen Sie eine Eule in der linken oberen Bildschirmecke. Diese sollen sie auf unterschiedliche Art und Weise animieren. Beachten Sie, dass im Folgenden der Avatar nicht „Eule“, sondern „Ball“ genannt wird. Die Eule ist lediglich eine View des ballartigen Objektes.

Lösen Sie jede der folgenden Aufgaben in einer der vorgegebenen Apps. Scheuen Sie sich nicht davor, eigene Experimente durchzuführen. Wenn die vorgegebenen Apps nicht ausreichen sollten, legen Sie einfach noch ein paar an.

Schreiben Sie Ihre Lösungen der Aufgabe $i$ in die Datei src/js/ball/ball$i$.js. Am einfachsten ist es, wenn Sie jeweils die Lösung der vorangegangenen Aufgabe kopieren und diese Kopie dann weiterentwickeln.

Aufgabe 1

Passen Sie zur Lösung dieser Aufgabe die Datei src/js/ball/ball01.js an. Lassen Sie sich durch den Code der Datei ball.js aus dem Beispiel WK_GameLoop02 inspirieren. (Sie könnten auch ball_interpolate.js verwenden, aber das verwirrt Sie vermutlich zurzeit deutlich mehr, als dass es Ihnen nützt.)

Lassen Sie den Ball horizontal vom linken bis zum rechten Fensterrand des Browsers fliegen.

Tipp: http://ryanve.com/lab/dimensions/

Berücksichtigen Sie, dass der Ball 150 Pixel breit ist, d. h. einen Radius von 75 Pixel hat, und dass der Ankerpunkt im linken oberen Eck des zugehörigen Bildes liegt. Sie müssen im Ball-Objekt auch die Radius des Balls speichern und diesen Wert bei der Kollissionserkennung und -behandlung berücksichtigen. Übrigens, wenn Sie v_ball_view wie in ball.js von WK_GameLoop02 definieren, können Sie mittels v_ball_view.offsetWidth/2; die aktuelle Breite des Ballobjektes aus der View auslesen.

Ein Tipp noch: Wenn Sie das Ball-Objekt zunächst als leeres Objekt definieren und danach in der Reset-Funktion initialisieren, funktionieren Ihre Anwendungen auch noch, wenn Sie später einen Start/Stopp- und einen Pause-Button einfügen (vgl. z. B. index_start_stop_toggling.html in WK_GameLoop02). Sollten Sie keine Buttons zur Steuerung einfügen wollen, können Sie die Objekte auch direkt bei der Definition initialisieren.

Vergessen Sie nicht, die Sourcen mittels npm run watch zu übersetzen. Und beachten Sie, dass im Browser nur die Dateien web/index$i$.html funktionieren. Wenn Sie versuchen, src/index$i$.html erhalten Sie im Browser einen leeren Screen und in der Browser-Konsole drei Fehlermeldungen, dass gewissen Dateien nicht geladen werden können.

Aufgabe 2

Lassen Sie den Ball nicht waagerecht, sondern in der horizontalen Mitte des Browserfensters senkrecht von Fensterrand zu Fensterrand fliegen.

Um die Aufgabe zu lösen, müssen Sie für der Ball zusätzlich eine y-Position und eine y-Geschwindigkeit definieren. Die Berechnung der aktuellen y-Position funktioniert analog zur Berechnung der aktuellen x-Position.

Vergessen Sie nicht, auch die Kollissionserkennung und -behandlung für die beiden Bildschirmseiten top und botton zu implementieren.

Und Sie müssen natürlich die Render-Funktion anpassen, sodass die aktuelle y-Position beim Rendern auch berücksichtigt wird.

Aufgabe 3

Lassen Sie der Ball von der Mitte des Browserfensters aus schräg über den Bildschirm fliegen. In x-Richtung soll er doppelt so schnell sein (200 Pixel/s) wie in y-Richtung (100 Pixel/s).

Aufgabe 4

Setzen Sie die x-Start-Position des Balls auf -100 und starten Sie die Web-App. Den Effekt, den Sie sehen, nennt man Penetration. Die Eule hängt in der Wand fest, da sie nicht den Kollissionsbereich (die linke Wand) in einem Schritt verlässt. Daher besteht die Kollission fort und im nächsten Schritt ändert sie wieder ihre Flugrichtung.

Verbessern Sie das, indem Sie die Kollisionserkennung und -behandlung verbessern:

if (v_ball.x <= v_stage.left)
{ v_ball.vx = Math.abs(v_ball.vx);
}
if (v_ball.x >= v_stage.right - 2*v_ball.r)
{ v_ball.vx = -Math.abs(v_ball.vx);
}

Passen Sie die Kollisionserkennung und -behandlung in y-Richtung analog an.

Sie können und sollten sogar noch einen Schritt weiter gehen und den Ball wieder zurück auf die Bühne schieben, wenn er in die Wand eingedrungen ist. In die Wand einzudringen ist zwar physikalisch nicht möglich, aber leider in einer Simulation der physikalischen Welt nur schwer zu vermeiden, da die Position nur alle 16,7 ms berechnet wird. War der Ball zu einem Zeitpunkt noch vor der Mauer, kann er beim nächsten Schritt schon drinnen stecken. Insbesondere bei sehr schnellen Objekten kann das dann zu den beobachteten Penetrationseffekten führen.

Also schieben Sie den Ball besser zurück auf die Bühne.

if (v_ball.x <= v_stage.left)
{ v_ball.x = v_stage.left;
  v_ball.vx = Math.abs(v_ball.vx);
}
if (v_ball.x >= v_stage.right - 2*v_ball.r)
{ v_ball.x = v_stage.right - 2*v_ball.r;
  v_ball.vx = -Math.abs(v_ball.vx);
}

Passen Sie die Kollisionserkennung und -behandlung in y-Richtung wiederum analog an.

Aufgabe 5

Ändern Sie die Kollisionserkennung und -behandlung so ab, dass sich der Ball ausgehend von der linken oberen Fensterecke im Uhrzeigersinn immer entlang des Fensterrandes bewegt.

Beachten Sie bitte: Hier ist es besonders wichtig, dass Sie den Ball wieder auf die Bühne zurückschieben, wenn er mit einer Wand kollidiert. Ansonsten verschwindet der Ball schnell im Nirgendwo.

(Anmerkung: Dies war einmal eine Aufgabe im Rahmen des Prüfungspraktikums, wobei die Lösung zur 3. Aufgabe vorgegeben war.)

Aufgabe 6

Kopieren Sie diesmal nicht die Lösung von Aufgabe 5, sondern die von Aufgabe 4. Im Folgenden arbeiten Sie wieder mit der normalen Kollissionserkennung und -behandlung. Positionieren Sie den Ball allerdings wieder im linken oberen Eck (in Aufgabe 4 hatten Sie sie außerhalb der Bühne platziert).

Die neue Position des Balls berechnen Sie mit Hilfe der Geschwindigkeit (velocity, vx, vy). Doch auch die Geschwindigkeig kann sich im Laufe der Zeit ändern. Dazu benötigt man die Beschleunigung (acceleration, ax, ay).

Fügen Sie zu Ihrem Ball zwei weitere Attribute ax (Beschleunigung in x-Richtung) und ay (Beschleunigung in y-Richtung) hinzu. Setzen Sie die Initialwerte auf 400 (Pixel pro Sekunde) bzw. 200 (Pixel pro Sekunde). Das heißt, Sie möchten, dass der Ball in jeder Sekunde um 400 bzw. 200 Pixel pro Sekunde mehr zurücklegt als zuvor.

Wenn Sie jetzt die Web-App starten, beschleunigt der Ball allerdings noch nicht.

In Ihrem Code wird die Position 60 mal pro Sekunde mit Hilfe des folgenden Codes aktualisiert:

v_ball.x += v_ball.vx * p_delta_s;
v_ball.y += v_ball.vy * p_delta_s;

Die Geschwindigkeit wird zur Position hinzuaddiert. Allerdings ist die Geschwindigkeit in Pixeln pro Sekunde angegeben. Die Modellaktualisierung passiert jedoch alle $0,0167$ Sekunden. In dieser Zeit bewegt sich der Ball nur um das $0,0167$-fache (= $1,67$%) der Sekundengeschwindigkeit weiter. Dieser Faktor ist im Attribut p_delta_s enthalten. Dieser wird mit $1/60 = 0,0167$ initialisiert, sofern der Update-Methode kein anderer Wert übergeben wird.

Auf genau dieselbe Weise wird die aktuelle Geschwindigkeit mit Hilfe der Beschleunigung berechnet:

v_ball.vx += v_ball.ax * p_delta_s;
v_ball.vy += v_ball.ay * p_delta_s;

Fügen Sie diesen Code in Ihre Model-Update-Funktion ein und starten Sie den Ball erneut. Wenn Sie jetzt Ihre Web-App laufen lassen, stellen Sie fest, dass der Ball zunächst beschleunigt, nach eine Kollision aber wieder abbremst. Nach der nächsten Kollision beschleunigt er wieder.

Um diesen Effekt zu vermeiden, müssen Sie jedes mal, wenn Sie bei der Kollissionsbehandlung das Vorzeichen der Geschwindigkeit ändern, das Vorzeichen der zugehörigen Beschleunigung analog ändern.

Beispielsweise muss der Code

v_ball.vx = -Math.abs(v_ball.vx);

um

v_ball.ax = -Math.abs(v_ball.ax);

ergänzt werden.

Aufgabe 7

Schreiben Sie die Kollissionsbehandlung so um, dass im Falle einer Kollission des Balls mit dem unteren Fensterrand sowohl die Geschwindigkeit als auch die Beschleunigung jeweils in x- und in y-Richtung auf Null gesetzt wird. Das heißt, der Ball bleibt bei einer Kollision mit dem unteren Rand stehen.

Aufgabe 8

Positionieren Sie der Ball im linken oberen Eck, geben Sie ihm eine Geschwindigkeit von 300 Pixeln in x-Richtung und von 0 Pixeln in y-Richtung. Die Beschleunigung in x-Richtung beträgt 0, die Beschleunigung in y-Richtung 800. (Diese Zahlen sind gut für meinen Monitor geeignet, der eine Auflösung von 1600x900 hat. Wenn Sie einen deutlich kleineren oder größeren Monitor haben, müssen Sie die Zahlen evtl. anpassen.)

Welche Kurve beschreibt der Ball, wenn Sie die Web-App starten?

Aufgabe 9

Positionieren Sie den Ball im linken unteren Eck, geben Sie ihm eine Geschwindigkeit von 300 Pixeln in x-Richtung und von -400 Pixeln in y-Richtung. Die Beschleunigung in x-Richtung beträgt 0, die Beschleunigung in y-Richtung 200.

Welche Kurve beschreibt der Ball, wenn Sie die Web-App starten?

Allerdings ist es nicht ganz sauber, die Erdanziehung mittels v_ball.ax zu simulieren. Diese Beschleunigung ist die Beschleunigung, die vom Ball selbst ausgeht (die also von der Eule per Muskelkraft geleistet wird). Wenn der Ball seine Bewegungsrichtung ändert, ändert sich auch die Richtung der Beschleunigung (eine Eule beschleunigt immer in Flugrichtung, vgl. Aufgabe 6). Die Richtung der Erbbeschleunigung ändert jedoch bei einer Kollision nicht.

Verbessern Sie daher Ihre Anwendung vorlgendermaßen:

  • Fügen Sie eine Variable v_g = 981 in die let-Anweisung ein. (981 wurde in Anlehnung an die Gravitationskonstante der Erde gewählt.)
  • Reduzieren Sie die Eigenbeschleunigung der Eule in $y$-Richtung auf 0. (Jetzt sollte sich die Eule wieder geradlinig bewegen.)
  • Ersetzen Sie un der Update-Funktion
    v_ball.vy += v_ball.ay * p_delta_s;
    
    durch
    v_ball.vy += (v_ball.ay+v_g) * p_delta_s;
    

Das heißt, berücksichtigen Sie bei der Berechnung der $y$-Geschwindigkeit des Balles zusätzlich die Erdanziehungskraft. Nun sollte die Eule wieder einen sauberen Parabelflug vollführen.

Alles, was jetzt noch fehlt, ist ein Gummiband, mit dem Sie die Eule beschleunigen können. :-)

Aufgabe 10

Machen Sie eigene Experimente. Bringen Sie z. B. den Ball dazu, wie ein Flummi zu springen, indem sie seine Geschwindigkeit in x- und y-Richtung bei einem Bodenkontakt um einen gewissen Prozentsatz reduzieren, aber nicht gleich auf null setzen. (Die Beschleunigung, die die Erdanziehung simuliert, bleibt die ganze Zeit über gleich). Achtung: Bei einem Bodenkontakt, dreht sich das Vorzeichen der y-Geschwindigkeit um, das der x-Geschwindigkeit ändert sich dagegen nicht.

Nervig ist, dass der Ball zum Schluss immer noch ganz leicht hüpft und gar nicht zur Ruhe kommt. Vielleicht können Sie auch dieses Problem beheben.

Oder probieren Sie etwas ganz anderes aus.

Quellen

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