diff options
| -rw-r--r-- | Info/10/2/JumpNRun/img/oide_mouse_coordinates.png | bin | 0 -> 6562 bytes | |||
| -rw-r--r-- | Info/10/2/JumpNRun/slides.md | 289 |
2 files changed, 123 insertions, 166 deletions
diff --git a/Info/10/2/JumpNRun/img/oide_mouse_coordinates.png b/Info/10/2/JumpNRun/img/oide_mouse_coordinates.png Binary files differnew file mode 100644 index 00000000..27482880 --- /dev/null +++ b/Info/10/2/JumpNRun/img/oide_mouse_coordinates.png diff --git a/Info/10/2/JumpNRun/slides.md b/Info/10/2/JumpNRun/slides.md index afac3e84..16c4d61c 100644 --- a/Info/10/2/JumpNRun/slides.md +++ b/Info/10/2/JumpNRun/slides.md @@ -40,12 +40,14 @@ aspectratio: 169 * Bewegen * Springen -\vspace{-0.3cm} +\vspace{-0.2cm} ### Flagge +\vspace{-0.3cm} * Position -\vspace{-0.3cm} +\vspace{-0.2cm} ### Plattform +\vspace{-0.3cm} * Position * Höhe * Breite @@ -108,7 +110,7 @@ aspectratio: 169 \attribute{interaktiveObjekte} \end{class} - \begin{class}[text width=3cm]{Spiel}{0,-2.5} + \begin{class}[text width=3cm]{Spiel}{0,-4.5} \attribute{level} \attribute{player} \end{class} @@ -142,15 +144,15 @@ aspectratio: 169 \attribute{Level} \attribute{Player} \end{class} - \association{Spiel}{}{}{Spieler}{1}{}; + \association{Spiel}{}{enthält}{Spieler}{1}{}; \begin{class}[text width=3cm]{Level}{1,-4.5} \attribute{festeObjekte} \attribute{interaktiveObjekte} \end{class} - \association{Spiel}{}{}{Level}{1}{}; + \association{Spiel}{}{ist aktiv}{Level}{1}{}; \association{Level}{}{}{Flagge}{}{}; - \association{Level}{}{}{Platform}{n}{}; + \association{Level}{}{enthält}{Platform}{n}{}; \end{tikzpicture} ## {.standout} @@ -234,13 +236,13 @@ solange Spiel aktiv <- Online-IDE ::: {.columns} :::: {.column width=75%} -Wir erfüllen mit unserer `Spieler`-Klasse das \boldred{interface}, das die Online-IDE vorgibt. +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 `Actor`. +Um automatisch das Interface zu erfüllen, erben wir von der Klasse `Sprite` bzw. `Actor`. :::: :::: {.column width=25%} @@ -284,7 +286,7 @@ Um automatisch das Interface zu erfüllen, erben wir von der Klasse `Actor`. \pause **Java** -`class Player extends Actor`{.java} +`class Player extends Sprite`{.java} \pause @@ -351,6 +353,31 @@ Wir haben die Methoden bereits von der Klasse `Actor` geerbt. * `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%} +{.center height=60%} + +Die Koordinaten des Mauszeigers werden über dem Spielfeld angezeigt. +:::: +::: + + ## \faIcon{desktop} Arbeitsauftrag: Los gehts! \hfill 10 min \let\tightlist\relax @@ -361,14 +388,14 @@ Wir haben die Methoden bereits von der Klasse `Actor` geerbt. ## \faIcon{desktop} Arbeitsauftrag: Spieler bewegen \hfill 15 min -Vervollständige die Methode `act` des Spielers +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` + **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. + Setzte ihre Geschwindigkeit in X-Richtung auf $80\%$ des aktuellen Werts. \faIcon{play} Teste deine Implementierung. @@ -384,7 +411,7 @@ Vervollständige die Methode `act` des Spielers ## \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` soll sich ihre Geschwindigkeit in Y-Richtung `vy` um `sprung` erhöhen. +*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. @@ -404,11 +431,13 @@ Die Figur soll in die Richtung ihrer Bewegung blicken. ## 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,-4.5} + \begin{class}[text width=4cm]{Plattform}{0,-3.5} \attribute{position} \attribute{hoehe} \attribute{breite} @@ -418,11 +447,9 @@ Die Figur soll in die Richtung ihrer Bewegung blicken. \attribute{festeObjekte} \attribute{interaktiveObjekte} \end{class} + \association{Plattform}{n}{}{Level}{enthält}{1}; \end{tikzpicture} \end{center} - -\vspace{1cm} -Ein Level soll mehrer feste Plattformen haben. :::: :::: {.column width=50%} @@ -430,196 +457,126 @@ Ein Level soll mehrer feste Plattformen haben. :::: ::: -<!-- -## Zufall +## \faIcon{lightbulb} Plattformen und Level -Die Java Klasse `java.util.Random` stellt *pseudo* zufällige Zahlen bereit. +### Klassiker -\pause -### Verwendung +Wie speichern wir mehrere Plattformen in einem Level? -* 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$\rightarrow$ mit einem Feld (`Platform[]`{.java})! \pause -### Größe des Welt +### **Besser:** `Group` -Das Zeichenfenster misst 800x600 Pixel. +Die Online-IDE bietet die Klasse `Group` zur Verwaltung mehrer graphischer Objekte (`Shape`). -## Tischlein deck dich +**Methoden**: -::: {.columns} -:::: {.column width=50%} - -:::: - -:::: {.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); - } - ... -} -``` -:::: -::: +* `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 -## Wachstum +\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. +* Die Methode `Level next()`{.java} soll nichts zurückgeben, da es kein zweites Level gibt (`return null;`{.java}). +* Implementiere die Methode `void spawnPlayer(Player player)`{.java} und setzte das `player` Objekt an eine geeignete Startposition (`100, 400`). -Die Schlange soll im Laufe des Spiels länger werden. +## \faIcon{desktop} Arbeitsauftrag: Spielstart \hfill{} 5min -**\faIcon{lightbulb} Welcher Datentyp eignet sich dazu eine unbekannte Anzahl an Rechtecken zuspeichern?** -\pause +Vervollständige den Konstruktor der Klasse `JumpNRun`. -### Das Attribut `koerper` +\let\tightlist\relax +* Erzeuge in `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. -* 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. +\faIcon{play} Teste deine Implementierung. -## Bewegung +## {.standout} -**\faIcon{lightbulb} Wie kommt die Schlange um die Ecke?** +Wir fallen einfach durch den Boden! -\pause +## \only<2->{Kollision} -::: {.columns align=center} -:::: {.column width=50%} -\only<3>{Jedes Körperteil folgt seinem Vorgänger.} -:::: +\faIcon{lightbulb} Wie erkennen wir, dass zwei graphische Objekte sich berühren? -:::: {.column width=50%} -{.center width=100%} -:::: -::: - -## Bewegung +\pause +Wir müssen prüfen, ob sie sich in \emph{mindestens} einem Punkt im Koordinatensystem überschneiden. -```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() - ... -} +\pause +```\begin{pseudocode}```{=latex} ``` +für alle Objekte + für alle anderen Objekte + Finde Überschneidung + Falls Überschneidung + Behandle Überschneidung +``` +```\end{pseudocode}```{=latex} -# Phase III - Kollisionserkennung - -## Wann frisst die Schlange das Essen - -::: {.columns align=center} -:::: {.column width=50%} -\vspace{0.3cm} - -:::: - -:::: {.column width=50%} -Berührt der Kopf das Essen? -:::: -::: +## Kollision: Online-IDE -## Wann frisst die Schlange das Essen +Damit wir nicht selbst prüfen müssen, ob sich Objekte berühren, fragen wir einfach die Online-IDE. -### \faIcon{lightbulb} Wo findet die Überprüfung statt? -\pause -In der `Ausführen`-Methode der Welt-Klasse `Snake`, da +Die Methode `getCollidingShapes(Group g)`{.java} eines `Sprite` Objektes gibt alle Objekte einer Gruppe `g` zurück, die mit dem `Sprite` kollidieren. ->- dort Schlange und Essen bekannt sind ->- dort die Schlange bewegt wird +Mit der `foreach`-Variante der `for`-Schleife können wir alle Kollisionen behandeln. -\pause -### Pseudocode -``` -Schlange bewegen -Falls Kopf das Essen berührt - entferne Essen - Schlange wachse +```java +Shape[] collidingShapes = getCollidingShapes(jumpNRun.level.solidObjects); +for (Shape shape: collidingShapes) { + // Behandle Kollision +} ``` -## Kollision mit dem Rand der Welt - -::: {.columns align=center} -:::: {.column width=50%} -\vspace{0.3cm} - -:::: +## \faIcon{desktop} Arbeitsauftrag: Kollision erkennen \hfill{} 5min -:::: {.column width=50%} -Ist die Position des Kopfes noch Teil der Welt? -:::: -::: +Implementiere in der `void act()`{.java} des Spielers die Kollisionserkennung. -## Kollision mit dem Rand der Welt +\let\tightlist\relax +* Speichere alle \emph{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{lightbulb} Wo findet die Überprüfung statt? -\pause -In der `bewegen`-Methode der Klasse `Schlange`, nachdem der Kopf bewegt wurde +## \faIcon{desktop} Arbeitsauftrag: Kollision behandeln \hfill{} 10min -### \faIcon{lightbulb} Woher weiß das Spiel das die Schlange kollidiert ist? -\pause -Die Methode `bewegen` gibt einen Wahrheitswert zurück, ob sie erfolgreich war. +\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} -\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 -``` +Implementiere `void reactToCollisionWithShape(Shape shape)`{.java} im Spieler: -## Kollision mit sich selbst +* 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 \emph{nicht} zur Kollision führt. + -::: {.columns align=center} -:::: {.column width=50%} -\vspace{0.3cm} - -:::: +## \faIcon{desktop} Arbeitsauftrag: Auf dem Boden stehen \hfill{} 10min -:::: {.column width=50%} -Berührt der Kopf der Schlange eins der eigenen Körperteile? -:::: +:::{.block} +### Wir wollen erkennen, wann wir auf festem Boden stehen! +* Springen erlauben +* Laufanimation abspielen ::: -## 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. +Das Attribut `Shape standsOn`{.java} der Klasse `Player` merkt sich auf welchem Shape der Spieler steht. -\pause -### Pseudocode -``` -Koerper bewegen -Kopf bewegen -... - -Für jedes koerperteil hinter dem kopf - Falls kopf beruehrt koerperteil - return false - -return true -``` +* (Ergänze das `standsOn` Attribut vom Typ `Shape` in der Klasse `Player`) +* (Ändere die Gravitation zu einer Prüfung `standsOn == null`) +* Bei Kollision von \emph{oben}, speichere das kollidierende `shape` im Attribut `standsOn`. +* Überprüfe vor der Kollisionserkennung, ob der Spieler noch mit einem möglicherweise gespeicherten `standsOn` Objekt kollidiert. (`standOn != null && !collidesWith(standsOn)`{.java}) +* \emph{Falls nein} setze `standOn` auf `null`{.java} ## {.standout} Dieses Werk ist lizenziert unter einer [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/) Lizenz \faCreativeCommons\ \faCreativeCommonsBy\ \faCreativeCommonsSa. ---> |
