2017-09-18 4 views
1

Das hat mich seit Tagen beschäftigt. Ich versuche, ein Spiel mit einem in der Mitte fixierten Spieler zu erstellen, und einen Kachel-basierten Hintergrund, der sich flüssig hinter dem Spieler bewegt und zusätzliche Kachelbilder erzeugt, wenn der Spieler sich bewegt. Der Hintergrund funktioniert soweit perfekt.Python (Pygame) - Objektinstanzen bewegen sich mit unterschiedlicher Geschwindigkeit zum Hintergrund

Das Problem tritt auf, wenn ich Objekte zum Hintergrund (z. B. einen Baum) hinzufügen möchte. Ich möchte, dass dieses Objekt an einem bestimmten Hintergrundort fixiert bleibt, aber wenn sich der Spieler bewegt, bewegt sich das Objekt allmählich in Relation zum Hintergrund. Das heißt, das Objekt bewegt sich, wenn sich der Spieler bewegt (wie es sein sollte), aber es bewegt sich auch viel .

Ich habe die Ursache auf die World.update-Methode, den Abschnitt self.tileShift, isoliert. Wenn Sie diesen gesamten if/elif-Abschnitt entfernen, sieht das Verhalten gut aus (außer natürlich, dass der Hintergrund nicht richtig aktualisiert wird, daher brauchen wir diesen Abschnitt). Irgendwie, wenn der tileShift überspringt, überspringt jedes Objekt auf dem Bildschirm auch ein paar Pixel. Nachdem ich über eine Woche lang geforscht und experimentiert habe, kann ich es immer noch nicht beheben. Ich habe versucht, das Bild zu ändern, den tileShift Cutoff-Punkt zu ändern, die Reihenfolge des Aufrufs von update/draw-Methoden usw. zu ändern.

Siehe unten (massiv abgespeckte, aber eigenständige) Code unten. Beachten Sie, dass wir ein Hintergrundkachelbild mit Mustern benötigen (siehe Weltklasse init), sonst können Sie das beschriebene Verhalten nicht sehen, da die fehlerhafte Bewegung so graduell ist. Verwenden Sie für eine optimale Leistung ein 70 x 70 PNG-Bild.

Hoffentlich macht diese Erklärung Sinn, bitte lassen Sie mich wissen, wenn zusätzliche Informationen erforderlich sind. Jede Hilfe würde sehr geschätzt werden !!

import pygame 

# Initialisation 
SCREEN_WIDTH, SCREEN_HEIGHT = 800, 850 
pygame.init() # Initialise pygame 
window = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT)) # Set the window surface (the main screen of the game) 
pygame.display.set_caption("Game") # Game window caption 
window_rect = window.get_rect() 

# GLOBAL VARIABLES 
WorldMove = dict(x=0, y=0) # List for the direction and amount the background moves as the player moves 
PlayerMoveSpeed = 5 

# CLASSES 
class World(pygame.sprite.Sprite): 
    def __init__(self): 
     self.tileShift = dict(x=0, y=0) # Tracker for when the player has passed from one map tile to another 

     # Load and set up the tile images 
     self.tiles = pygame.image.load("Images\Tiles\Tile.png") 
     self.tileSize = self.tiles.get_rect().size[0] # Assumes a square size 
     self.map = pygame.Surface((self.tileSize*14,self.tileSize*15)) # Visible area surface size, based on tile size 
     self.rect = self.map.get_rect() # Create a rect attribute for the World, so it can be blitted to the window 
     self.rect.x, self.rect.y = -self.tileSize,-self.tileSize # The map is blitted starting one tile size above left of the screen (so we see no whitespace) 

    def update(self): 
     # Move the map around the player based on WorldMove, which is set in the player_move function 
     self.rect.x += WorldMove["x"] 
     self.rect.y += WorldMove["y"] 

     # Update the tileShift based on player movement so we know when they've moved onto another tile 
     if WorldMove["x"] != 0: self.tileShift["x"] -= WorldMove["x"] 
     if WorldMove["y"] != 0: self.tileShift["y"] -= WorldMove["y"] 

     # Once the self.tileShift has passed the size of one of the tile images, reset it and move self.matrix by 1 
     if self.tileShift["x"] < -self.tileSize: 
      self.tileShift["x"] = 0 # Reset the tileShift variable 
      self.rect.x = -self.tileSize # Reset the point from which the map is blitted to window to top left of visible screen 
     elif self.tileShift["x"] > self.tileSize: 
      self.tileShift["x"] = 0 
      self.rect.x = -self.tileSize 
     if self.tileShift["y"] > self.tileSize: 
      self.tileShift["y"] = 0 
      self.rect.y = -self.tileSize 
     elif self.tileShift["y"] < -self.tileSize: 
      self.tileShift["y"] = 0 
      self.rect.y = -self.tileSize 

    def draw(self): 
     # Draw the tiles in a grid in the visible area 
     for y in range(15): # Visible number of tiles on y axis 
      for x in range(14): # Visible number of tiles on x axis 
       self.map.blit(self.tiles, (self.tileSize*x, self.tileSize*y)) # Blit each tile onto self.map 
     window.blit(self.map, self.rect) # Blit self.map onto the window 

