Pygame-Tutorial

Aus Spieleprogrammierer-Wiki
(Unterschied zwischen Versionen)
Wechseln zu: Navigation, Suche
[unmarkierte Version][unmarkierte Version]
K (Zusammenbasteln)
(Zusammenbasteln)
Zeile 964: Zeile 964:
  
 
Hier nochmal der neue Code im Überblick:
 
Hier nochmal der neue Code im Überblick:
 +
 +
<tt>TileType.py</tt>, <tt>Tileset.py</tt> und <tt>Utils.py</tt> haben sich nicht verändert.
  
 
<tt>Animation.py</tt>:
 
<tt>Animation.py</tt>:
Zeile 971: Zeile 973:
 
import pygame
 
import pygame
  
 +
# Die Klasse kümmert sich um eine einfache Animation:
 
class Animation(object):
 
class Animation(object):
 
     def __init__(self, image, startX, startY, num, width, height, duration):
 
     def __init__(self, image, startX, startY, num, width, height, duration):
 +
        # Die Surface speichern,
 +
        # alle Einzelbilder müssen in einer Reihe liegen.
 
         self.__image = image
 
         self.__image = image
 +
       
 +
        # Dazu müssen wir wissen, an welcher Position die Frames beginnen,
 +
        # wie viele Frames die Animation hat,
 +
        # sowie die Breite und Höhe der Animation kennen.
 
         self.__startX = startX
 
         self.__startX = startX
 
         self.__startY = startY
 
         self.__startY = startY
Zeile 979: Zeile 988:
 
         self.__width = width
 
         self.__width = width
 
         self.__height = height
 
         self.__height = height
 +
       
 +
        # Und natürlich auch, nach welchem Zeitraum wir das nächsten Frame anzeigen sollen.
 
         self.__duration = duration
 
         self.__duration = duration
 
          
 
          
 +
        # Die aktuelle Zeit und das aktuellen Frame speichern wir ebenfalls.
 
         self.__time = 0
 
         self.__time = 0
 
         self.__current = 0
 
         self.__current = 0
 
          
 
          
 
      
 
      
 +
    # Die update-Methode rufen wir einmal pro Frame auf:
 
     def update(self, time = 1):
 
     def update(self, time = 1):
 +
        # Die vergangene Zeit addieren
 
         self.__time += time
 
         self.__time += time
 
          
 
          
 +
        # Falls wir den Anzeige-Zeitraum überschreiten, ...
 
         if self.__time > self.__duration:
 
         if self.__time > self.__duration:
 +
            # ... setzten wir die Zeit zurück und gehen zum nächsten Frame.
 
             self.__time = 0
 
             self.__time = 0
 
             self.__current += 1
 
             self.__current += 1
 +
            # Sicherstellen, dass das aktuelle Frame auch verfügbar ist.
 
             if self.__current >= self.__num:
 
             if self.__current >= self.__num:
 
                 self.__current = 0
 
                 self.__current = 0
 
                  
 
                  
       
+
   
 +
    # Das aktuelle Frame an einer bestimmten Position rendern:
 
     def render(self, screen, pos):
 
     def render(self, screen, pos):
 +
        # Welchen Bereich aus der Grafik müssen wir anzeigen?
 +
        # Die x-Position können wir aus der Breite und der Start-Position berechnen,
 +
        # die restlichen Werte kennen wir bereits.
 
         screen.blit(self.__image, pos, pygame.Rect(self.__startX + (self.__width * self.__current), self.__startY, self.__width, self.__height))
 
         screen.blit(self.__image, pos, pygame.Rect(self.__startX + (self.__width * self.__current), self.__startY, self.__width, self.__height))
 
</sourcecode>
 
</sourcecode>
Zeile 1.004: Zeile 1.025:
  
 
import pygame
 
import pygame
 +
import Utils
 
import Animation
 
import Animation
import Tileset              # für loadImage
 
  
 +
# Die Player Klasse verwendet zwei Animationen, um eine steuerbare Spielfigur dazustellen.
 
class Player(object):
 
