這一直在我的腦海中持續數日。我正在嘗試創建一個遊戲,遊戲中有一個固定在中間的玩家,以及一個基於瓦片的背景,在玩家身後流暢地移動,並在玩家移動時生成額外的瓦片圖像。背景完美到目前爲止。Python(Pygame) - 以不同速度向背景移動的對象實例
當我嘗試將對象添加到背景(例如樹)時,會出現此問題。我希望這個對象保持固定在某個背景位置,但隨着玩家的移動,對象逐漸相對於背景移動。也就是說,物體會隨着玩家的移動而移動(因爲它應該),但它也會移動太多。
我已經隔離了World.update方法的原因,self.tileShift部分。如果你刪除了整個if/elif部分,這個行爲看起來不錯(當然背景沒有正確更新,所以我們需要這個部分)。不知何故,當tileShift跳過時,屏幕上的每個對象也會跳過幾個像素。花了一週的研究和試驗後,我仍然無法解決它。我試圖改變圖像,改變tileShift截點,改變調用更新/繪製方法的順序等。
請參考下面的代碼(從原始的,但自包含的代碼大量剝離下來)。請注意,我們需要一個帶有模式的背景平鋪圖像(請參閱World class init),否則您將無法看到我描述的行爲,因爲錯誤的移動是如此漸進的。爲獲得最佳性能,請使用70x70 png圖像。
希望這個解釋是有道理的,請讓我知道是否需要任何額外的信息。任何幫助將不勝感激!!
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()
在情況下,它可以幫助你做更多的研究,這是稱爲*視差*滾動。 – jwg