====== Graphics'n Games-API des Cornelsen-Verlages ====== Die Autoren der [[https://informatikschulbuch.de/|Informatik-Bücher des Cornelsen-Verlages für bayerische Gymnasien]] haben eine API geschrieben, die es auf einfache Weise ermöglicht, kleine Spiele zu programmieren. Diese API heißt "Graphics and Games". Sie wurde von den Buchautoren in den Programmiersprachen Java, Python und Swift implementiert. Damit die Beispiele der Cornelsen-Bücher auch in der Online-IDE lauffähig sind, habe ich die Java-Version der Graphics and Games-API nach Typescript portiert. \\ * Die Vorlagen für die Buchaufgaben finden Sie [[https://informatikschulbuch.de/jahrgangsstufe-9-uebersicht/objektorientierte-modellierung-und-programmierung/|hier auf der Website der Buchautoren]]. * Hier die [[http://gng4java.informatikschulbuch.de/package-summary.html|Dokumentation der Java-Variante der Graphics and Games-API als JavaDoc]]. Im Folgenden eine Beschreibung, wie die Graphics and Games-API in der Online IDE bzw. der Embedded-IDE aktiviert wird sowie eine kurze Dokumentation der API. **Ich kenne die API selbst nur aufgrund der [[http://gng4java.informatikschulbuch.de/package-summary.html|JavaDoc-Beschreibung der Buchautoren]] und der Aufgaben im Buch. Entsprechend erhebt die Dokumentation unten keinen Anspruch auf Vollständigkeit oder Korrektheit.** * Eine einführende Beschreibung der API ist mir nicht bekannt. Falls Sie eine kennen, schreiben Sie mir bitte, ich verlinke sie gerne! * Falls Sie unten Fehler finden oder Verbesserungsbedarf, **schreiben Sie mir bitte**. Vielleicht gibt es sogar jemanden unter Ihnen, die/der es übernehmen möchte, das Kapitel unten zu überarbeiten/vervollständigen? Ich würde mich freuen! ===== Turtle -> GTurtle ===== Leider gibt es zwei Namensüberschneidungen zwischen der API der Online-IDE und der Graphics and Games-API. * Die Klasse ''Turtle'' der Graphics and Games-API heißt in der Online-IDE daher ''GTurtle''. * Die Klasse ''Text'' der Graphics and Games-API heißt in der Online-IDE daher ''GText''. ===== Aktivieren der API in der Online-IDE ===== Da die Klassen der Graphics and Games-API stark unterschiedlichen Konventionen folgen wie die Standardklassen der Online-IDE (Bezeichner von Methoden großgeschrieben, nur ganzzahlige Koordinaten möglich, sehr eingeschränktes Farbschema, ...) und sich die Anwendungsbereiche der Bibliotheken stark überschneiden (Klassen für Rechtecke, Kreise, eine Turtle, ...) ist es nicht sinnvoll, beide APIs zu mischen. Die Graphics and Games-API ist daher standardmäßig ausgeblendet. Will man sie verwenden, so muss man sie je Workspace einmalig aktivieren: \\ - Rechtsklick auf den Workspace -> Einstellungen - Es öffnet sich ein Modales Fenster, das alle möglichen optionalen APIs zeigt. Hier den Haken bei "Graphics and Games-Bibliothek" setzen und mit "OK" bestätigen. ===== Aktivieren der API in der Embedded-IDE ===== Möchte man die Graphics and Games-Bibliothek in den Programmierkästen der **Embedded-IDE** nutzen, so muss bei den Einstellungen das Array "libraries" den Eintrag "gng" besitzen. Hier ein Beispiel:
===== Koordinatensystem ===== Das Koordinatensystem der Graphics and Games-API ist 800 Pixel breit und 600 Pixel hoch. Die x-Achse zeigt nach rechts, die y-Achse zeigt nach **unten**. Der Hintergrund ist immer hellgrau gefärbt. ===== Grundformen =====
Die Klassen ''Rechteck'', ''Dreieck'' und ''Kreis'' für die Grundformen haben jeweils nur einen parameterlosen Konstruktor. Sie erscheinen ohne Rahmen mit der Füllfarbe "rot" und haben folgende Größe/Position: * Das **Rechteck** ist 100 Pixel breit, 100 Pixel hoch und achsenparallel. Seine Linke obere Ecke befindet sich bei (10/10). Drehpunkt ist sein Diagonalenschnittpunkt. Die Methode ''PositionSetzen(x,y)'' verschiebt das Rechteck so, dass seine **linke obere Ecke** am Punkt ''x/y'' zu liegen kommt. * Der **Kreis** hat einen Radius von 50 Pixel, sein Mittelpunkt (= Drehpunkt) befindet sich bei (60/60). Die Methode ''PositionSetzen(x,y)'' verschiebt den Kreis so, dass sein **Mittelpunkt** am Punkt ''x/y'' zu liegen kommt. * Die Eckpunkte des **Dreiecks** haben die Koordinaten ''60/10'', ''110/110'' und ''10/110''. Das Dreieck ist also gleichschenklig, aber nicht gleichseitig. **Drehpunkt** ist der Punkt ''60/60''. Die Methode ''PositionSetzen(x/y)'' verschiebt das Dreieck so, dass der Punkt des Dreiecks, der vorher bei ''60/10'' lag (also die **obere Spitze**), danach bei ''x/y'' liegt. * Das Text-Objekt schreibt initial "Text" ungefähr in die linke obere Ecke. \\ **Gemeinsame Methoden der Grundformen:** \\ * ''Verschieben(int x, int y)'' - verschiebt die Figur um ''x'' Pixel nach rechts und ''y'' Pixel nach unten * ''Drehen(int winkelInGrad)'' - dreht die Figur um ''winkel'' grad gegen den Uhrzeigersinn ( = mathematisch positive Drehrichtung) * ''PositionSetzen(int x, int y)'' - verschiebt die Figur so, dass ein ausgezeichneter Punkt (unterschiedlich je nach Figur, siehe oben) danach bei ''x/y'' liegt. * ''FarbeSetzen(String farbe)'' - ändert die Füllfarbe der Figur. Erlaubt sind die unten angegebenen Farbbezeichner. * ''WinkelSetzen(int winkelInGrad)'' - dreht die Figur **relativ zu ihrer initialen Lage** um den angegebenen Winkel in Grad gegen den Uhrzeigersinn. * ''SichtbarkeitSetzen(boolean sichtbarkeit)'' - macht die Figur sichtbar/unsichtbar. \\ **Bem.:** Kollisionen mit unsichtbaren Figuren werden nicht erkannt. * ''Entfernen()'' - zerstört die Figur * ''GanzNachVornBringen()'' - bringt die Figur ganz nach vorne. Entsprechen ''ganzNachHintenBringen'' * ''NachVorneBringen()'' - bringt die Figur vor diejenige Figur, die sich gerade eine "Schicht" über ihr befindet. \\ **Gemeinsame Attribute der Grundformen:** \\ * ''farbe: String'' * ''x: int'' - x-Koordinate des "Ankers" der Figur (siehe oben) * ''y: int'' - y-Koordinate des "Ankers" der Figur (sihe oben) * ''winkel: int'' - Richtung der Figur (initial: ''winkel == 0'') * ''größe: int'' - Der Wert 100 entspricht der initialen Größe. * ''sichtbar: boolean'' ==== Besondere Attribute/Methoden der einzelnen Grundformen ==== === Rechteck, Dreieck === Die Klassen **Rechteck** und Dreieck besitzen die Attribute ''breite'' und ''höhe'' sowie die Methode ''GrößeSetzen(int breite, int höhe)'', mit der sich die beiden setzen lassen. === Kreis === Die Klasse **Kreis** besitzt das Attribut ''radius'' sowie die Methode ''RadiusSetzen(int radius)'' zum Ändern desselben. === GText === Die Klasse **GText** besitzt die Attribute ''text'' und ''textGröße'' sowie die Methoden ''TextSetzen'' und ''TextGrößeSetzen'' zum Ändern der beiden. Zusätzlich gibt es noch die Methoden ''Textvergrößern'' und ''Textverkleinern'', die die Textgröße ausgehend vom aktuellen Wert nach einem bestimmten Algorithmus verändern [[https://github.com/martin-pabst/Online-IDE/blob/c357875b18ef4840220226d93f2a377b5c48e8be/src/client/runtimelibrary/gng/GNGText.ts#L98|(siehe hier)]]. ===== Mögliche Farbbezeichner ===== * "weiß": 0xffffff, * "weiss": 0xffffff, * "rot": 0xff0000, * "grün": 0x00ff00, * "gruen": 0x00ff00, * "blau": 0x0000ff, * "gelb": 0xffff00, * "magenta": 0xff00ff, * "cyan": 0x00ffff, * "hellgelb": 0xffff80, * "hellgrün": 0x80ff80, * "hellgruen": 0x80ff80, * "orange": 0xff8000, * "braun": 0x804000, * "grau": 0x808080, * "schwarz": 0x000000 ===== Die Klasse GTurtle =====
Die Klasse ''GTurtle'' stellt eine Turtlegrafik dar, ähnlich wie bei der [[https://en.wikipedia.org/wiki/Logo_(programming_language)|Programmiersprache Logo.]]. Eine Schildkröte ("Turtle") bewegt sich über die Zeichenfläche und führt einen Farbstift mit, der ihren zurückgelegten Weg zeichnet. \\ Die Turtle wird durch ein gleichschenkliges Dreick dargestellt, dessen spitz zulaufende Ecke in Richtung ihrer Blickrichtung zeigt. Initial befindet sich die Turtle bei der Position (100/200) und schaut nach rechts ( = 0°). Positive Winkeländerungen bedeuten eine Drehung entgegen dem Uhrzeigersinn ( = mathematisch positive Drehrichtung). \\ \\ **Methoden der Turtle:** * ''Gehen(int länge)'' - lässt die Turtle um die angegebene Länge (in Pixeln) nach vorne gehen. * ''Drehen(int winkel)'' - dreht die Turtle um den angegebenen Winkel (in Pixeln) entgegen dem Uhrzeigersinn. * ''Winkelsetzen(int winkel)'' - dreht die Turtle so, dass sie - ausgehend von ihrer initialen Blickrichtung - in die durch den Winkel angegebene Richtung blickt. * ''GrößeSetzen(int größe)'' - ändert nur die Größe des Dreiecks, das die Turtle darstellt. Dabei ist die initiale Größe 40. * ''FarbeSetzen(string farbe)'' - ändert die Farbe der zukünftig gezeichneten Turtlespur (mögliche Farben siehe oben). * ''StiftHeben()'' - hebt den Stift, so dass die Turtle nachfolgend ihren Weg nicht mehr mitzeichnet. * ''StiftSenken()'' - senkt den Stift, so dass die Turtle nachfolgend ihren Weg (wieder) mitzeichnet. * ''Löschen()'' - löscht alles bisher gezeichnete, setzt die Turtle wieder auf ihre initiale Position (100/200) zurück und dreht sie in ihre initiale Blickrichtung. * ''PositionSetzen(int x, int y)'' - setzt die Turtle auf die angegebene Position. * ''ZumStartpunktGehen()'' - setzt die Turtle auf die Position (100/200). * ''WinkelSetzen(int winkelInGrad)'' - dreht die Turtle zum angegebenen Winkel (0° zeigt nach rechts, positive Winkel entgegen dem Uhrzeigersinn). * ''WinkelGeben()'', ''XPositionGeben()'', ''YPositionGeben'' - geben die entsprechenden Attributwerte zurück * ''Entfernen'', ''NachVorneBringen'', ''NachHintenBringen'', ''GanzNachVorneBringen'', ''GanzNachHintenBringen'' - wie bei den Grundfiguren Rechteck, Dreieck, ... (s.o.) * ''SichtbarkeitSetzen(boolean istSichtbar)'' - macht die Turtle und alles bisher von ihr gezeichnete sichtbar/unsichtbar. * ''Berührt()'' - Gibt genau dann true zurück, wenn sich an der aktuellen Position der Turtle mindestens eine andere Figur befindet. * ''Berührt(String farbe)'' - Gibt genau dann true zurück, wenn sich an der aktuellen Position der Turtle mindestens eine andere Figur mit der angegebenen Farbe befindet. * ''Berührt(Object figur)'' - Gibt genau dann true zurück, wenn die übergebene Figur die aktuelle Turtleposition enthält. * ''AktionAusführen()'' - Diese Methode wird vom Taktgeber aufgerufen und kann überschrieben werden. * ''TasteGedrückt(char taste)'' - Diese Methode wird aufgerufen, wenn der Benutzer eine Taste gedrückt und wieder losgelassen hat. Sie kann überschrieben werden, um auf Tastendrucke zu reagieren. * ''SonderTasteGedrückt(int taste)'' - Diese Methode wird aufgerufen, wenn der Benutzer eine Sondertaste gedrückt und wieder losgelassen hat. Sie kann überschrieben werden, um auf Tastendrucke zu reagieren. Zu den Sondertasten siehe unten. * ''MausGedrückt(int x, int y, int anzahl)'' - Diese Methode wird aufgerufen, wenn mit der linken Maustaste irgendwo in die Zeichenfläche geklickt wurde. Übergeben wird die Position, auf die geklickt wurde und die Anzahl der Klicks. Diese Methode kann überschrieben werden, um auf Mausklicks zu reagieren. Anzahl ist eigentlich immer 1. \\ **Attribute der Klasse GTurtle:** * 'x', 'y': x- bzw. y-Koordinate der Turtle * ''winkel'': Blickwinkel der Turtle in Grad (0° => nach rechts blickend, positive Winkel linksdrehend) * ''sichtbar'': ''true'' genau dann, wenn die Turtle und ihre Zeichnung sichtbar sind. * ''stiftUnten'': ''true'' genau dann, wenn der Stift der Turtle unten ist und die Turtle also beim nächsten Gehen zeichnet. ===== Mögliche Parameterwerte der Methode SondertasteGedrückt ===== * "Enter": 13, * "ArrowLeft": 37, * "ArrowRight": 39, * "ArrowUp": 38, * "ArrowDown": 40, * "PageUp": 33, * "PageDown": 34, * "Insert": 155 ===== Die Klasse Figur ===== Ein Objekt der Klasse ''Figur'' besteht aus beliebig vielen Dreiecken, Rechtecken und Ellipsen. Es kann - ähnlich einer Gruppierung in einem vektororientierten Grafikprogramm - als Ganzes verschoben, gedreht oder gestreckt werden. Zudem kann ermittelt werden, ob es mit anderen graphischen Objekten kollidiert. \\ \\ Ein Objekt der Klasse Figur kann - in Maßen - auch animiert werden. Dazu ist es jedoch nötig, für jeden Animationsschritt alle Bestandteile der Figur zu löschen und neu zu zeichnen. \\ \\ Die Idee hinter der Klasse ''Figur'' ist, eine Unterklasse zu erstellen und mit Methoden zu versehen, die die einzelnen Animationsbilder zeichnen. Durch Überschreiben der Methoden ''TasteGedrückt'', ''SondertasteGedrückt'' und ''Mausgeklickt'' kann man auf Tastatur- und Mausereignisse reagieren. Die Methode ''AktionAusführen'' wird periodisch vom Taktgeber aufgerufen. Durch Überschreiben lässt sich also eine Game Loop-artige Programmierung realisieren. ==== Beispiel: Mit den Cursortasten steuerbares Männchen ====
==== Attribute der Klasse Figur ==== * **int winkel**: Blickrichtung der Figur in Grad. 0° entspricht nach rechts, 90° nach oben usw. * **int größe**: "Größe" der Figur, wobei der Wert 100 der ursprünglichen Größe (ungestreckt) entspricht. * **boolean sichtbar**: ist genau dann true, wenn die Figur sichtbar ist. ==== Methoden der Klasse Figur ==== * **void GrößeSetzen(int größe)**: Setzt die Größe der Figur (d.h. streckt sie entsprechend). ''größe == 100'' entspricht der ursprünglichen Größe der Figur. * **void Drehen(int winkel)**: Dreht die Figur um den angegebenen Winkel im Grad. Positive Werte bewirken eine Drehung entgegen dem Uhrzeigersinn. * **void Gehen(int länge)**: Verschiebt die Figur um die angegebene Länge (in Pixeln) in die aktuelle Blickrichtung. Die initiale Blickrichtung ist nach rechts. Sie kann durch die Methode Drehen verändert werden. * **void PositionSetzen**: Verschiebt die Figur so, dass ihr Anker an der angegebenen Position zu liegen kommt. Der "Anker" ist der Nullpunkt der ''FigurTeilFestlegen''...-Methodenaufrufe unten. * **void ZumStartpunktGehen()**: Entspricht der Anweisung ''PositionSetzen(100, 200)''. * **void WinkelSetzen(int winkel)**: Dreht die Figur so, dass der Blickwinkel der Figur in die angegebene Richtung zeigt. 0° => nach rechts (initial), 90°: => nach oben, usw.. * **int WinkelGeben()**: Gibt den Blickwinkel der Figur zurück. * **int XPositionGeben()**: Gibt die X-Position der Figur zurück. * **int YPositionGeben()**: Gibt die Y-Position der Figur zurück. * **void SichtbarkeitSetzen(boolean sichtbarkeit)**: Macht die Figur sichtbar (''sichtbarkeit == true'') bzw. unsichtbar. * **void GanzNachVornBringen()**: Setzt das Grafikobjekt vor alle anderen. * **void GanzNachHintenBringen()**: Setzt das Grafikobjekt hinter alle anderen. * **void NachVornBringen()**: Setzt das Grafikobjekt eine Ebene nach vorne. * **void NachHintenBringen()**: Setzt das Grafikobjekt eine Ebene nach hinten. * **void EigeneFigurLöschen()**: Löscht die eigene - mittels der Methoden ''FigurTeilFestlegen...'' gezeichnete Figur und ersetzt sie durch die initiale Dreiecksfigur. * **boolean Berührt()**: Gibt genau dann true zurück, wenn die Figur mit einem graphischen Objekt kollidiert. * **boolean Berührt(string farbe)**: Gibt genau dann true zurück, wenn die Figur mit einem graphischen Objekt der angegebenen Farbe kollidiert. * **boolean Berührt(Object objekt)**: Gibt genau dann true zurück, wenn die Figur mit dem übergebenen graphischen Objekt kollidiert. * **void FigurteilFestlegenDreieck(int x1, int y1, int x2, int y2, int x3, int y3, String farbe)**: Erzeugt ein neues, dreieckiges Element und fügt es der Figur hinzu. x1/y1, x2/y2 und x3/y3 sind die drei Eckpunkte des Dreiecks. Die Koordinaten sind relativ zum 'Anker' der Figur, der initial auf der Position (100/200) liegt. * **void FigurteilFestlegenEllipse(int x, int y, int breite, int höhe, String farbe)**: Erzeugt eine Ellipse und fügt sie der Figur hinzu. x/y ist die linke obere Ecke der bounding box der Ellipse (d.h. des kleinsten achsenparallelen umgebenden Rechtecks), ''breite'' und ''höhe'' sind die doppelten Radien in x- bzw. y-Richtung. Die Koordinaten sind relativ zum 'Anker' der Figur, der initial auf der Position (100/200) liegt. * **void FigurteilFestlegenRechteck(int x, int y, int breite, int höhe, String farbe)**: Erzeugt ein achsenparalleles Rechteck und fügt es der Figur hinzu. x/y ist die linke obere Ecke des Rechtecks. Die Koordinaten sind relativ zum 'Anker' der Figur, der initial auf der Position (100/200) liegt. * **void AktionAusführen()**: Diese Methode wird vom Taktgeber aufgerufen. Sie kann überschrieben und mit eigenen Anweisungen gefüllt werden, die dann in periodischen Zeitabständen immer wieder ausgeführt werden. \\ :!: **Wichtig:** Der Taktgeber startet erst nach Aufruf von ''Zeichenfenster.TaktgeberStarten()''. * **void TasteGedrückt(char taste)**: Diese Methode wird aufgerufen, wenn der Benutzer eine Nicht-Sondertaste drückt. Übergeben wird das Zeichen, das der gedrückten Taste entspricht. Diese Methode kann überschrieben und so mit eigenen Anweisungen gefüllt werden, damit das eigene Programm auf Tastendrucke reagieren kann. * **void SonderTasteGedrückt(int taste)**: Diese Methode wird aufgerufen, wenn der Benutzer eine Sondertaste drückt. Übergeben wird das Zeichen, das der gedrückten Taste entspricht. Diese Methode kann überschrieben und so mit eigenen Anweisungen gefüllt werden, damit das eigene Programm auf Tastendrucke reagieren kann. Zur Kodierung der Sondertasten sie Abschnitt 'Kodierung der Sondertasten' auf dieser Seite. * **void MausGeklickt(int x, int y, int anzahl)**: Diese Methode wird aufgerufen, wenn die linke Maustaste (irgendwo im Zeichenbereich, nicht nur auf dem graphischen Objekt) gedrückt wurde. ===== Zeichenfenster, Taktgeber ===== Das Zeichenfenster besitzt statische Methoden zur Steuerung des Taktgebers, zum Auslesen der geometrischen Daten der Malfläche und zum Registrieren von Aktionsempfängern, in denen Man Anweisungen hinterlegen kann, die auf Tastendrucke, Mausklicks und Taktimpulse des Taktgebers reagieren. ==== Methoden der Klasse Zeichenfenster ==== * **static int MalflächenBreiteGeben()**: Gibt die Breite der Zeichenfläche in Pixeln zurück. * **static int MalflächenHöheGeben()**: Gibt die Höhe der Zeichenfläche in Pixeln zurück. * **static void TaktgeberStarten()**: Startet den Taktgeber * **static void TaktgeberStoppen()**: Stoppt den Taktgeber * **static void TaktdauerSetzen(int dauer)**: Setzt die Taktdauer des Zeitgebers in Millisekunden * **static void AktionsEmpfängerEintragen(AktionsempfaengerNeu)**: Trägt einen Aktionsempfänger ein (Observer-Pattern) * **static void AktionsEmpfängerEntfernen(Aktionsempfaenger alt)**: Trägt einen Aktionsempfänger wieder aus (Observer-Pattern) ==== Beispiel 1: Einfacher Timer durch Implementieren des Interfaces Aktionsempfänger ====
==== Beispiel 2: Einfacher Timer durch Erben von der Klasse Ereignisbehandlung ====