class Player(object):
 
     def __init__(self):
 
     def __init__(self):
         self.__anim_image_right = Tileset.loadImage("tileset.png", (255, 0, 255))
+
        # Bild laden und erste Animation erstellen:
 +
         self.__anim_image_right = Utils.loadImage("tileset.png", (255, 0, 255))
 
         self.__anim_right = Animation.Animation(self.__anim_image_right, 32, 32, 2, 32, 64, 15)   
 
         self.__anim_right = Animation.Animation(self.__anim_image_right, 32, 32, 2, 32, 64, 15)   
 
          
 
          
 +
        # Die Grafik spiegeln und in einer neuen Surface speichern,
 +
        # dann können wir die linke Animation erstellen.
 
         self.__anim_image_left = pygame.transform.flip(self.__anim_image_right, True, False)
 
         self.__anim_image_left = pygame.transform.flip(self.__anim_image_right, True, False)
 
         self.__anim_left = Animation.Animation(self.__anim_image_left, 32, 32, 2, 32, 64, 15)
 
         self.__anim_left = Animation.Animation(self.__anim_image_left, 32, 32, 2, 32, 64, 15)
 
          
 
          
 +
        # Start-Position des Players festlegen und
 +
        # merken in welche Richtung wir schauen und ob wir überhaupt laufen.
 
         self.__posX = 10*32
 
         self.__posX = 10*32
 
         self.__posY = 13*32         
 
         self.__posY = 13*32         
Zeile 1.021: Zeile 1.048:
 
          
 
          
 
          
 
          
     def render(self, screen):        
+
     def render(self, screen):
         if self.__dir == -1:  
+
        # Die Blickrichtung ist links:
             if self.__walking:
+
         if self.__dir == -1:
 +
            # Wenn der Spieler die linke oder rechte Pfeiltaste gedrückt hat sind wir am laufen,
 +
             if self.__walking:              
 +
                # nur dann die Animation updaten.
 
                 self.__anim_left.update()
 
                 self.__anim_left.update()
 +
            # Blickrichtung links rendern.
 
             self.__anim_left.render(screen, (self.__posX, self.__posY))   
 
             self.__anim_left.render(screen, (self.__posX, self.__posY))   
         else:    
+
         else:
 +
            # Und das gleiche nochmal für rechts:
 
             if self.__walking:
 
             if self.__walking:
 
                 self.__anim_right.update()
 
                 self.__anim_right.update()
 
             self.__anim_right.render(screen, (self.__posX, self.__posY))
 
             self.__anim_right.render(screen, (self.__posX, self.__posY))
           
+
       
 +
        # De Laufen-Zustand zurücksetzen, im nächsten Frame bleiben wir stehen.
 
         self.__walking = False
 
         self.__walking = False
 
          
 
          
       
+
   
 
     def handleInput(self, key):
 
     def handleInput(self, key):
 +
        # Linke Pfeiltaste wird gedrückt:
 
         if key == pygame.K_LEFT:
 
         if key == pygame.K_LEFT:
 +
            # x-Position der Spielfigur anpassen,
 +
            # die Blickrichtung festlegen
 +
            # und den Laufen-Zustand einschalten.
 
             self.__posX -= 1
 
             self.__posX -= 1
 
             self.__dir = -1
 
             self.__dir = -1
 
             self.__walking = True
 
             self.__walking = True
 +
       
 +
        # Und nochmal für die rechte Pfeiltaste.
 
         if key == pygame.K_RIGHT:
 
         if key == pygame.K_RIGHT:
 
             self.__posX += 1
 
             self.__posX += 1
Zeile 1.050: Zeile 1.089:
  
 
import pygame
 
import pygame
import random
 
 
import Tileset
 
import Tileset
 
import Player
 
import Player
  
 +
# Die Tilemap Klasse verwaltet die Tile-Daten, die das Aussehen der Karte beschreiben.
 
class Tilemap(object):
 
class Tilemap(object):
     def __init__(self):      
