Hier werden die Unterschiede zwischen zwei Versionen gezeigt.
Beide Seiten der vorigen Revision Vorhergehende Überarbeitung Nächste Überarbeitung | Vorhergehende Überarbeitung | ||
ws1718:projektplanung [2018/03/28 17:37] daphna_99 [Klassen] |
ws1718:projektplanung [2018/04/05 12:08] (aktuell) daphna_99 [Hilfsmittel] |
||
---|---|---|---|
Zeile 18: | Zeile 18: | ||
Vielmehr setzten wir uns dann wöchentliche Ziele, die wir abarbeiteten. Die wichtigsten Punkte sind dabei folgende gewesen: | Vielmehr setzten wir uns dann wöchentliche Ziele, die wir abarbeiteten. Die wichtigsten Punkte sind dabei folgende gewesen: | ||
* Anfang des Hauptcodes CreatureR: Klasse für die Entstehung der Kreaturen, deren Fortbewegung und deren Bewertung | * Anfang des Hauptcodes CreatureR: Klasse für die Entstehung der Kreaturen, deren Fortbewegung und deren Bewertung | ||
- | * Anfänge mit pygame -> Umfeld erschaffen | + | * Anfänge mit PyGame -> Umfeld erschaffen |
* Vererbung durch Selektierung | * Vererbung durch Selektierung | ||
* Neustrukturierung des Hauptcodes Creature und Anpassung an den Visualiserungscode pygame | * Neustrukturierung des Hauptcodes Creature und Anpassung an den Visualiserungscode pygame | ||
* Design | * Design | ||
* mehrere Kreaturen gleichzeitig visualisieren und vererben lassen | * mehrere Kreaturen gleichzeitig visualisieren und vererben lassen | ||
- | * unterschiedliche Spezien erzeugen und Visualisieren | + | * unterschiedliche Spezies erzeugen und visualisieren |
+ | ==== Hilfsmittel ==== | ||
+ | * vorgegebenes Lehrmaterial für die Programmiersprache Python | ||
+ | * [[https://www.youtube.com/channel/UCNaPQ5uLX5iIEHUCLmfAgKg|KidsCanCode YouTube-Channel]] für die Visualisierung mit PyGame | ||
+ | * [[https://www.pygame.org/docs/|Pygame Dokumentation]] für die Visualisierung mit PyGame | ||
+ | * Stack Overflow bei Fragen zur Programmierung | ||
+ | * GIMP zum Freistellen der Bilder | ||
+ | ====Aufgabenverteilung==== | ||
+ | * Lorenz: Programmierung am Hauptcode | ||
+ | * Lena: Visualisierung mit PyGame | ||
+ | * Daphna: Visualisierung mit PyGame und Illustration | ||
- | =====Das ist Doof(Pygame)===== | + | ==== voraussichtliche Bestandteile des Projekts ==== |
- | PyGame bot uns im Gegensatz zu Turtle wesentlich umfangreichere Visualisierungsmöglichkeiten für unser Projekt. Einer der wichtigsten Vorteile dieses Pakets war dabei, dass wir damit in der Lage dazu waren, mehrere Kreaturen gleichzeitig auf dem Bildschirm erscheinen zu lassen. Mit Turtle konnte man Maximal eine Kreatur beobachten und so zwar den Hauptcode verbessern, aber nicht das volle Ausmaß dessen graphisch darstellen. | + | Unser Projekt setzt sich aus dem Hauptcode "CreatureR.py" bzw. der neuen Version "creatureV2.py" und dem Visulaisierungscode "pygamevisualisierung.py" (neue Version: pygamevisuV2.py) zusammen. Außerhalb der Programmierung spielt auch die **Illustration** eine Rolle.\\ |
- | Wie der Name schon sagt ist PyGame an sich für Videospiee mit Python entwickelt worden und ist leider entsprechend nicht besonders gut dokumentiert. Die beste Dokumentation, die wir gefunden hatten waren die Tutorials von KidsCanCode auf YouTube.\\ | + | |
- | Das grundsätzliche Konzept eines jeden Spiels also auch eines Spiels, das man mit Pyhtn programmiert ist die sogenannte Game Loop. Diese sorgt dafür, dass das Spiel angezeigt wird und sich je nach bestimmten Inputs etwas auf dem Bildschirm verändert. \\ | + | |
- | Auf dem Folgenden Bild erkennt man die Bestandteile eines Game Loops, in die der Sceleton eines PyGame Projekts auch im Groben unterteilt.\newline | + | |
- | Der Processing Input ist alles, was extern vom Code selbst eingegeben wird. Dazu gehören z.B. Interaktionen mit der Maus oder den Tasten auf dem Keyboard. Auch so etwas wie ein „x“ am oberen Fensterrrand zum Schließen des Programms muss in diesen Bereich des Codes eingebaut werden.\\ | + | Der **Hauptcode** unterteilt sich vor Allem in: |
- | In der Update Section werden in jedem Frame die neuen Daten verarbeitet, die sich seit dem letzten Frame verändert haben, in unserem Fall also jegliche Fortbewegungne er Kreaturen.\newline | + | * die Creature-Klasse |
+ | * die Coord-Klasse | ||
+ | * diverse Funktionen zur Umsetzung des Ratings\\ | ||
- | Die Render Section kann man auch als rawing section bezeichen Sie lässt die daten, die beim Updaten sih verändert haben auf dem Bildschirm ausgeben. \newline | + | Der **Visualisierungscode** besteht aus: |
+ | * der CREA-Klasse für die Kreaturen | ||
+ | * den DROP-,CLOUD- und STAFI-Klassen für die Hindernisse und Plattformen | ||
+ | * den bubbly()-, newGen()-, stats()-Funktionen für die Umsetzung der Selektion | ||
+ | * den draw()-Funktionen zur Ausgabe von Text auf dem Bildschirm\\ | ||
- | Die Uhr am ende der gameloop soll symbolisieren, dass die Game loop sich in jedem Frame wiederholt und so eine Game Loop sich innerhalb von einer Sekunde z.B. 24 mal ( 24 fps = Anzahl an Frames für ein bewegtes Bild) oder auch 60 Mal (Frame rate moderner videospiele) wiederholen kann. Je nach dem wie gut der Prozessor des zum Ausführen verwendeten endgerätes ist, kann das Programm dann auch bei einer zu hohen Frame-Rate ruckeln oder hängen. \newline | ||
- | Nach dieser etwas längeren Einführung nun zum eigentlichen Code. \newline | ||
- | ====PyGame Sceleton==== | ||
- | Die Notwendigen Bestandteile eines PyGame Codes haben wir so gut wie eins zu eins aus dem „Sceleton Code“ von Kids Can Code (Github link) übernommen. Da dieser für jedes PyGame Projekt so gut wie gleich ist, werden wir ihn an dieser stelle nicht näher erklären, sondern auf das zugehörige Tutorial verweisen. \\ | ||
- | Nun aber wirklich zu **unserem** Code: | ||
- | ====Klassen==== | ||
- | ===Hindernisse=== | ||
- | Beginnen wir mit den **Klassen**: | ||
- | |||
- | Für alle Hindernisse, die auf unserer Karte zu sehen sind (namentlich die Regentropfen, die Wolke und die Plattformen) haben wir Klassen angelegt. | ||
- | Von der Struktur her sind die Klassen sehr ähnlich weswegen hier nun exemplarisch eine erklärt wird. | ||
- | |||
- | Das ist die Klasse für unsere **Regentropfen**: | ||
- | <code python> | ||
- | class DROP(pygame.sprite.Sprite): | ||
- | """Regentropfen""" | ||
- | |||
- | def __init__(self, x, y): | ||
- | pygame.sprite.Sprite.__init__(self) | ||
- | |||
- | self.x = x | ||
- | self.y = y | ||
- | |||
- | self.image = pygame.image.load(os.path.join(img_folder, "drop.png")).convert() | ||
- | self.image.set_colorkey(BLACK) | ||
- | self.image = pygame.transform.scale(self.image, (30,50)) | ||
- | self.mask = pygame.mask.from_surface(self.image) | ||
- | self.rect = self.image.get_rect() | ||
- | self.rect.center = (self.x, self.y) | ||
- | </code> | ||
- | |||
- | Der Klasse wird ein PyGame Sprite übergeben. Da alle Objekte in PyGame als Sprites bezeichnet werden, ist dies an dieser Stelle obligatorisch.\\ | ||
- | Genauso muss in jeder Klasse eine <nowiki>__init__</nowiki>-Funktion enthalten sein, der die relevanten Variablen (in diesem Fall z.B. die x- und y-Koordniaten) übergeben werden, die für die Vorgänge in der Klasse benötigt werden. \\ | ||
- | Als erste Zeile in dieser Funktion muss zudem die <nowiki>__init__</nowiki>-Funktion selbst initialisiert werden. | ||
- | Darauf folgt das Einbauen und Positionieren der Regentropfen-Bilder.\\ | ||
- | Die übergebenen x- und y-Koordinaten müssen in der Funktion zur weiteren Verwendung mit ihrer eigenen Selbstreferenz gleichgesetzt werden.\\ | ||
- | Mit den drei Zeilen, die mit „self.image“ beginnen wird zuerst erreicht, dass das Bild namens "drop.png" aus einem extra Ordner namens "img" geladen wird. Der ".convert()"-Befehl muss an das Ende des Ausdrucks gesetzt werden, sonst entsteht eventuell eine falsche Darstellung des eigentlichen Bildes. \\ | ||
- | Der "set_colorkey"-Befehl Entfernt jegliche Stellen im Bild mit der vermerkten Farbe. Alle selbstgezeichneten Bilder wurden freigestellt und mit einem schwarzen Hintergrund ausgestattet, sodass durch diesen Befehl das Bild ohne schwarzen Hintergrund auf dem Bildschirm zu sehen ist. \\ | ||
- | Der transform.scale(), der in der darauffolgenden Zeile verwenden wird, gibt uns die Möglichkeit ohne zusätzliche Bildbearbeitung, sondern direkt in PyGame die Größe des Bildes bequem anzupassen. Dabei steht die erste Zahl in den Klammern für die Länge und die zweite für die Breite. \\ | ||
- | Bevor die nächste Zeile versanden werden kann, ist es wichtig die zwei "self.rect"-Zeilen danach zu erklären. Hier wird nämlich erstmal ein Rechteck (rect) um unseren Regentropfen erstellt und im Weiteren mit dem ".center"-Befehl wird dieses Rechteck an das Zentrum der Version des Bildes mit schwarzem Hintergrund gelegt. Das ist bei jedem PyGame-Sprite erforderlich, damit Pygame das Bild auch als Objekt wahrnehmen und nach verfolgen kann. Zwar können Bilder freigestellt werden, jedoch gelten sie im PyGame-Algorithmus nur als Rechtecke mit speziellen Eigenschaften. | ||
- | An dieser Stelle kommt die "self.mask"-Zeile ins Spiel, die zuerst ausgelassen wurde. \\ | ||
- | Wir möchten bei unseren Hindernissen und auch später bei unseren Kreaturen nicht, dass (selbst wenn man es wegen den freigestellten Bildern so nicht sieht) nur die Rechtecke um die Obejekte herum mit einander kollidieren, sondern die Umrisse der Bilder, wie sie durch die freigestellten Bilder sichtbar sind. Dafür wird eine Maske (mask) erstellt. Diese Maske wird bei der Kollision weiterverwendet werden. | ||
- | |||
- | ===Kreaturen=== | ||
- | Das ist die Klasse für unsere Kreaturen: | ||
- | <code python> | ||
- | |||
- | class CREA(pygame.sprite.Sprite): | ||
- | |||
- | """erstellt die kreaturen""" | ||
- | |||
- | def __init__(self,spec): | ||
- | pygame.sprite.Sprite.__init__(self) | ||
- | self.c1 = cr.Creature(species=spec) | ||
- | self.c1.milkAppend() | ||
- | self.apCounter = self.c1.species[3] | ||
- | self.image = all_images[spec] | ||
- | |||
- | self.spec = spec | ||
- | self.rect = self.image.get_rect() | ||
- | self.rect.center = (0,0) | ||
- | |||
- | self.block_index = 0 | ||
- | |||
- | def update(self): | ||
- | if self.block_index < len(self.c1.milkyway): | ||
- | block = self.c1.milkyway[self.block_index] | ||
- | self.block_index += 1 | ||
- | self.c1.moveFurther(block) | ||
- | self.rect.center = (self.c1.xcor+100,self.c1.ycor+360) | ||
- | |||
- | if self.apCounter == 1 and self.c1.survivaltimer < moveCap and not self.c1.dead: | ||
- | self.c1.milkAppend() | ||
- | self.apCounter = self.c1.species[3] | ||
- | elif self.apCounter > 1: | ||
- | self.apCounter -= 1 | ||
- | |||
- | else: | ||
- | self.c1.dead = True | ||
- | |||
- | if (self.c1.xcor+100) < 0 or (self.c1.xcor+100) > 1000: | ||
- | self.c1.dead = True | ||
- | |||
- | |||
- | if (self.c1.ycor+360) < 0 or (self.c1.ycor+360) > 720: | ||
- | self.c1.dead = True | ||
- | </code> | ||
- | ====Funktionen==== | ||
- | ===für die Kreaturen=== | ||
- | [Blackbox] | ||
- | ===für die Ausgabe auf dem Bildschirm=== | ||
- | ==draw== | ||
- | <code python> | ||
- | def draw(): | ||
- | #->screen | ||
- | screen.fill(BLACK) | ||
- | screen.blit(background, (0,0)) | ||
- | pygame.draw.rect(screen, ROSE, [1000, 0, 280, 720]) | ||
- | pygame.draw.rect(screen, BLACK, [1000, 0, 280, 720], 2) | ||
- | pygame.draw.rect(screen, BLACK, [0, 0, 1000, 720], 2) | ||
- | |||
- | #->sprites | ||
- | all_sprites.draw(screen) | ||
- | #->Text | ||
- | draw_text(screen,("Start"), 25, 65,320) | ||
- | draw_text(screen,("Ziel"), 25, 870,320) | ||
- | draw_text(screen,("Generation: " + str(gencnt)), 30, 1050,10) | ||
- | draw_text(screen,("Sieger: " + str(finpergencnt)), 30, 1050,50) | ||
- | draw_text(screen,("Rating: " + str(int(ratingcnt/amountEnt))), 30, 1050, 90) | ||
- | draw_text(screen,("Einhorn:"), 18, 1050,150) | ||
- | draw_text(screen,("Pinguin:" ), 18, 1050,200) | ||
- | draw_text(screen,("Schmetterling:"), 18, 1050,250) | ||
- | |||
- | #->Balken | ||
- | draw_bar(screen, 1050,170, speccnt[0], WHITE) | ||
- | draw_bar(screen, 1050,220, speccnt[1], BLACK) | ||
- | draw_bar(screen, 1050,270, speccnt[2], YELLOW) | ||
- | </code> | ||
- | ==draw_text== | ||
- | <code python> | ||
- | def draw_text(surf,text,size,x,y): | ||
- | """ ermöglicht das Schreiben in den screen """ | ||
- | font= pygame.font.Font(font_name, size) | ||
- | text_surface = font.render(text, True, BLACK) | ||
- | text_rect = text_surface.get_rect() | ||
- | text_rect.topleft=(x,y) | ||
- | surf.blit(text_surface,text_rect) | ||
- | </code> | ||
- | ==draw_bar== | ||
- | <code python> | ||
- | def draw_bar(surf, x, y, pct, clr): | ||
- | """ zeicnet Balken für die Skala """ | ||
- | if pct < 0: | ||
- | pct = 0 | ||
- | BAR_LENGTH = 100 | ||
- | BAR_HEIGHT = 20 | ||
- | fill = (pct/100.*BAR_LENGTH) | ||
- | outline_rect = pygame.Rect(x,y,BAR_LENGTH, BAR_HEIGHT) | ||
- | fill_rect = pygame.Rect(x,y,fill,BAR_HEIGHT) | ||
- | pygame.draw.rect(surf,clr,fill_rect) | ||
- | pygame.draw.rect(surf, BLACK, outline_rect,2) | ||
- | </code> |