【问题标题】:Background image change glitches背景图像更改故障
【发布时间】:2021-12-13 00:48:48
【问题描述】:

我尝试使用 Pygame 制作一个简单的关卡,它会在玩家移动到特定位置时更改背景(简单的关卡/场景更改)。

在启动时,我的第一个背景绘制正确。当我更改背景(移动到左上角)时,第二个背景被正确绘制。但是当我移动到屏幕上的特定位置时,在透明精灵后面(使用 set_keycolor 设置透明)不是我的第二个(正确)背景,而是最初的第一个。

我是否需要明确清除屏幕对象的背景?我必须删除屏幕对象,然后创建一个全新的对象吗?

程序.py

#!/usr/bin/env python
import pygame

from player import Character

# see if we can load more than standard BMP
if not pygame.image.get_extended():
    raise SystemExit("Sorry, extended image module required")

# globals
id = 1

# main
def main(winstyle=0):
    # Initialize pygame
    pygame.init()

    SCREENRECT = pygame.Rect(0, 0, 630, 450)
    winstyle = 0  # |FULLSCREEN
    bestdepth = pygame.display.mode_ok(SCREENRECT.size, winstyle, 32)
    screen = pygame.display.set_mode(SCREENRECT.size, winstyle, bestdepth)

    BG_TILE_SIZE = 90

    # decorate the game window
    pygame.display.set_caption("Pygame TEST")
    pygame.mouse.set_visible(0)

    # create the background, tile the bgd image
    background = pygame.Surface(SCREENRECT.size)
    background.fill((0,0,255))
    screen.blit(background, (0, 0))
    pygame.display.flip()

    # Initialize Game Groups
    all = pygame.sprite.RenderUpdates()

    # assign default groups to each sprite class
    Character.containers = all

    # Create Some Starting Values
    clock = pygame.time.Clock()

    # initialize our starting sprites
    player = Character(SCREENRECT)

    # Run our main loop whilst the player is alive.
    while player.alive():

        # get input
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                return
            if event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
                return

        # update all the sprites
        all.update()

        # handle player input
        player.move(pygame.key.get_pressed(), SCREENRECT)

        # change background
        indexX, indexY = player.rect.center
        if checkPlayerPosition(indexY, screen, background):
            player.rect = player.image.get_rect(center=SCREENRECT.center)

        # clear/erase the last drawn sprites
        all.clear(screen, background)

        # draw the scene
        dirty = all.draw(screen)
        pygame.display.update(dirty)

        # cap the framerate at 60fps. Also called 60HZ or 60 times per second.
        clock.tick(60)

    pygame.time.wait(1000)

# change the background
def checkPlayerPosition(indexY, screen, background):
    global id
    if id == 1:
        if indexY < 90:
            screen.fill((0,0,0))
            pygame.display.flip()
            background.fill((0,0,255))
            id = -1
            return True
    else:
        if indexY > 360:
            screen.fill((0,0,255))
            pygame.display.flip()
            background.fill((0,0,0))
            id = 1
            return True
    return False

# call the "main" function if running this script
if __name__ == "__main__":
    main()
    pygame.quit()

这是我的精灵的代码。

player.py:

import os
import pygame

class Character(pygame.sprite.Sprite):
    # fields
    speed = 4
    run = 1
    images = []

    # constructor
    def __init__(self, SCREENRECT):
        pygame.sprite.Sprite.__init__(self, self.containers)
        self.setCharImages()
        self.image = self.images[0]
        self.rect = self.image.get_rect(center=SCREENRECT.center)
        self.reloading = 0
        self.origtop = self.rect.top
        self.facing = -1

    # sets the character image array
    def setCharImages(self):
        img = self.load_image("char.png")
        img.set_colorkey((0,0,0))
        self.images = [img, 
                       pygame.transform.flip(img, 1, 1),
                       pygame.transform.rotate(img, 270),
                       pygame.transform.rotate(img, 90)]

    # loads an image from disk
    def load_image(self, file):
        try:
            MAIN_DIR = os.path.split(os.path.abspath(__file__))[0]
            surface = pygame.image.load(os.path.join(MAIN_DIR, "img", file))
        except pygame.error:
            raise SystemExit('Could not load image "%s" %s' % (file, pygame.get_error()))
        return surface.convert()

    # move operation and animation
    def move(self, keystate, SCREENRECT):
        if keystate[pygame.K_LSHIFT]:
            self.run = 2
        else:
            self.run = 1

        movX = (keystate[pygame.K_RIGHT] - keystate[pygame.K_LEFT]) * self.speed * self.run
        movY = (keystate[pygame.K_DOWN] - keystate[pygame.K_UP]) * self.speed * self.run

        self.rect.move_ip(movX, movY)
        self.rect = self.rect.clamp(SCREENRECT)

        if movX < 0:
            self.image = self.images[0]
        elif movX > 0:
            self.image = self.images[1]
        if movY < 0:
            self.image = self.images[2]
        elif movY > 0:
            self.image = self.images[3]

