--- author: Florian Fischer theme: metropolis aspectratio: 169 --- # Phase I - Modellierung eines Spiels ## \faIcon{pencil-alt} Modellierung - 10min ::: {.columns align=center} :::: {.column width=50%} * Erstelle ein Klassendiagramm mit allen **Klassen**, die du im rechten Screenshot ausmachen kannst. * Notiere die **Attribute**, die du sehen kannst und die, die Klassen haben müssen. * Notiere die **Methoden**, die die Klassen vermutlich haben. * Zeichne und beschrifte die Beziehungen zwischen den Klassen. :::: :::: {.column width=50%} ![](img/snake.png) :::: ::: ## "Offensichtliche" Klassen ::: {.columns} :::: {.column width=50%} ### Schlange Attribute: \vspace{-0.2cm} * `richtung` *(rauf, runter, links, rechts)* * `koerperteile` Methoden: \vspace{-0.2cm} * bewegen * wachse ### Essen * Position ::: :::: {.column width=50%} \begin{tikzpicture} \begin{class}[text width=4cm]{Schlange}{0,0} \attribute{richtung} \attribute{koerperteile} \operation{bewegen()} \operation{wachse()} \end{class} \begin{class}[text width=4cm]{Essen}{0,-4.5} \attribute{Position} \end{class} \end{tikzpicture} :::: ::: ## \faIcon{desktop} Arbeitsauftrag \hfill 15 min * Kopiere die **Snake** BlueJ-Projekt Vorlage * Erzeuge Objekte der bereits vorhandenen Klassen und untersuche ihre Methoden * Erstelle eine neue Klasse `Schlange` * Ergänze die Klasse Schlange um das Attribut `String richtung`{.java} * Ergänze die Klasse Schlange um ein Attribut `kopf` vom Typ `Rechteck` * Implementiere den `Konstruktor` der Klasse `Schlange` * Es soll die Position übergeben werden * Die Startrichtung soll `"runter"`{.java} sein * Erzeuge einen neuen grünen Kopf an der richtigen Position mit der Größe 20x20. ## \faIcon{desktop} Arbeitsauftrag \hfill 10 min \let\tightlist\relax * Implementiere die Methode `bewegen` der Schlange * Je nach ihrer Richtung soll sich der Kopf der Schlange um 20 Pixel bewegen **Tipp**: verwende die Methode `Verschieben(int deltaX, int deltaY)`{.java} der Klasse `Rechteck` * Erzeuge ein Schlangen Objekt und verschiebe es über den Bildschirm. ## Wer ruft die Methoden der Klasse Schlange auf? \pause ### Once class to rule them all Eine Klasse verwaltet das gesamte Spiel indem sie auf Nutzereingaben reagiert und die richtigen Methoden der anderen Objekte ausführt. **\faIcon{lightbulb} Welche Attribute hat diese Klasse?** \pause #### Attribute * schlange * essen * rahmen * zeit * (highscore) ## EVA-Prinzip {.t} ::: {.columns} :::: {.column width=65%} \vspace{0.2cm} \only<2->{ Trennung der Datenverarbeitung in: \begin{itemize} \item \boldred{E}ingabe: \texttt{input()} \item \boldred{V}erarbeitung: \texttt{update()} \item \boldred{A}usgabe: \texttt{output()} \end{itemize} } \vspace{0.1cm} \only<3->{\textbf{\faIcon{lightbulb} Wie oft müssen wir die drei Schritte ausführen?}} \only<4->{ Solange das Spiel läuft! \begin{block}{EVA-Loop} \phantomsection\label{eva-loop} \texttt{solange Spiel aktiv}\\ ~~\texttt{input()}\\ ~~\texttt{update()}\\ ~~\texttt{output()}\\ \end{block} } :::: :::: {.column width=30%} \vspace{1.5cm} \begin{tikzpicture} \only<2->{ \node[line width=1pt, draw, minimum width=3cm, rounded corners=5pt] (e) {Eingabe}; \node[line width=1pt, draw, minimum width=3cm, rounded corners=5pt, below=of e] (v) {Verarbeitung}; \node[line width=1pt, draw, minimum width=3cm, rounded corners=5pt, below=of v] (a) {Ausgabe}; \draw[-{Triangle}, line width=1pt] (e) to (v); \draw[-{Triangle}, line width=1pt] (v) to (a); } \only<4>{ \draw[-{Triangle}, line width=1pt, dashed] (a.east) -- ($(a.east) + (0.5, 0)$) -- ($(e.east) + (0.5, 0)$) -- (e.east); } \end{tikzpicture} :::: ::: ## \only<2->{Spieleengine} **\faIcon{lightbulb} Sind wir die ersten mit diesem Problem?** \pause Sicher nicht! Also lasst uns das Rad nicht neu erfinden. Sondern eine \boldred{Spieleengine} verwenden die uns die lästigen Dinge abnimmt. \pause ### GraphicsAndGames ``` solange Spiel aktiv <- GraphicsAndGames input() <- GraphicsandGames update() <- Wir output() <- GraphicsAndGames ``` ## Wie bekommen wir die Eingabe? ::: {.columns} :::: {.column width=75%} Wir erfüllen mit unserer Spiel-Klasse das \boldred{interface} `Zeichenfenster.AktionsEmpfaenger` damit uns GraphicsAndGames Eingaben übergeben kann. \vspace{0.1cm} Ein Interface gibt zu implementierende Methoden vor. :::: :::: {.column width=25%} \hspace{-1cm} \scalebox{1.1}{ \begin{tikzpicture} \node[line width=1pt, draw, minimum height=1cm, minimum width=3cm, rounded corners=5pt] (v) {Verarbeitung}; \node[fill=bg, line width=1pt, minimum height=1cm, minimum width=3cm, rounded corners=5pt, above=-0.1cm of v] (e) {Eingabe}; \draw[line width=1pt, rounded corners=5pt] ($(v.north west) + (0, 1cm)$) -- ($(v.north east) + (0, 1cm)$) -- (v.north east) {[sharp corners] -- ($(v.north east) - (0.625cm, 0)$) -- ($(v.north east) - (0.6cm, 0.2cm)$) -- ($(v.north east) - (0.8cm, 0.2cm)$) -- ($(v.north east) - (0.775cm, 0)$) -- ($(v.north east) - (1.525cm, 0)$) -- ($(v.north east) - (1.5cm, 0.2cm)$) -- ($(v.north east) - (1.7cm, 0.2cm)$) -- ($(v.north east) - (1.675cm, 0)$) -- ($(v.north east) - (2.425cm, 0)$) -- ($(v.north east) - (2.4cm, 0.2cm)$) -- ($(v.north east) - (2.6cm, 0.2cm)$) -- ($(v.north east) - (2.575cm, 0)$)} -- (v.north west) -- ($(v.north west) + (0, 1cm)$); \draw[line width=1pt, red] ($(v.north east) + (0.1cm, 0.2cm)$) -- ($(v.north east) - (-0.1cm, 0.3cm)$) -- ($(v.north west) - (0.1cm, 0.3cm)$) -- ($(v.north west) + (-0.1cm, 0.2cm)$) -- ($(v.north east) + (0.1cm, 0.2cm)$); \node[rotate=90] at ($(v.north west) - (0.3cm, 0.0cm)$) {\boldred{interface}}; \end{tikzpicture} } :::: ::: \pause **Java** `class Snake implements Zeichenfenster.AktionsEmpfaenger`{.java} \pause **Methoden** * `public void Ausführen()`{.java} * `public void Taste(char taste)`{.java} * `public void SonderTaste(int taste)`{.java} * `public void Geklickt(int x, int y, int anzahl)`{.java} ## \faIcon{desktop} Arbeitsauftrag `\begin{itemize}`{=latex} `\item`{=latex} Erstelle eine neue Klasse `Snake` `\begin{itemize}`{=latex} `\item`{=latex} Ergänze die Klasse `Snake` um ein **Referenzattribut** `schlange` `\item`{=latex} Initialisiere das Attribut `schlange` im `Snake` Konstruktor an der Position (380, 280). `\item`{=latex} Ergänze die Klasse `Snake` um die 4 Methoden des `AktionsEmpfaenger` interfaces. `\item`{=latex} Definiere, dass die Klasse `Snake` das interface `AktionsEmpfaenger` erfüllt. `\item`{=latex} Registriere neue `Snake`-Objekte als AktionsEmpfanger, indem du den Konstruktor um den Aufruf `Zeichenfenster.AktionsEmpfängerEintragen(this);`{.java} erweiterst. `\end{itemize}`{=latex} `\end{itemize}`{=latex} ## \faIcon{desktop} Arbeitsauftrag * Implementiere die Methode `Taste(char taste)`{.java} sodass die Richtung der Schlange angepasst wird. * 'W': rauf * 'S': runter * 'A': links * 'D': rechts * Rufe `schlange.bewegen()` in der `Ausführen` Methode auf * Teste dein Spiel indem du ein neues `Snake` Objekt erzeugst * **Für Schnelle:** Implementiert die Schlangensteuerung mit den Pfeiltasten und der Methode `Sondertaste` (Tipp: die Klasse `java.awt.event.KeyEvent` hilft) # Phase II - Essen und Wachstum ## Essen ::: {.columns} :::: {.column width=50%} \begin{center} \begin{tikzpicture} \begin{class}[text width=4cm]{Essen}{0,-4.5} \attribute{Position} \end{class} \end{tikzpicture} \end{center} \vspace{1cm} Das Essen soll in festen Zeitintervallen an einer zufälligen Position entstehen. :::: :::: {.column width=50%} ![](img/snake.png) :::: ::: ## Zufall Die Java Klasse `java.util.Random` stellt *pseudo* zufällige Zahlen bereit. \pause ### Verwendung * Importieren der Klasse: `import java.util.Random;` * Deklarieren und Initialisieren eins Attributs vom Typ `Zufall`. * Die Methode `nextInt(int max)` liefert eine Zahl zwischen 0 und `max`. **\faIcon{lightbulb} In welchem Bereich soll das Essen platziert werden?** \pause ### Größe des Welt Das Zeichenfenster misst 800x600 Pixel. ## Tischlein deck dich ::: {.columns} :::: {.column width=50%} ![](img/tischlein_deck_dich.png) :::: :::: {.column width=50%} ```java void Ausführen() { ticks++; if (ticks % 30 == 0) { if (essen) { essen.entfernen(); } int x = zufall.nextInt(780); int y = zufall.nextInt(580); essen = new Essen(x, y); } ... } ``` :::: ::: ## Wachstum Die Schlange soll im Laufe des Spiels länger werden. **\faIcon{lightbulb} Welcher Datentyp eignet sich dazu eine unbekannte Anzahl an Rechtecken zuspeichern?** \pause ### Das Attribut `koerper` * Das Attribut `koerper` der Klasse `Schlange` vom Typ `Rechteck[]` verwaltet alle Körperteile * Felder haben eine **feste** Länge, deshalb muss jedes mal ein neues größeres Feld erzeugt werden und die einzelnen Rechtecke von dem alten Feld in das neue Kopiert werden. ## Bewegung **\faIcon{lightbulb} Wie kommt die Schlange um die Ecke?** \pause ::: {.columns align=center} :::: {.column width=50%} \only<3>{Jedes Körperteil folgt seinem Vorgänger.} :::: :::: {.column width=50%} ![Schematische Skizze der Fortbewegung einer Raupe](img/Copyrighted/caterpillar_movement.png){.center width=100%} :::: ::: ## Bewegung ```java void bewegen() { for (int i = koerper.length - 1; i > 0; i--) { Rechteck vorgaenger = koerper[i-1]; koerper[i].PositionSetzen(vorgaenger.x, vorgaenger.y); } Rechteck kopf = koerper[0]; // Kopf je nach aktueller Richtung verschieben // kopf.Verschieben() ... } ``` # Phase III - Kollisionserkennung ## Wann frisst die Schlange das Essen ::: {.columns align=center} :::: {.column width=50%} \vspace{0.3cm} ![](img/snake_eating.png) :::: :::: {.column width=50%} Berührt der Kopf das Essen? :::: ::: ## Wann frisst die Schlange das Essen ### \faIcon{lightbulb} Wo findet die Überprüfung statt? \pause In der `Ausführen`-Methode der Welt-Klasse `Snake`, da >- dort Schlange und Essen bekannt sind >- dort die Schlange bewegt wird \pause ### Pseudocode ``` Schlange bewegen Falls Kopf das Essen berührt entferne Essen Schlange wachse ``` ## Kollision mit dem Rand der Welt ::: {.columns align=center} :::: {.column width=50%} \vspace{0.3cm} ![](img/snake_crash.png) :::: :::: {.column width=50%} Ist die Position des Kopfes noch Teil der Welt? :::: ::: ## Kollision mit dem Rand der Welt ### \faIcon{lightbulb} Wo findet die Überprüfung statt? \pause In der `bewegen`-Methode der Klasse `Schlange`, nachdem der Kopf bewegt wurde ### \faIcon{lightbulb} Woher weiß das Spiel das die Schlange kollidiert ist? \pause Die Methode `bewegen` gibt einen Wahrheitswert zurück, ob sie erfolgreich war. \pause ### Pseudocode ``` Koerper bewegen Kopf bewegen Falls kopf.x < 0 oder kopf.x > Weltbreite oder kopf.y < 0 oder kopf.y > Welthöhe return false return true ``` ## Kollision mit sich selbst ::: {.columns align=center} :::: {.column width=50%} \vspace{0.3cm} ![](img/snake_eating_itself.png) :::: :::: {.column width=50%} Berührt der Kopf der Schlange eins der eigenen Körperteile? :::: ::: ## Kollision mit sich selbst ### \faIcon{lightbulb} Wo findet die Überprüfung statt? \pause In der `bewegen`-Methode der Klasse `Schlange`, nachdem die Schlange bewegt wurde. \pause ### Pseudocode ``` Koerper bewegen Kopf bewegen ... Für jedes koerperteil hinter dem kopf Falls kopf beruehrt koerperteil return false return true ``` ## {.standout} Dieses Werk ist lizenziert unter einer [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/) Lizenz \faCreativeCommons\ \faCreativeCommonsBy\ \faCreativeCommonsSa.