From fb2812be04f4be4368a255d5a883473879f885d6 Mon Sep 17 00:00:00 2001 From: Florian Fischer Date: Sat, 14 Mar 2026 12:14:12 +0100 Subject: add the second exercise sheet --- Info/10/2/JumpNRun/arbeitsauftrag2.tex | 187 ++++++++++++++++++++++----------- Info/10/2/JumpNRun/slides.md | 4 +- 2 files changed, 126 insertions(+), 65 deletions(-) diff --git a/Info/10/2/JumpNRun/arbeitsauftrag2.tex b/Info/10/2/JumpNRun/arbeitsauftrag2.tex index f886d958..abf8f818 100644 --- a/Info/10/2/JumpNRun/arbeitsauftrag2.tex +++ b/Info/10/2/JumpNRun/arbeitsauftrag2.tex @@ -5,99 +5,160 @@ \usepackage[ngerman]{babel} \geometry{margin=2cm} -\newcommand{\Snake}{\texttt{Snake}} +\usetikzlibrary{calc, shapes.arrows} -\title{Snake Arbeitsauftrag 2} +\title{JumpNRun Arbeitsauftrag 2} \setcounter{section}{2} \begin{document} \thispagestyle{empty} -\subsection{\faIcon{desktop} Essen} +\subsection{Weiterarbeiten} + +\begin{tcolorbox} +Du kannst mit deinem eigenen Projekt weiterarbeiten oder du verwendest den Workspace \textbf{JumpNRun Vorlage 2}. +Wenn du mit der Vorlage weiterarbeitest, kannst die manchne Schritte der Arbeitsaufträge in runden Klammern auslassen, da diese in der Vorlage schon enthalten sind. +\end{tcolorbox} + +\subsection{\faIcon{desktop} Plattformen und Level} +Ein Level besteht aus soliden - unbeweglichen und undurchlässigen - Plattformen. +Außerdem, soll ein Level zum nächsten Level weiterleiten können und die Startposition des Spielers festlegen. + +\begin{tabular}{p{0.325\textwidth} p{0.675\textwidth}} +\vspace{0mm} +\begin{tikzpicture} + \begin{class}[text width=4.75cm]{Level}{0,0} + \attribute{festeObjekte} + \attribute{interaktiveObjekte} + \operation{next(): Level} + \operation{spawnPlayer(Player player)} + \end{class} +\end{tikzpicture} & +\begin{defbox}{Objekte gruppieren} +Die Online-IDE bietet die Klasse `Group` um mehrere graphische Objekte zu verwalten. +Wir benötigen folgende Methoden: \begin{itemize} -\item Erstelle eine neue Klasse \texttt{Essen}. -\item Ergänze die Klasse Essen um ein \textit{Attribut} \texttt{symbol} vom Typ \texttt{Rechteck}/ -\item Implementiere den \textit{Konstruktor} der Klasse \texttt{Essen}: - \begin{itemize} - \item Es soll die Position übergeben werden. - \item Initialisiere \texttt{symbol} mit einem neuen roten Rechteck an der richtigen Position mit der Größe 20x20. - \end{itemize} -\item Implementiere eine Methode \texttt{entferne()} der Klasse \texttt{Essen}, die das \texttt{symbol} mittels dessen Methode \texttt{Entfernen()} von der Zeichenfläche löscht. -\item Teste deine Klasse \texttt{Essen}, indem du neue Objekte von ihr anlegst und wieder entfernst. + \item \mintinline{java}{void add(T shape)} - Fügt ein Objekt der Gruppe hinzu + \item \mintinline{java}{void destroyAllChildren()} - Zerstört alle Objekte der Gruppe \end{itemize} - -\subsection{\faIcon{desktop} Zeitgesteuertes Essen} -\begin{defbox}{Zeitgesteuerte Ereignisse} -Die Methode \mintinline{java}{public void Ausführen()} unserer Spiel-Klasse wird für jedes neue Bild von der Spiel-Engine aufgerufen. \\[0.2cm] -Um Aktionen in Abhängigkeit von der Zeit auszuführen, müssen wir wissen wie viel „\textit{Zeit}“ bereits vergangen ist. \end{defbox} +\\ +\end{tabular} \begin{itemize} -\item Ergänze die Klasse \Snake{} um eine \textit{Attribut} \texttt{ticks}, das die Anzahl der bereits gezeichneten Bilder speichert. -\item Importiere in der Klasse \Snake{} die Java Klasse \texttt{Random}, indem du außerhalb deiner Klasse \Snake{} die Zeile \mintinline{java}{import java.util.Random;} einfügst. -\item Ergänze die Klasse \Snake{} um ein \textit{Attribut} \texttt{zufall} vom Typ \texttt{Random}, initialisiere das \textit{Attribut} im \textit{Konstruktor}. -\item Ergänze die Methode \mintinline{java}{Snake.Ausführen}: - \begin{itemize} - \item Erhöhe zu Beginn die Anzahl der bereits gezeichneten Bilder. - \item Falls das aktuelle Bild ein Vielfaches von 30 ist: - \begin{itemize} - \item Falls ein Essen in dem \textit{Attribut} \texttt{essen} der Klasse \Snake{} gespeichert ist, entferne es. - \item Erzeuge eine neues \texttt{Essen}-Objekt an einer zufälligen Position (\mintinline{java}{zufall.nextInt(max)} liefert dir eine Zufallszahl zwischen 0 und \texttt{max}). - \end{itemize} - - \end{itemize} -\end{itemize} - -\begin{defbox}{Modulo} -Die \boldred{Modulo-Operation}, in Java das Zeichen \texttt{\%}, liefert als Ergebnis, den Rest der Ganzzahldivision zweier Zahlen. \\[0.1cm] -\textbf{Beispiele}: \mintinline{java}{7 % 3 == 1; 64 % 30 == 4} -\end{defbox} +\item (Implementiere oder Kopiere die Klasse \texttt{Level}) +\item Implementiere die Klasse \texttt{Level1}, die von der Klasse \texttt{Level} erbt. + \item Erzeuge ein Rechteck für den Boden.\newline + (\mintinline{java}{new Rectangle(x, y, breite, hoehe)}) + \item Erzeuge ein Rechteck als linke Spielrand-Begrenzung. + \item Erzeuge vier Rechtecke als aufsteigende Platformen.\newline + Vorschlag: \mintinline{java}{new Rectangle(200 + 450 * i, 470 - 40 * i, 300, 25)} + \item Füge alle erzeugten Rechtecke der \texttt{solidObjekt} Gruppe hinzu. +\item Die Methode \mintinline{java}{Level next()} soll nichts zurückgeben, da es kein zweites Level gibt (\mintinline{java}{return null}). +\item Implementiere die Methode \mintinline{java}{void spawnPlayer(Player player)} und setzte das \texttt{player} Objekt an eine geeignete Startposition (\texttt{100, 400}). +\end{itemize} -\newpage -\subsection{\faIcon{desktop} Wachstum} +\subsection{\faIcon{desktop} Spielstart} -Damit unsere Schlange wachsen kann, muss sie aus mehr Körperteilen als nur dem Kopf bestehen. +Vervollständige den Konstruktor der Klasse \texttt{JumpNRun}. \begin{itemize} -\item Ersetze das \textit{Attribut} Kopf der Schlange durch ein Feld namens \texttt{koerper} vom Typ \texttt{Rechteck}. -\item Initialisiere das Feld im \textit{Konstruktor} der Klasse \texttt{Schlange} mit Länge 0. -\item Ergänze die Klasse \texttt{Schlange} um die Methode \mintinline{java}{wachsen(int x, int y)}: - \begin{itemize} - \item Erzeuge ein neues Feld, das um ein Element länger ist als der aktuelle Körper der Schlange. - \item Erzeuge einen neuen Kopf an der richtigen Position (grün und 20x20 Pixel groß). - \item Speichere den neuen Kopf als erstes Element in dem neu erzeugten Feld. - \item Kopiere alle Elemente des aktuellen Körpers in das neue Feld. \\ - \textbf{Vergiss nicht}: Das neue Feld enthält bereits den Kopf am Index 0. - \item Speichere das neue Feld in dem \textit{Attribut} \texttt{koerper}. - \end{itemize} +\item Erzeuge ein \texttt{Level1} Objekt und initialisiere damit das \texttt{Level} Attribut der Klasse. +\item Rufe die \texttt{spawnPlayer}-Methode des ersten Levels mit dem \texttt{Player} Attribute der Klasse auf. \end{itemize} -\subsection{\faIcon{desktop} Bewegung der Schlange} +\subsection{\faIcon{desktop} Kollision} + +Bisher fällt der Spieler einfach durch den Boden! + +\begin{defbox}{Kollision erkennen} +\begin{tabular}{p{0.5\textwidth} p{0.48\textwidth}} +\vspace{0mm} +Um eine Kollision zwischen zwei Objekten zu erkennen, müssen wir prüfen, ob sie sich in \emph{mindestens} einem Punkt im Koordinatensystem überschneiden. & +\vspace{-0.5cm} +\begin{pseudocode} +\begin{verbatim} +für alle Objekte + für alle anderen Objekte + Finde Überschneidung + Falls Überschneidung + Behandle Überschneidung +\end{verbatim} +\end{pseudocode} \\ +\end{tabular} +\end{defbox} -\begin{defbox}{Bewegung mehrere Körperteile} -\begin{tabular}{p{0.65\textwidth} p{5cm}} -\vspace{-3.5cm} -Es bietet sich an bei der Bewegung der Schlange die Bewegung der Raupen in der Natur nachzuahmen. -Dabei wird jedes Körperteil an die Position des Vorgängers gezogen. +Die Methode \mintinline{java}{getCollidingShapes(Group g)} eines Sprites gibt alle Objekte einer Gruppe \texttt{g} zurück, die mit dem \texttt{Sprite} kollidieren. -Du kannst ein Feld rückwärts durchlaufen, indem du die dir bereits bekannte \mintinline{java}{for} Schleife leicht modifizierst. +Mit der \texttt{foreach}-Variante der \texttt{for}-Schleife können wir alle Kollisionen behandeln. \begin{minted}{java} -for (int i = feld.length -1; i >= 0; i--) { - ... +// Finde alle kollidierenden soliden Objekte des Levels +Shape[] collidingShapes = getCollidingShapes(jumpNRun.level.solidObjects); +for (Shape shape: collidingShapes) { // Betrachte jedes kollidierende Objekt + // Behandle Kollision } \end{minted} + +Implementiere in der \mintinline{java}{void act()} des Spielers die Kollisionserkennung. + +\begin{itemize} +\item Speichere alle \emph{soliden} kollidierenden Objekte, des aktuellen Levels als Variable.\newline + (\mintinline{java}{Shape[] collidingShapes = getCollidingShapes(jumpnrun.level.solidObjects);} +\item Implementiere eine \texttt{foreach}-Wiederholung, die alle kollidierenden Objekte behandeln soll.\newline + (\mintinline{java}|for(Shape shape: collidingShapes) {}|) +\end{itemize} + +\subsection{\faIcon{desktop} Kollision behandeln} + +\begin{defbox}{Kollision was jetzt?} +\begin{tabular}{p{0.37\textwidth} p{0.6\textwidth}} +\vspace{0mm} +\begin{tikzpicture}[scale=0.9] + \node[draw, minimum width=2cm, minimum height=0.5cm] (p) at (0,0) {}; + % \draw[opacity=0.7] (2,2) -- (-2,-2); + % \draw[opacity=0.7] (-2,2) -- (2,-2); + \node[draw, minimum width=2cm, minimum height=0.5cm] (p) at (0,0) {}; + \node[draw, single arrow, below=0.5cm of p, shape border rotate=90] {bottom}; + \node[draw, single arrow, left=0.5cm of p] {left}; + \node[draw, single arrow, right=0.5cm of p, shape border rotate=180 ] {right}; + \node[draw, single arrow, above=0.5cm of p, shape border rotate=270] {top}; +\end{tikzpicture} & -\includegraphics[keepaspectratio, width=5cm]{img/Copyrighted/caterpillar_movement.png} \\ +Der Spieler, soll die aktuelle Bewegung, die zur Kollision geführt hat, rückgängig machen, bis es zu keiner Kollision mehr kommt. \newline\vspace{2mm} + +Die Geschwindigkeit des Spielers muss in die Kollisionsrichtung gestoppt (auf \texttt{0} gesetzt werden). \\ \end{tabular} \end{defbox} +Implementiere im Spieler die Methode \mintinline{java}{void reactToCollisionWithShape(Shape shape)}: + \begin{itemize} -\item Beginnend mit dem letzten Körperteil setze die Position auf die des Körperteils davor. -\item Verschiebe anschließend den Kopf wie gewohnt in die aktuelle Richtung. -\item Teste deine Methoden \texttt{bewegen} und \texttt{wachsen}, indem du alle 40 Bilder die Schlange in die aktuelle Richtung wachsen lässt. +\item Bestimme die Richtung, aus der der Spieler mit \texttt{shape} kollidiert ist.\newline + (\mintinline{java}{Direction direction = directionRelativeTo(shape);}) +\item Setze je nach Richtung (\texttt{top}, \texttt{left}, \texttt{right}, \texttt{bottom}), die Geschwindigkeit dieser Richtung auf 0. +\item Mache die letzte Bewegung mit \mintinline{java}{moveBackFrom(shape, false)} rückgängig.\newline + (\mintinline{java}{moveBackFrom(Shape otherShape, boolean keepColliding)}) +\item Wiederholung die letzte Bewegung in die Richtung, die \emph{nicht} zur Kollision führt. \end{itemize} +\subsection{\faIcon{desktop} Auf dem Boden stehen} + +Bei Kollision \textbf{von oben} wollen wir erkennen, das wir auf festem Boden stehen! +Das erlaubt uns abzuspringen und gegebenenfalls eine Laufanimation anzuzeigen. + +Das Attribut \mintinline{java}{Shape standsOn} der Klasse \texttt{Player} merkt sich auf welchem Shape der Spieler steht. + +\begin{itemize} +\item (Ergänze das \texttt{standsOn} Attribut vom Typ \texttt{Shape} in der Klasse \texttt{Player}) +\item (Ändere die Gravitation zu einer Prüfung \mintinline{java}{standsOn == null}) +\item Bei Kollision von \emph{oben}, speichere das kollidierende \texttt{shape} im Attribut \texttt{standsOn}. +\item Überprüfe vor der Kollisionserkennung, ob der Spieler noch mit einem möglicherweise gespeicherten \texttt{standsOn} Objekt kollidiert. (\mintinline{java}{standOn != null && !collidesWith(standsOn)}) +\item \emph{Falls nein} setze \texttt{standOn} auf \mintinline{java}{null} +\end{itemize} + \vfill Dieses Werk ist lizenziert unter einer \href{https://creativecommons.org/licenses/by-sa/4.0/}{CC BY-SA 4.0} Lizenz \faCreativeCommons\ \faCreativeCommonsBy\ \faCreativeCommonsSa. \end{document} + + diff --git a/Info/10/2/JumpNRun/slides.md b/Info/10/2/JumpNRun/slides.md index 16c4d61c..7217a6b7 100644 --- a/Info/10/2/JumpNRun/slides.md +++ b/Info/10/2/JumpNRun/slides.md @@ -494,7 +494,7 @@ Die Online-IDE bietet die Klasse `Group` zur Verwaltung mehrer graphischer Objek Vervollständige den Konstruktor der Klasse `JumpNRun`. \let\tightlist\relax -* Erzeuge in `Level1` Objekt und initialisiere damit das `Level` Attribut der Klasse `JumpNRun`. +* 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. @@ -572,7 +572,7 @@ Implementiere `void reactToCollisionWithShape(Shape shape)`{.java} im Spieler: 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 Gravitation zu einer Prüfung `standsOn == null`) +* (Ändere die Gravitation zu einer Prüfung `standsOn == null`{.java}) * 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} -- cgit v1.2.3