class Player(pygame.sprite.Sprite): 
    def __init__(self): 
     self.image = pygame.Surface((35, 35)) 
     self.image.fill((0, 0, 0)) 
     self.rect = (SCREEN_WIDTH/2, SCREEN_HEIGHT/2) # Player is always in middle of screen 

    def player_move(self): 
     global WorldMove # Make sure that we're referring to and updating the global variable for the world movement 

     key = pygame.key.get_pressed() 
     x, y = 0, 0 

     if key[pygame.K_w] or key[pygame.K_UP]: y = PlayerMoveSpeed 
     if key[pygame.K_d] or key[pygame.K_RIGHT]: x = -PlayerMoveSpeed 
     if key[pygame.K_a] or key[pygame.K_LEFT]: x = PlayerMoveSpeed 
     if key[pygame.K_s] or key[pygame.K_DOWN]: y = -PlayerMoveSpeed 

     if x != 0 and y != 0: # If more than one key pressed, move diagonally 
      WorldMove["x"] = int(x/1.5) 
      WorldMove["y"] = int(y/1.5) 
     else: 
      WorldMove["x"] = x 
      WorldMove["y"] = y 

    def draw(self): 
     window.blit(self.image, self.rect) 

class Object(pygame.sprite.Sprite): 

    def __init__(self): 
     self.image = pygame.Surface((50,100)) 
     self.image.fill((50,50,250)) 
     self.rect = self.image.get_rect() 
     self.rect.center = window_rect.center 
     self.rect.x, self.rect.y = 100, 100 # Spawn location of the object 

    def update(self): # Move the object as the world moves around the player 
     self.rect.x += WorldMove["x"] 
     self.rect.y += WorldMove["y"] 

    def draw(self): # Blit the object onto the screen at its location 
     window.blit(self.image, self.rect) 

# Set Objects 
world = World() 
object = Object() 
player = Player() 

# Main Loop 
gameRunning = True 

while gameRunning: 

    # Player events 
    for event in pygame.event.get(): 

     if event.type == pygame.QUIT or (event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE): 
      gameRunning = False 

     player.player_move() # Move player based on movement key(s) pressed (if any) 

    # Class updates and drawing to the screen 
    window.fill((255, 255, 255)) # Fill the window with background white 
    world.update() 
    world.draw() 
    object.update() 
    object.draw() 
    player.draw() 

    pygame.display.update() # Refresh the display 

# End - only reaches this point if gameRunning = False 
pygame.quit() 
+0

Falls es hilft Ihnen, mehr Forschung zu tun, das ist genannt * Parallax * Scrollen. – jwg

Antwort

0

Anstatt die self.rect der World Instanz -self.tileSize Einstellung, Ein- oder verringern die rect Attribute und die self.tileShift vom self.tileSize:

if self.tileShift["x"] < -self.tileSize: 
    self.tileShift["x"] += self.tileSize 
    self.rect.x -= self.tileSize 
elif self.tileShift["x"] > self.tileSize: 
    self.tileShift["x"] -= self.tileSize 
    self.rect.x += self.tileSize 
if self.tileShift["y"] > self.tileSize: 
    self.tileShift["y"] -= self.tileSize 
    self.rect.y += self.tileSize 
elif self.tileShift["y"] < -self.tileSize: 
    self.tileShift["y"] += self.tileSize 
    self.rect.y -= self.tileSize 
+0

Das hat es geschafft! Vielen Dank – Matthew

Verwandte Themen