Cela fait des choses qui me trottent dans la tête depuis des jours. J'essaie de créer un jeu avec un joueur fixé au milieu, et un fond basé sur les tuiles qui bouge fluide derrière le joueur et génère des images de tuiles supplémentaires que le joueur se déplace. L'arrière-plan fonctionne parfaitement jusqu'à présent.Python (Pygame) - Instances d'objets se déplaçant à une vitesse différente de l'arrière-plan
Le problème se pose lorsque j'essaie d'ajouter des objets à l'arrière-plan (par exemple, un arbre). Je souhaite que cet objet reste fixé sur un certain emplacement d'arrière-plan, mais au fur et à mesure que le joueur bouge, l'objet se déplace progressivement par rapport à l'arrière-plan. C'est-à-dire que l'objet bougera au fur et à mesure que le joueur bouge (comme il se doit), mais il bougera beaucoup trop.
J'ai isolé la cause à la méthode World.update, la section self.tileShift. Si vous supprimez toute la section if/elif, le comportement semble bon (à l'exception bien sûr, l'arrière-plan ne se met pas à jour correctement, nous avons donc besoin de cette section). D'une façon ou d'une autre, lorsque le tileShift saute, tous les objets sur l'écran sautent aussi de quelques pixels. Après avoir passé plus d'une semaine de recherche et d'expérimentation, je n'arrive toujours pas à le réparer. J'ai essayé de changer l'image, en changeant le point de coupure de tileShift, en changeant l'ordre des méthodes de mise à jour d'appel, etc.
Reportez-vous à (massivement dépouillé de l'original, mais autonome) le code ci-dessous. Notez que nous avons besoin d'une image de mosaïque d'arrière-plan avec des motifs (voir la classe mondiale init), sinon vous ne pourrez pas voir le comportement que je décris, car le mouvement erroné est si progressif. Pour de meilleures performances, utilisez une image png 70x70.
Espérons que cette explication a du sens, s'il vous plaît laissez-moi savoir si des informations supplémentaires sont nécessaires. Toute aide serait grandement appréciée !!
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()
Dans le cas où il vous aide à faire plus de recherche, c'est appelé * parallax * défilement. – jwg