Dank dem gestern vorgestellten Video der fluffigen Kartoffel (DaFluffy Potato) habe ich jetzt begriffen, wie Rotationen in Pygame funktionieren. Als Übung habe ich erst einmal ein Raumschiff programmiert, das in acht diskreten Richtungen (Ost, Nordost, Nord, Nordwest, West, Südwest, Süd und Südost) rotiert, also immer in Schritten von 45°. Dabei habe ich mich an einem Beispiel von Andy Harris aus seinem wunderbaren Buch »Game Programming« orientiert. Das ist zwar schon etwas älter und wird momentan antiquarisch teuer verhökert, aber es ist immer noch aktuell und inspirierend.
Die ganze Logik findet in der Klasse Ship
statt, die von pygame.sprite.Sprite
erbt. Daher muß sich der Programmierer nicht um das Zeichnen des Raumschiffes kümmern, das erledigt die Oberklasse für ihn (wenn er das Schiff in einer sprite.Group
registriert hat). Im gestrigen Video habe ich gelernt, daß jede Rotation die Qualität des Sprites herabsetzt. Daher wird diese immer in der Kopie
def update(self): oldCenter = self.rect.center self.image = pygame.transform.rotate(self.imageMaster, self.dir) self.rect = self.image.get_rect() self.rect.center = oldCenter
durchgeführt. Und da sich bei einer Rotation auch das umgebende Rechteck ändert, wird das Zentrum des Originalrechtecks zwischengespeichert und nach der Rotation dem neuen Rechteck zugewiesen. So wird sichergestellt, daß das Sprite immer um die Mitte rotiert und keine seltsamen Sprünge ausführt.
Die calcVector()
-Methode ist ein wenig geschwätzig geraten, das müßte eigentlich auch einfacher gehen. Aber bevor ich da mit irgendwelchen Tricks rangehe, lasse ich sie erst einmal so stehen.
Die Methode checkBounds()
sorgt dafür, daß das Schiff, wenn es das Fenster verläßt, auf der gegenüberliegenden Seite wieder auftaucht. Jetzt erst einmal das komplette Skript zum Nachvollziehen und -programmieren:
# In acht Richtungen rotierendes Raumschiff import pygame from pygame.locals import * import os # Hier wird der Pfad zum Verzeichnis des ».py«-Files gesetzt file_path = os.path.dirname(os.path.abspath(__file__)) os.chdir(file_path) # Konstanten deklarieren WIDTH, HEIGHT = 640, 480 TITLE = "Rotating Space Ship in 8 Directions" FPS = 60 BG = (52, 152, 219) # Dunkelblau class Ship(pygame.sprite.Sprite): def __init__(self, screen): pygame.sprite.Sprite.__init__(self) self.screen = screen self.imageMaster = pygame.image.load("images/playership.gif").convert() self.imageMaster = pygame.transform.scale(self.imageMaster, (50, 38)) self.image = self.imageMaster self.rect = self.image.get_rect() self.rect.center = (WIDTH/2, HEIGHT/2) self.x = self.rect.centerx self.y = self.rect.centery self.dir = 0 self.speed = 0 self.dx = 0 self.dy = 0 def update(self): oldCenter = self.rect.center self.image = pygame.transform.rotate(self.imageMaster, self.dir) self.rect = self.image.get_rect() self.rect.center = oldCenter self.calcVector() self.x += self.dx self.y += self.dy self.checkBounds() self.rect.centerx = self.x self.rect.centery = self.y def turnLeft(self): self.dir -= 45 if self.dir < 0: self.dir = 315 def turnRight(self): self.dir += 45 if self.dir == 360: self.dir = 0 def speedUp(self): self.speed += 1 if self.speed > 8: self.speed = 8 def slowDown(self): self.speed -= 1 if self.speed < 0: self.speed = 0 def calcVector(self): if self.dir == 0: self.dx = 1 self.dy = 0 elif self.dir == 45: self.dx = 0.7 self.dy = -0.7 elif self.dir == 90: self.dx = 0 self.dy = -1 elif self.dir == 135: self.dx = -0.7 self.dy = -0.7 elif self.dir == 180: self.dx = -1 self.dy = 0 elif self.dir == 225: self.dx = -0.7 self.dy = 0.7 elif self.dir == 270: self.dx = 0 self.dy = 1 elif self.dir == 315: self.dx = 0.7 self.dy = 0.7 else: print("Es ist was faul im Staate Dänemark: " + str(self.dir)) self.dx *= self.speed self.dy *= self.speed def checkBounds(self): if self.x > WIDTH: self.x = 0 if self.x < 0: self.x = WIDTH if self.y > HEIGHT: self.y = 0 if self.y < 0: self.y = HEIGHT # Pygame initialisieren und das Fenster und die Hintergrundfarbe festlegen pygame.init() screen = pygame.display.set_mode((WIDTH, HEIGHT)) pygame.display.set_caption(TITLE) background = pygame.Surface(screen.get_size()) background.fill(BG) screen.blit(background, (0, 0)) clock = pygame.time.Clock() ship = Ship(screen) allSprites = pygame.sprite.Group(ship) keep_going = True while keep_going: clock.tick(FPS) for event in pygame.event.get(): if event.type == pygame.QUIT: keep_going = False elif event.type == pygame.KEYDOWN: if event.key == pygame.K_LEFT: ship.turnLeft() elif event.key == pygame.K_RIGHT: ship.turnRight() elif event.key == pygame.K_UP: ship.speedUp() elif event.key == pygame.K_DOWN: ship.slowDown() elif event.key == pygame.K_ESCAPE: keep_going = False allSprites.clear(screen, background) allSprites.update() allSprites.draw(screen) pygame.display.flip() pygame.quit()
Als nächstes möchte ich, daß das Raumschiff der Maus folgt (wie in Daniel Shiffmans »The Nature of Code«) und das möchte ich mit der Vector2-Klasse von Pygame realisieren. Diese besitzt nämlich unter anderem ebenfalls einige rotate()
-Methoden und sie scheint auch ansonsten sehr mächtig zu sein. Still digging!
Über …
Der Schockwellenreiter ist seit dem 24. April 2000 das Weblog digitale Kritzelheft von Jörg Kantel (Neuköllner, EDV-Leiter Rentner, Autor, Netzaktivist und Hundesportler — Reihenfolge rein zufällig). Hier steht, was mir gefällt. Wem es nicht gefällt, der braucht ja nicht mitzulesen. Wer aber mitliest, ist herzlich willkommen und eingeladen, mitzudiskutieren!
Alle eigenen Inhalte des Schockwellenreiters stehen unter einer Creative-Commons-Lizenz, jedoch können fremde Inhalte (speziell Videos, Photos und sonstige Bilder) unter einer anderen Lizenz stehen.
Der Besuch dieser Webseite wird aktuell von der Piwik Webanalyse erfaßt. Hier können Sie der Erfassung widersprechen.
Diese Seite verwendet keine Cookies. Warum auch? Was allerdings die iframes
von Amazon, YouTube und Co. machen, entzieht sich meiner Kenntnis.
Werbung
Diese Spalte wurde absichtlich leergelassen!