+
     def __init__(self):
 +
        # Wir erstellen ein neues Tileset.
 +
        # Hier im Tutorial fügen wir manuell vier Tile-Typen hinzu.
 
         self.__tileset = Tileset.Tileset("tileset.png", (255, 0, 255), 32, 32)
 
         self.__tileset = Tileset.Tileset("tileset.png", (255, 0, 255), 32, 32)
 
         self.__tileset.addTile("grass", 0, 0)
 
         self.__tileset.addTile("grass", 0, 0)
         self.__tileset.addTile("mud", 32, 0)
+
         self.__tileset.addTile("mud", 32, 0)      
        self.__tileset.addTile("water", 64, 0)
+
        self.__tileset.addTile("block", 0, 32)
+
       
+
 
         self.__tileset.addTile("grass-mud", 0, 64)
 
         self.__tileset.addTile("grass-mud", 0, 64)
 
         self.__tileset.addTile("empty", 0, 96)
 
         self.__tileset.addTile("empty", 0, 96)
 
          
 
          
 +
        # Festlegen der Startposition der Kamera. Hier (0, 0).
 
         self.__cameraX = 0
 
         self.__cameraX = 0
 
         self.__cameraY = 0
 
         self.__cameraY = 0
           
+
       
         self.__width = 25
+
        # Die Größe der Maps in Tiles.
 +
         self.__width = 30
 
         self.__height = 25
 
         self.__height = 25
  
 +
        # Erstellen einer leeren Liste für die Tile Daten.
 
         self.__tiles = list()
 
         self.__tiles = list()
 
          
 
          
         for i in range(0, self.__width):
+
        # Sehr einfache Karte basteln:
 +
         for i in range(0, self.__height):
 
             self.__tiles.append(list())
 
             self.__tiles.append(list())
             for j in range(0, self.__height):
+
             for j in range(0, self.__width):
 
                 if i == 14:
 
                 if i == 14:
 
                     self.__tiles[i].append("grass")  
 
                     self.__tiles[i].append("grass")  
Zeile 1.085: Zeile 1.127:
 
                     self.__tiles[i].append("empty")
 
                     self.__tiles[i].append("empty")
 
          
 
          
 +
        # Player-Objekt erstellen.
 
         self.__player = Player.Player()
 
         self.__player = Player.Player()
 
                      
 
                      
 
      
 
      
 +
    # Hier rendern wir den sichtbaren Teil der Karte.
 
     def render(self, screen):
 
     def render(self, screen):
 +
        # Zeilenweise durch die Tiles durchgehen.
 
         for y in range(0, int(screen.get_height() / self.__tileset.getTileHeight()) + 1):
 
         for y in range(0, int(screen.get_height() / self.__tileset.getTileHeight()) + 1):
 +
            # Die Kamera Position mit einbeziehen.
 
             ty = y + self.__cameraY
 
             ty = y + self.__cameraY
 
             if ty >= self.__height or ty < 0:
 
             if ty >= self.__height or ty < 0:
 
                 continue
 
                 continue
             col = self.__tiles[ty]
+
             # Die aktuelle Zeile zum einfacheren Zugriff speichern.
 +
            line = self.__tiles[ty]
 +
            # Und jetzt spaltenweise die Tiles rendern.
 
             for x in range(0, int(screen.get_width() / self.__tileset.getTileWidth()) + 1):
 
             for x in range(0, int(screen.get_width() / self.__tileset.getTileWidth()) + 1):
 +
                # Auch hier müssen wir die Kamera beachten.
 
                 tx = x + self.__cameraX
 
                 tx = x + self.__cameraX
 
                 if tx >= self.__width or tx < 0:
 
                 if tx >= self.__width or tx < 0:
 
                     continue
 
                     continue
                 tilename = col[tx]
+
                # Wir versuchen, die Daten des Tiles zu bekommen.
 +
                 tilename = line[tx]
 
                 tile = self.__tileset.getTile(tilename)
 
                 tile = self.__tileset.getTile(tilename)
 +
                # Falls das nicht fehlschlägt können wir das Tile auf die screen-Surface blitten.
 
                 if tile is not None:
 
                 if tile is not None:
 
                     screen.blit(self.__tileset.getImage(), (x * self.__tileset.getTileWidth(), y * self.__tileset.getTileHeight()), tile.getRect())
 
                     screen.blit(self.__tileset.getImage(), (x * self.__tileset.getTileWidth(), y * self.__tileset.getTileHeight()), tile.getRect())
 +
       
 +
        # Und zuletzt den Player rendern.
 +
        self.__player.render(screen)           
 
      
 
      
        self.__player.render(screen)
 
                   
 
 
      
 
      
     def handleInput(self, key):