这是第一关,开始游戏时。

这是有故障的版本,在我更改了级别并且背景变黑之后。如您所见,精灵获取的透明背景被第一个添加的背景层替换,而不是第二个。

所以基本上我会说,当移动我的精灵时,错误的背景会被重绘,当它离开它的位置时。这只发生在第二个屏幕上!如果我回到第一个,我不会遇到这个故障。

所以基本上我上面的简短代码示例中的两行实际上在这里调用了这个函数。也许这会导致问题?!

【问题讨论】:

    标签: python pygame


    【解决方案1】:

    您必须更改用于清除屏幕的 Surface 的颜色:

    all.clear(screen, background)
    

    你必须给fillbackground换上新的颜色,并用相同的颜色清屏:

    def checkPlayerPosition(self, indexX, indexY, screen):
            if self.id == 1:
                if indexX <= 2 and indexY == 0:
                    backgrund.fill((0, 0, 0)) 
                    screen.blit(backgrund, (0, 0))
                    pygame.display.flip()
                    return True
            else:
                if indexX < 3 and indexY == 4:
                    backgrund.fill((0, 0, 255)) 
                    screen.blit(backgrund, (0, 0))
                    pygame.display.flip()
                    return True
            return False
    

    另外,在checkPlayerPosition之后拨打all.clear(screen, background)

    while player.alive():
    
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                return
            if event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
                return
    
        all.update()
        player.move(pygame.key.get_pressed(), map.matrix)
    
        indexX, indexY = player.mapPosition()
        if map.checkPlayerPosition(indexX, indexY, screen):
            player.rect = player.image.get_rect(center=SCREENRECT.center)
    
        # draw the scene
        all.clear(screen, background)
        dirty = all.draw(screen)
        pygame.display.update(dirty)
    
        # cap the framerate at 60fps. Also called 60HZ or 60 times per second.
        clock.tick(60)
    

    【讨论】:

      【解决方案2】:

      我终于找到了问题,您的代码非常有帮助,非常感谢!

      当我测试答案时,一切正常,但后来我尝试实现更多逻辑,但又失败了。我换行了:

      background.fill((0,0,255))
      screen.blit(background, (0, 0))
      

      到以下:

      bgGreen = load_image("background_green.png")
      background = pygame.Surface(SCREENRECT.size) # <- this was wrong
      for height in range(0, 450, 90):
         for width in range(0, 630, 90):
            background.blit(bgGreen, (width, height))
      screen.blit(background, (0, 0))
      

      然后我发现,当我删除第二行(Surface 构造函数调用)时,“故障”消失了。

      所以我会说我完全误解了 Python 中的参数传递。背景是通过值而不是通过引用传递给函数的?因此,我在背景上创建了一个新的 Surface,但是当函数返回到我的主游戏循环时,它会继续使用原始背景对象。

      我希望我的解释是正确的,这对我自己来说似乎是一个非常愚蠢的错误。但我设法更改了我的初始程序,现在一切正常,正如我所期望的那样。

      @Rabbid76:感谢您的耐心等待。我是否也应该将您的答案标记为正确/有帮助,因为它帮助我正确安排了游戏循环?当然,它对我找到自己的 bug 有很大帮助...

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-05-27
        • 1970-01-01
        • 1970-01-01
        • 2016-10-05
        • 1970-01-01
        • 2016-01-09
        • 2020-12-16
        • 2011-12-07
        相关资源
        最近更新 更多