Python(Pygame) - 以不同速度移动到背景的对象实例

时间:2017-09-18 23:01:21

标签: python-3.x 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()

1 个答案:

答案 0 :(得分:0)

不是将self.rect实例的World设置为-self.tileSize,而是将{1}}中的矩形属性和self.tileShift置入或递减,而不是self.tileSize / p>

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