+
    # Tastendrücke an den Player weiterreichen:
 +
     def handleInput(self, key):      
 
         self.__player.handleInput(key)
 
         self.__player.handleInput(key)
 +
</sourcecode>
 +
 +
<tt>Tile_3.py</tt>
 +
<sourcecode lang=python line>
 +
# -*- coding: UTF-8 -*-
 +
 +
# Pygame Modul importieren.
 +
import pygame
 +
 +
# Unser Tilemap Modul ebenfalls importieren.
 +
import Tilemap
 +
 +
# Überprüfen, ob die optionalen Text- und Sound-Module geladen werden konnten.
 +
if not pygame.font: print('Fehler pygame.font Modul konnte nicht geladen werden!')
 +
if not pygame.mixer: print('Fehler pygame.mixer Modul konnte nicht geladen werden!')
 +
 +
def main():
 +
    # Initialisieren aller Pygame-Module und
 +
    # Fenster erstellen (wir bekommen eine Surface, die den Bildschirm repräsentiert).
 +
    pygame.init()
 +
    screen = pygame.display.set_mode((800, 600))
 +
   
 +
    # Titel des Fensters setzen, Mauszeiger nicht verstecken und Tastendrücke wiederholt senden.
 +
    pygame.display.set_caption("Pygame-Tutorial: Animation")
 +
    pygame.mouse.set_visible(1)
 +
    pygame.key.set_repeat(1, 30)
 +
 +
    # Clock-Objekt erstellen, das wir benötigen, um die Framerate zu begrenzen.
 +
    clock = pygame.time.Clock()
 +
   
 +
    # Wir erstellen eine Tilemap.
 +
    map = Tilemap.Tilemap()
 +
   
 +
    # Die Schleife, und damit unser Spiel, läuft solange running == True.
 +
    running = True
 +
    while running:
 +
        # Framerate auf 30 Frames pro Sekunde beschränken.
 +
        # Pygame wartet, falls das Programm schneller läuft.
 +
        clock.tick(30)
 +
 +
        # screen Surface mit Schwarz (RGB = 0, 0, 0) füllen.
 +
        screen.fill((198, 209, 255))
 +
 +
        # Alle aufgelaufenen Events holen und abarbeiten.
 +
        for event in pygame.event.get():
 +
            # Spiel beenden, wenn wir ein QUIT-Event finden.
 +
            if event.type == pygame.QUIT:
 +
                running = False
 +
           
 +
            # Wir interessieren uns auch für "Taste gedrückt"-Events.
 +
            if event.type == pygame.KEYDOWN:
 +
                # Wenn Escape gedrückt wird posten wir ein QUIT-Event in Pygames Event-Warteschlange.
 +
                if event.key == pygame.K_ESCAPE:
 +
                    pygame.event.post(pygame.event.Event(pygame.QUIT))
 +
               
 +
                # Alle Tastendrücke auch der Tilemap mitteilen.
 +
                map.handleInput(event.key)
 +
       
 +
        # Die Tilemap auf die screen-Surface rendern.
 +
        map.render(screen)
 +
       
 +
        # Inhalt von screen anzeigen
 +
        pygame.display.flip()
 +
 +
 +
# Überprüfen, ob dieses Modul als Programm läuft und nicht in einem anderen Modul importiert wird.
 +
if __name__ == '__main__':
 +
    # Unsere Main-Funktion aufrufen.
 +
    main()
 
</sourcecode>
 
</sourcecode>
  

Version vom 29. Oktober 2011, 12:33 Uhr

Klicke hier, um diese Version anzusehen.

Meine Werkzeuge
Namensräume
Varianten
Aktionen
Navigation
Werkzeuge