image image


image

Pygame: Rotierendes Raumschiff in acht Richtungen

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!


(Kommentieren) 

image image



Ü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!


Werbung


image  image  image
image  image  image


image