Seite anzeigenÄltere VersionenLinks hierherCopy this pageFold/unfold allNach oben Diese Seite ist nicht editierbar. Du kannst den Quelltext sehen, jedoch nicht verändern. Kontaktiere den Administrator, wenn du glaubst, dass hier ein Fehler vorliegt. ====== - PyGame ====== ===== - Setup ===== ==== PyGame installieren ==== Installiere PyGame. Achtung: In der Vergangenheit habe ich die Erfahrung gemacht, dass PyGame manchmal nicht mit der neusten Versionen von Python läuft. Die neuste Version, mit der ich es getestet habe, ist Python 3.9.0, wahrscheinlich läuft es aber auch mit neueren Versionen. Es ist aber kein Problem, mehrere Python-Installationen parallel zu haben. Siehe dazu die Seite [[talit:python_setup|Python Setup]] ==== PyGame Links ==== **Offizielle Dokumentation:** https://www.pygame.org/docs/ ==== Git & GitHub ==== Siehe dazu die Seite [[talit:git_github|Git & GitHub]] ==== Konventionen ==== Für unterschiedliche Programmiersprachen gibt es unterschiedliche Konventionen dazu, wie man Variablen, Klassen usw. benennt. Zum Beispiel sollten Klassen im `UpperCamelCase` Stil und Funktionen & Variablen im `snake_case` Stil notiert werden. [[talit:python_setup#programmier-konventionen|Hier findest du mehr Infos zu den Programmier-Konventionen.]] ==== Pfade in Python ==== Pfade von Ordner und Dokumente werden in Windows (`myfolder\\myfile.txt`) anders angegeben als in MacOS (`myfolder/myfile.txt`). Damit dein Code auf sämtlichen Plattformen funktioniert, musst du also solche Pfadangaben vermeiden. Stattdessen sollst du das os Modul verwenden: <code python> import os.path # KORREKT: path = os.path.join("myfolder", "myfile.txt") # falsch 1: path = "myfolder/myfile.txt") # falsch 2: path = "myfolder\\myfile.txt") </code> ===== - Template ===== Für dein/euer PyGame-Projekt ist es Pflicht, dieses **objektorientiert** zu programmieren. Verwende dafür das **Template** unten. Theoretisch kann man das ganze Game in einem einzigen File programmieren. Gerade für grössere Projekte und wenn man zusammen am gleichen Code arbeitet, so lohnt es sich, das Projekt auf mehrere Files aufzuteilen. Wir verfolgen hier den Grundsatz: **für jede Klasse ein eigenes File**. {{ :talit:template_pygame_2022_v02.zip |Template herunterladen}} <nodisp 1> ++++Template anzeigen| <code python main.py> from settings import Settings from game import Game import os import sys """ MAIN FILE - execute this file - for VSC: template includes launch.json file which includes line '"program": "main.py",' -> always launch this file """ if __name__ == "__main__": os.chdir(sys.path[0]) # changes current working directory to file directory # define some settings settings_default = Settings() settings_slow = Settings(speed=1) # create game object and play game = Game(settings_default) game.play() </code> <code python settings.py> class Settings: """ class containing all settings remember: use CAPITAL letters for CONSTANTS (variables that don't change) """ def __init__(self,win_height=800,win_width=500,bg_color=(255,255,255),fps=30,speed=12): self.NAME = "sloppy bird" # WINDOWS SIZE self.WIN_HEIGHT = win_height self.WIN_WIDTH = win_width # COLOR SETTINGS self.BG_COLOR = bg_color # FRAMERATE self.FPS = fps # frames per second self.TIME_DELAY = int(1000 / self.FPS) # calculate delay time between two frames # GAME CONSTANTS self.SPEED = speed </code> <code python game.py> import os import pygame import sys from player import Player from ball import Ball class Game: """ Main GAME class """ def __init__(self,settings): pygame.init() pygame.font.init() self.settings = settings self.time_delay = self.settings.TIME_DELAY size = (self.settings.WIN_WIDTH, self.settings.WIN_HEIGHT) self.screen = pygame.display.set_mode(size) # create screen which will display everything self.win = pygame.display.set_mode(size) pygame.display.set_caption(self.settings.NAME) # Game title def quit(self): pygame.quit() sys.exit(0) def play(self): # CREATE GAME OBJECTS # PLAYER: player = Player(os.path.join("data","battleship.png"),(150,550)) # OTHER OBJECTS: """ if you have multiple objects of the same class (e.g. enemies), use a SPRITE GROUP: """ balls = pygame.sprite.Group() balls.add(Ball(os.path.join("data","ball_blue.png"),[100,200])) balls.add(Ball(os.path.join("data","ball_black.png"),[200,400])) balls.add(Ball(os.path.join("data","ball_green.png"),[300,600])) # GAME PERMANENT LOOP while True: pygame.time.delay(self.settings.TIME_DELAY) # KEY EVENTS for event in pygame.event.get(): # Exit app if click quit button if event.type == pygame.QUIT: self.quit() # Naviation of player keys = pygame.key.get_pressed() if keys[pygame.K_UP]: player.rect.top -= self.settings.SPEED if keys[pygame.K_DOWN]: player.rect.top += self.settings.SPEED # and so on ... # COLLISION DETECTION """ see manual for all types of collisions: https://www.pygame.org/docs/ref/sprite.html#pygame.sprite.spritecollide """ for ball in balls: # use loop to iterate through sprite group easily pass # UPDATE ALL GAME OBJECTS balls.update() # can update all members of a group with a single command player.update() # DRAW self.screen.fill(self.settings.BG_COLOR) # draw empty screen balls.draw(self.screen) # draw all group members self.screen.blit(player.image, player.rect) # draw single object # UPDATE DISPLAY pygame.display.update() pygame.quit()</code> <code python player.py> import pygame import os class Player(pygame.sprite.Sprite): def __init__(self, img_path, xy_center): super().__init__() # call __init__ of parent class (i.e. of pygame.sprite.Sprite) # ASSIGN CLASS ATTRIBUTES if not os.path.exists(img_path): raise Exception("THE FOLLOWING FILE DOES NOT EXIST: {0}".format(img_path)) self.image = pygame.image.load(str(img_path)) # load image self.rect = self.image.get_rect() # create rectangle containing ball image self.rect.center = xy_center # set center coords of player self.mask = pygame.mask.from_surface(self.image) # creates a mask, used for collision detection (see manual about pygame.sprite.collide_mask()) def update(self): """ - update function gets executed in every step - determines motion of player """ pass def collide(self,ball): """ player collides with ball, given as argument this method updates velocities of BOTH player and ball """ pass </code> <code python ball.py> import pygame import os class Ball(pygame.sprite.Sprite): """ Class for balls, derive from pygame's sprite class -> makes your life easier since you can use e.g. the collision detection of the sprite class """ def __init__(self, img_path, xy_center): super().__init__() # call __init__ of parent class (i.e. of pygame.sprite.Sprite) # ASSIGN CLASS ATTRIBUTES if not os.path.exists(img_path): # check if folder of image exists raise Exception("THE FOLLOWING FILE DOES NOT EXIST: {0}".format(img_path)) self.image = pygame.image.load(str(img_path)) # load image self.rect = self.image.get_rect() # create rectangle containing ball image self.rect.center = xy_center # set center coords of ball self.mask = pygame.mask.from_surface(self.image) # creates a mask, used for collision detection (see manual about pygame.sprite.collide_mask()) def update(self): """ - update function gets executed in every step - determines motion of ball """ pass def collide(self,ball): """ ball self collides with other ball, given as argument this method updates velocities of BOTH balls """ pass </code> ++++ </nodisp> ==== - Tutorial ==== Ziel von diesem Tutorial ist, dich in PyGame anhand des Templates von oben einzuarbeiten. 1. **Installiere** PyGame (mit pip) 1. Lade das **Template-Spiel** herunter und stelle sicher, dass du es ausführen kannst. Du solltest ein Flugzeug und ein paar farbige Bälle sehen. 1. Verschaffe dir einen **Überblick** über das Projekt. Es geht nicht darum, jede einzelne Code-Zeile zu verstehen, sondern darum, das Big Picture zu verstehen: 1. Welches File muss man ausführen, wenn man das Spiel starten möchte? Was passiert darin? 1. Das Herzstück ist die `play`-Methode in der Game-Klasse. Darin befindet sich der **Game-Loop** - eine Endlosschleife (`while True`). In dieser steht der Code, der während dem Spiel in der Dauerschleife ausgeführt wird. Verschaffe dir darin eine Übersicht. 1. Es gibt noch weitere Files wie `setting.py` oder `ball.py`. Wozu sind diese da? 1. In `player.py` und `ball.py` gibt es zwei Methoden: Update und Collide. Wozu? 1. **Erweitere** das Spiel nun wie folgt: 1. Füge noch **zwei rote Bälle** hinzu. Dazu muss zuerst ein Bild von einem roten Ball erstellt werden und in den `data`-Ordner abgelegt werden. Beachte, dass das gleiche Bild dann für beide roten Bälle im Spiel verwendet wird. 1. Ändere das **Bild des Players** (aktuell Flugzeug). Finde ein lustiges Bild im Internet. Wichtig: Das Bild soll einen transparenten Hintergrund haben. Z.B. kann man man mit Photoshop den Hintergrund transparent machen. 1. Füge dem Game ein **Hintergrundbild** hinzu. 1. Den Player soll man nun auch noch nach **links und rechts** bewegen. Implementiere dies in der `play`-Methode, da hier die ganzen Inputs verarbeitet werden sollen. 1. Der Player soll aber nicht aus dem Bild verschwinden können. Erreicht er z.B. den linken Rand, soll er sich nicht weiter nach links bewegen. Implementiere dies in der `update`-Methode des Players. Diese wird bei jedem Durchgangs Game-Loops ausgeführt. 1. Implementiere eine **Collision**: Sobald der Player mit einem Ball kollidiert, soll dieser Ball verschwinden. ===== - Projekt ===== ==== Vorgehen ==== 1. **Plan** erstellen auf Papier: 1. Welche Klassen? Welche Attribute und Methoden? 1. Skizzen für Graphiken anfertigen 1. Neues **GitHub** Repo erstellen. Alle Gruppenmitglieder und Lehrperson einladen. 1. **Template** von oben hinein kopieren und als Startpunkt verwenden. 1. **Programmieren:** siehe Tipps unten ==== Tipps ==== Tipps zum Arbeiten in Gruppen an Programmierprojekten: * Haltet euch strikt an **Konventionen und Programmierphilosophien** (z.B. strikt eine Klasse pro File) * regelmässig **commit** und **push** * aussagekräftige **Commit-Messages** (ultrawichtig, wenn man zusammenarbeitet!) * Code sinnvoll **kommentieren** (ebenso!) * **Pfade** richtig schreiben (siehe oben). Ansonsten läuft z.B. Code, der auf Windows programmiert wurde, nicht auf Mac. * Optimalerweise arbeiten verschiedene Personen an **verschiedenen Klassen**. * Eventuell macht es Sinn, mit **Git-Branches** zu arbeiten. Es werden wie verschiedene Versionen vom Code erzeugt, die dann später wieder zusammengeführt werden. {{ :talit:github_branches.png?400 |}} * **Keine dirty fixes!** Haltet //strikte Ordnung// in eurem Code. Arbeitet lieber länger an eines //sauberen Lösung//, als dass ihr irgendetwas komisches, das ihr nicht wirklich versteht macht, nur damit der Code funktioniert. Dies rächt sich immer! * Letzte Regel: Haltet euch an diese Regeln. Ansonsten erlischt auch der Anspruch auf Support! talit/python_pygame.txt Zuletzt geändert: 2024-08-08 12:37von sca