--- author: Florian Fischer theme: metropolis aspectratio: 169 --- # Phase I - Modellierung eines Spiels ## \faIcon{pencil-alt} Modellierung \hfill 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 welche 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/jumpnrun.png) :::: ::: ## "Offensichtliche" Klassen ::: {.columns} :::: {.column width=45%} ### Spieler \vspace{-0.3cm} *Attribute*: \vspace{-0.2cm} * Geschwindigkeit * Position \vspace{-0.3cm} *Methoden*: \vspace{-0.2cm} * Bewegen * Springen \vspace{-0.2cm} ### Flagge \vspace{-0.3cm} * Position \vspace{-0.2cm} ### Plattform \vspace{-0.3cm} * Position * Höhe * Breite ::: :::: {.column width=55%} \begin{tikzpicture} \begin{class}[text width=3cm]{Spieler}{0,0} \attribute{geschwindigkeit} \attribute{position} \operation{bewegen()} \operation{springen()} \end{class} \begin{class}[text width=3cm]{Flagge}{0,-4.5} \attribute{position} \end{class} \begin{class}[text width=3cm]{Platform}{5,-2.5} \attribute{position} \attribute{hoehe} \attribute{breite} \end{class} \association{Spieler}{steht auf}{}{Platform}{}{}; \association{Spieler}{erreicht}{}{Flagge}{}{}; \end{tikzpicture} :::: ::: ## "Nicht sichtbare" Klassen ::: {.columns} :::: {.column width=50%} ### Level \vspace{-0.3cm} *Attribute*: \vspace{-0.2cm} * feste Objekte * interaktive Objekte \vspace{-0.3cm} *Methoden*: \vspace{-0.2cm} * naechstes Level * Spieler-Position setzen ### Spiel * Level * Spieler * Highscore * Zeit * ... ::: :::: {.column width=50%} \begin{tikzpicture} \begin{class}[text width=3cm]{Level}{0,0} \attribute{festeObjekte} \attribute{interaktiveObjekte} \end{class} \begin{class}[text width=3cm]{Spiel}{0,-4.5} \attribute{level} \attribute{player} \end{class} \end{tikzpicture} :::: ::: ## Klassendiagramm \centering \begin{tikzpicture} \begin{class}[text width=3cm]{Spieler}{6,1} \attribute{geschwindigkeit} \attribute{position} \operation{bewegen()} \operation{springen()} \end{class} \begin{class}[text width=3cm]{Flagge}{4.5,-2.5} \attribute{position} \end{class} \begin{class}[text width=3cm]{Platform}{8,-3.75} \attribute{position} \attribute{hoehe} \attribute{breite} \end{class} \begin{class}[text width=3cm]{Spiel}{0,0} \attribute{Level} \attribute{Player} \end{class} \association{Spiel}{}{enthält}{Spieler}{1}{}; \begin{class}[text width=3cm]{Level}{1,-4.5} \attribute{festeObjekte} \attribute{interaktiveObjekte} \end{class} \association{Spiel}{}{ist aktiv}{Level}{1}{}; \association{Level}{}{}{Flagge}{}{}; \association{Level}{}{enthält}{Platform}{n}{}; \end{tikzpicture} ## {.standout} Wer ruft die Methoden des Spielers auf? ## \faIcon{chalkboard-teacher} 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} :::: ::: ## \faIcon{chalkboard-teacher} \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 ### Online-IDE ``` solange Spiel aktiv <- Online-IDE input() <- Online-IDE update() <- Wir output() <- Online-IDE ``` ## Wie werden unsere Methoden aufgerufen? ::: {.columns} :::: {.column width=75%} Wir erfüllen mit unserer Spieler Klasse das \boldred{interface}, das die Online-IDE vorgibt. \vspace{0.1cm} Ein Interface gibt zu implementierende Methoden vor. \vspace{0.1cm} Um automatisch das Interface zu erfüllen, erben wir von der Klasse `Sprite` bzw. `Actor`. :::: :::: {.column width=25%} \hspace{-1.25cm} \scalebox{1.1}{ \begin{tikzpicture} \node[fill=magenta!20, line width=1pt, draw, minimum height=1cm, minimum width=3cm, rounded corners=5pt] (v) {Verarbeitung}; \node[fill=bg, minimum height=1cm, minimum width=3cm, rounded corners=5pt, above=-0.1cm of v] (e) {Eingabe}; \draw[line width=1pt, rounded corners=5pt, fill=bg] ($(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)$); \draw[-Latex, bend left=35, line width=0.75pt] ($(e.east) + (0, 1mm)$) to ($(v.east)-(0,1mm)$); \node[minimum height=1cm, above=-0.1cm of v] (e) {Eingabe}; \node[rotate=90] at ($(v.north west) - (0.3cm, 0.0cm)$) {\boldred{interface}}; \end{tikzpicture} } :::: ::: \pause **Java** `class Player extends Sprite`{.java} \pause **Methoden** * `void act()`{.java} ## Wie erhalten wir die Eingaben? ::: {.columns} :::: {.column width=75%} \faIcon{lightbulb} Wir fragen die Online-IDE. \vspace{0.1cm} Die Online-IDE bietet Methoden, um die Eingaben zu erfragen. \vspace{0.1cm} Wir haben die Methoden bereits von der Klasse `Actor` geerbt. :::: :::: {.column width=25%} \hspace{-1.25cm} \scalebox{1.1}{ \begin{tikzpicture} \node[line width=1pt, draw, minimum height=1cm, minimum width=3cm, rounded corners=5pt] (v) {Verarbeitung}; \node[fill=bg, minimum height=1cm, minimum width=3cm, rounded corners=5pt, above=-0.1cm of v] (e) {Eingabe}; \draw[line width=1pt, rounded corners=5pt, fill=cyan!20] ($(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.05cm, 0.2cm)$) -- ($(v.north east) - (-0.05cm, 0.3cm)$) -- ($(v.north west) - (0.05cm, 0.3cm)$) -- ($(v.north west) + (-0.05cm, 0.2cm)$) -- ($(v.north east) + (0.05cm, 0.2cm)$); \draw[-Latex, bend right=35, line width=0.75pt] (v.east) to ($(e.east) + (0, 2mm)$); \node[minimum height=1cm, minimum width=3cm, above=-0.1cm of v] (e) {Eingabe}; \node[rotate=90] at ($(v.north west) - (0.3cm, 0.0cm)$) {\boldred{interface}}; \end{tikzpicture} } :::: ::: \pause **Methoden** * `boolean isGamepadButtonDown(int gamepadIndex, int buttonIndex)`{.java} * `boolean isGamepadConnected(int gamepadIndex)`{.java} * `boolean isKeyDown(String key)`{.java} * `boolean isKeyUp(String key)`{.java} ## Koordinaten in der Online-IDE Die Online-IDE benutzt ein Koordinatensystem, dessen \boldred{Ursprung} in der **linken oberen** Ecke liegt. ::: {.columns} :::: {.column width=40%} \begin{tikzpicture} \node at (-0.5, 0.5) {\small $(0, 0)$}; \node at (1.5, 0.25) {\small $x$}; \draw[->] (0, 0) -- (3, 0); \node at (3, 0.5) {\small $(800,0)$}; \draw[->] (0, 0) -- (0, -3); \node at (-0.25, -1.5) {\small $y$}; \node at (-0.5, -3.3) {\small $(0,600)$}; \end{tikzpicture} :::: :::: {.column width=60%} ![](img/oide_mouse_coordinates.png){.center height=60%} Die Koordinaten des Mauszeigers werden über dem Spielfeld angezeigt. :::: ::: ## \faIcon{desktop} Arbeitsauftrag: Los gehts! \hfill 10 min \let\tightlist\relax * Öffne das **JumpNRun Vorlage1** Projekt. * Untersuche die bereits vorhandenen Klassen. * Ergänze die Klasse `Player` um die Attribute: `vx`, `speed` vom Typ `double`{.java}. * Initialisiere `vx` mit `0` und `speed` mit 10. ## \faIcon{desktop} Arbeitsauftrag: Spieler bewegen \hfill 15 min Vervollständige die Methode `act` des Spielers. * Die Figur soll sich entsprechend ihrer Geschwindigkeit in X-Richtung (`vx`) horizontal bewegen. **Tipp**: Verwende die Methode `move(double deltaX, double deltaY)`{.java} der Klasse `Sprite`. * *Falls* eine Pfeiltaste gedrückt wird, soll sich Figur mit der Geschwindigkeit `speed` in die entsprechende Richtung bewegen. **Tipp**: Verwende die Methode `isKeyDown(int key)`{.java} mit den beiden Pfeiltasten: `Key.ArrowLeft`{.java} und `Key.ArrowRight`{.java} * Wird **keine** der beiden Tasten gedrückt, soll die Figur abbremsen. Setzte ihre Geschwindigkeit in X-Richtung auf $80\%$ des aktuellen Werts. \faIcon{play} Teste deine Implementierung. ## \faIcon{desktop} Arbeitsauftrag: Fallen \hfill 10 min \let\tightlist\relax * Ergänze den Spieler um die Attribute: `vy`, `gravity`, `sprung` vom Typ `double`{.java}. * Initialisiere die Attribute `gravity` mit `0.8` und `sprung` mit `-15`. * Die Figur soll sich auch entsprechend ihrer Geschwindigkeit in Y-Richtung (`vy`) vertical bewegen. **Tipp**: Passe den `move(...)` Methoden-Aufruf in der `act`-Methode an. * *Falls* die Figur **nicht** auf dem Boden steht, d.h. ihr Mittelpunkt einen Y-Wert (`getCenterY()`) *kleiner* als 350 hat, soll sich ihre Geschwindigkeit in Y-Richtung `vy` um `gravity` erhöhen. * *Ansonsten* wenn sie auf dem Boden steht, soll ihre Y-Geschwindigkeit `vy` auf `0` gesetzt werden. ## \faIcon{desktop} Arbeitsauftrag: Springen \hfill 10 min *Falls* die Figur auf dem Boden steht, d.h. ihr Mittelpunkt einen Y-Wert *größer gleich* 350 hat, **und** die Pfeiltaste nach oben gedrückt ist `Key.ArrowUp`, \newline soll sich ihre Geschwindigkeit in Y-Richtung `vy` um `sprung` erhöhen. \faIcon{play} Teste deine Implementierung. ## \faIcon{desktop} Arbeitsauftrag: Blickrichtung ### \faIcon{earlybirds} Für Schnelle Die Figur soll in die Richtung ihrer Bewegung blicken. \let\tightlist\relax * Ergänze die Klasse `Player` um das Attribute: `headingRight` vom Typ `boolean`{.java} * *Falls* eine Pfeiltaste gedrückt wurde und ein Richtungswechsel statt findet * passe den Wert des Attributs `headingRight` entsprechend an * spiegele die Figur durch einen Aufruf der Methode `mirrorX()` # Phase II - Plattformen und Kollision ## Plattformen und Level Ein Level soll mehrere feste Plattformen haben. ::: {.columns} :::: {.column width=50%} \begin{center} \begin{tikzpicture} \begin{class}[text width=4cm]{Plattform}{0,-3.5} \attribute{position} \attribute{hoehe} \attribute{breite} \end{class} \begin{class}[text width=4cm]{Level}{0,0} \attribute{festeObjekte} \attribute{interaktiveObjekte} \end{class} \association{Plattform}{n}{}{Level}{enthält}{1}; \end{tikzpicture} \end{center} :::: :::: {.column width=50%} ![](img/jumpnrun.png) :::: ::: ## \faIcon{lightbulb} Plattformen und Level ### Klassiker Wie speichern wir mehrere Plattformen in einem Level? \pause$\rightarrow$ mit einem Feld (`Platform[]`{.java})! \pause ### **Besser:** `Group` Die Online-IDE bietet die Klasse `Group` zur Verwaltung mehrer graphischer Objekte (`Shape`). **Methoden**: * `void add(T shape)` - Fügt ein Objekt der Gruppe hinzu * `void destroyAllChildren()` - Zerstört alle Objekte der Gruppe * ... ## \faIcon{desktop} Arbeitsauftrag: Level1 \hfill{} 15min \let\tightlist\relax * (Implementiere die Klasse `Level`) * Implementiere die Klasse `Level1`, die von der Klasse `Level` erbt. * Erzeuge ein `Rectangle` für den Boden. * Erzeuge ein `Rectangle` als linke Spielrand-Begrenzung. * Erzeuge vier `Rectangle` als aufsteigende Platformen. Vorschlag: `new Rectangle(200 + 450 * i, 470 - 40 * i, 300, 25)`{.java} * Füge alle erzeugten Rechtecke der `solidObjekt` Gruppe hinzu. ## \faIcon{desktop} Arbeitsauftrag: Spielstart \hfill{} 5min Vervollständige den Konstruktor der Klasse `JumpNRun`. \let\tightlist\relax * Erzeuge ein `Level1` Objekt und initialisiere damit das `Level` Attribut der Klasse `JumpNRun`. * Rufe die `spawnPlayer`-Methode des ersten Levels mit dem `Player` Attribute der Klasse `JumpNRun` auf. \faIcon{play} Teste deine Implementierung. ## {.standout} Wir fallen einfach durch den Boden! ## \only<2->{Kollision} \faIcon{lightbulb} Wie erkennen wir, dass zwei graphische Objekte sich berühren? \pause Wir müssen prüfen, ob sie sich in *mindestens* einem Punkt im Koordinatensystem überschneiden. \pause ```\begin{pseudocode}```{=latex} ``` für alle Objekte für alle anderen Objekte Finde Überschneidung Falls Überschneidung Behandle Überschneidung ``` ```\end{pseudocode}```{=latex} ## Kollision: Online-IDE Damit wir nicht selbst prüfen müssen, ob sich Objekte berühren, fragen wir einfach die Online-IDE. Die Methode `getCollidingShapes(Group g)`{.java} eines `Sprite` Objektes gibt alle Objekte einer Gruppe `g` zurück, die mit dem `Sprite` kollidieren. Mit der `foreach`-Variante der `for`-Schleife können wir alle Kollisionen behandeln. ```java Shape[] collidingShapes = getCollidingShapes(jumpnrun.level.solidObjects); for (Shape shape: collidingShapes) { // Behandle Kollision } ``` ## \faIcon{desktop} Arbeitsauftrag: Kollision erkennen \hfill{} 5min Implementiere in der `void act()`{.java} des Spielers die Kollisionserkennung. \let\tightlist\relax * Speichere alle *soliden* kollidierenden Objekte, des aktuellen Levels als Variable. (`Shape[] collidingShapes = getCollidingShapes(jumpnrun.level.solidObjects);`{.java} * Implementiere eine `foreach`-Wiederholung, die alle kollidierenden Objekte behandeln soll. (`for(Shape shape: collidingShapes) {}`{.java}) ## \faIcon{desktop} Arbeitsauftrag: Kollision behandeln \hfill{} 10min \begin{tcolorbox}[colframe=yellow, colback=yellow!20, title=\textcolor{black}{\faIcon{lightbulb} Idee}] Der Spieler, soll die aktuelle Bewegung, die zur Kollision geführt hat, rückgängig machen, bis es zu keiner Kollision mehr kommt. \end{tcolorbox} Implementiere `void reactToCollisionWithShape(Shape shape)`{.java} im Spieler: * Bestimme die Richtung, aus der der Spieler mit `shape` kollidiert ist. (`Direction direction = directionRelativeTo(shape);`{.java}) * Setze je nach Richtung (`top`, `left`, `right`, `bottom`), die Geschwindigkeit dieser Richtung auf 0. * Mache die letzte Bewegung mit `moveBackFrom(shape, false)`{.java} rückgängig. (`moveBackFrom(Shape otherShape, boolean keepColliding)`{.java}) * Wiederholung die letzte Bewegung in die Richtung, die *nicht* zur Kollision führt. ## \faIcon{desktop} Arbeitsauftrag: Kollision behandeln 2 \hfill{} 5min ```\begin{pseudocode}```{=latex} ``` für alle überschneidenden Objekte Behandle Überschneidung ``` ```\end{pseudocode}```{=latex} Wir wollen unsere **Kollisionserkennung** `getCollidingShapes(Group group)`{.java} mit unserer **Kollisionsbehandlung** `reactToCollisionWithShape(Shape shape)`{.java} verbinden. \begin{center} \textbf{Kollisionserkennung} \hspace{5mm} \faIcon{link} \hspace{5mm} \textbf{Kollisionsbehandlung} \end{center} * Rufe mit *jedem* kollidierenden Shape in `collidingShapes` die `reactToCollisionWithShape` Methode auf. ## \faIcon{desktop} Arbeitsauftrag: Auf dem Boden stehen \hfill{} 10min :::{.block} ### Wir wollen erkennen, wann wir auf festem Boden stehen! * Nicht fallen * Springen erlauben * Laufanimation abspielen ::: Das Attribut `Shape standsOn`{.java} der Klasse `Player` merkt sich auf welchem Shape der Spieler steht. * (Ergänze das `standsOn` Attribut vom Typ `Shape` in der Klasse `Player`) * (Ändere die Prüfung, ob Gravitation wirkt zu: `standsOn == null`{.java}) * Bei Kollision von *oben*, speichere das kollidierende `shape` im Attribut `standsOn`. * Überprüfe vor der Kollisionserkennung, ob der Spieler *nicht mehr* mit dem gespeicherten `standsOn` Objekt kollidiert. (`standOn != null && !collidesWith(standsOn)`{.java}) * *Falls ja* setze `standOn` auf `null`{.java} ## {.standout} Wir wollen, dass etwas passiert! ## Erinnerung: Interaktive Elemente Neben mehreren festen Plattformen soll ein Level auch **interaktive Elemente** enthalten. ::: {.columns} :::: {.column width=50%} \begin{center} \begin{tikzpicture} \begin{class}[text width=4cm]{InteraktivesObjekt}{0,-3.5} \attribute{?} \attribute{?} \operation{onCollision(player)} \end{class} \begin{class}[text width=4cm]{Level}{0,0} \attribute{festeObjekte} \attribute{\textcolor{red}{interaktiveObjekte}} \end{class} \association{Plattform}{n}{}{Level}{enthält}{1}; \end{tikzpicture} \end{center} :::: :::: {.column width=50%} ![](img/jumpnrun.png) :::: ::: ## Mehrere Klassen mit den gleichen Methoden? Wir müssen sicherstellen, dass alle Objekte mit dem Player interagieren können. \begin{tcolorbox}[colframe=yellow, colback=yellow!20, title=\textcolor{black}{\faIcon{lightbulb} Idee(n)}] \begin{itemize} \item<2-> Gemeinsame Oberklasse? (\textit{Keine gemeinsamen Attribute}) \item<3-> \boldred{Interface}! \end{itemize} \end{tcolorbox} ::: {.columns} :::: {.column width=70%} \pause\pause\pause \vspace{0.1cm} Ein neues \boldred{Interface}: ```java interface InteractiveElement { void onCollisionWithPlayer(Player player, JumpNRun jumpNRun); } ``` :::: :::: {.column width=30%} \only<4->{ \begin{tikzpicture} \node[fill=magenta!20, line width=1pt, draw, minimum height=1cm, minimum width=3cm, rounded corners=5pt] (v) {Interakt. Objekt}; \node[fill=bg, minimum height=1cm, minimum width=3cm, rounded corners=5pt, above=-0.1cm of v] (e) {Player}; \draw[line width=1pt, rounded corners=5pt, fill=bg] ($(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)$); \draw[-Latex, bend left=35, line width=0.75pt] ($(e.east) + (0, 1mm)$) to ($(v.east)-(0,1mm)$); \node[minimum height=1cm, above=-0.1cm of v] (e) {Player}; \node[rotate=90] at ($(v.north west) - (0.3cm, 0.0cm)$) {\boldred{interface}}; \end{tikzpicture} } :::: ::: ## \faIcon{desktop} Arbeitsauftrag: Interaktive Objekte verwalten \hfill{} 10min \let\tightlist\relax * Implementiere in einer *neuen Datei* das Interface `InteractiveElement`: ```java interface InteractiveElement { void onCollisionWithPlayer(Player player, JumpNRun jumpNRun); } ``` * Ergänze die Klasse `Level` um das Attribut `interactiveObjects`, das die *Gruppe* aller interaktiver Objekte speichern soll. * Zerstöre auch alle interaktiven Objekte, wenn das gesamte Level zerstört wird. (**Tipp:** `Level.destroy() { ... }`{.java}) ## \faIcon{desktop} Arbeitsauftrag: Mit interaktiven Objekte interagieren \hfill{} 10min \vspace{-0.2cm} ::: {.columns align=center} :::: {.column width=55%} Damit etwas passiert, wenn der Spieler ein interaktives Objekt berührt, wollen wir `onCollisionWithPlayer(Player, JumpNRun)`{.java} bei einer Kollision aufrufen. :::: :::: {.column width=45%} \begin{tcolorbox}[title=Interaktions Beispiele, colframe=green!80!black] \small \begin{itemize} \setlength\itemsep{-2mm} \item \textit{Flagge -> Level wechseln} \item \textit{Gegner -> Leben verlieren} \item \textit{...} \end{itemize} \end{tcolorbox} :::: ::: \let\tightlist\relax * Ergänze die Methode `act` der Klasse `Player`, um die Kollisionserkennung mit allen interaktiven Objekten eines Levels. (**Tipp**: Du kannst viel von der Kollisionserkennung der `solidObjekts` kopieren.) * Rufe für jedes kollidierende interaktive Objekt die Methode `onCollisionWithPlayer` mit dem Player Objekt (`this`{.java}) und dem gesamten `jumpNRun` Spiel-Objekts auf. (**Hinweis**: Um die Methode `onCollisionWithPlayer`{.java} aufzurufen, musst das Objekt vom Typ `InteractiveElement` sein. Wandle das Shape mit dem [Cast](https://inf-schule.de/oop/java/experten/vererbung/konzept_typumwandlung): `((InteractiveElement)shape).onC...`{.java}) ## \faIcon{desktop} Arbeitsauftrag: Ziel in Sicht \hfill{} 10min \let\tightlist\relax * Implementiere die Klasse `Goal` die von der Klasse `Sprite` **erbt** und das Interface `InteraktiveElement` **implementiert** (`implements InteractiveElement`{.java}). * Implementiere den Konstruktor der Klasse `Goal`. * Wähle das Sprite **160** aus der Sprite-Bibliothek `SpriteLibrary.Plattforms` aus. (`super(x, y, SpriteLibrary.Plattforms, 160);`{.java}) * Mit der Anweisung `playAnimation(160, 161, RepeatType.loop, 3);`{.java} lässt du die Flagge im "Wind" wehen. * Implementiere die Methode `onCollisionWithPlayer` der Klasse `Goal`, die zum nächsten Level weiter schaltet. (**Tipp:** Implementiere die Methode `JumpNRun.nextLevel(Level level)` und rufe sie mit dem Nachfolger des aktuellen Levels auf) ## \faIcon{desktop} Arbeitsauftrag: Baue dein eigenes Spiel Verändere das nun fertige Grundspiel nach deinen Vorstellungen. ### Vorschläge {.example} * Ergänze eine Stoppuhr pro Level. * Füge sich bewegende Hindernisse/Gegner hinzu. * Ergänze Powerups die eingesammelt werden können. * Erweitere das Spiel um einen zweiten Spieler. * ... ## {.standout} Dieses Werk ist lizenziert unter einer [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/) Lizenz \faCreativeCommons\ \faCreativeCommonsBy\ \faCreativeCommonsSa.