移动pygame背景

3 投票
2 回答
2671 浏览
提问于 2025-04-18 05:57

我最近在学习用Python开发游戏,但我还是个新手。我试着模仿经典的“太空入侵者”游戏,做出了一个简单的版本,灵感主要来自网上的教程和代码。

现在我想让背景动起来,所以我想到了一个主意:创建两个精灵(就是游戏中的图像)和两张背景图片,让它们一个接一个地移动。当其中一个精灵移出屏幕时,它应该从底部重新出现,然后继续移动。但现在这个想法没有成功,我不太确定哪里出了问题。以下是我目前的代码:

#!/usr/bin/env python

from helpers import *

class Space1(pygame.sprite.Sprite):
    def __init__(self, i):                      
        pygame.sprite.Sprite.__init__(self)
        self.image, self.rect = load_image("space.png", 10)
        self.dx = -5
        self.reset(i)

    def update(self, i):
        self.rect.top += self.dx
        if i == 1:
            if self.rect.top <= -600:
                self.__init__(i) 
        else:
            if self.rect.top <= -1200:
                self.__init__(i) 

    def reset(self, i):
        if i == 1:
            self.rect.top = 1
        else:
            self.rect.top = 300

class Space2(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.image, self.rect = load_image("space.png", 10)
        self.dx = -5
        self.reset()

    def update(self):
        self.rect.top += self.dx
        if self.rect.top <= -1200:
            self.__init__() 

    def reset(self):
        self.rect.top = 600

class Player(pygame.sprite.Sprite):

    def __init__(self):

        pygame.sprite.Sprite.__init__(self)

        self.image, self.rect = load_image('ship.gif', -1)
        self.x_dist = 5
        self.y_dist = 5
        self.lasertimer = 0
        self.lasermax = 5
        self.rect.centery = 400
        self.rect.centerx = 400

    def update(self):
        key = pygame.key.get_pressed()

        # Movement
        if key[K_UP]:
            self.rect.centery += -3
        if key[K_DOWN]:
            self.rect.centery += 3
        if key[K_RIGHT]:
            self.rect.centerx += 3
        if key[K_LEFT]:
            self.rect.centerx += -3

        # Lasers
        if key[K_SPACE]:
            self.lasertimer = self.lasertimer + 1
            if self.lasertimer == self.lasermax:
                laserSprites.add(Laser(self.rect.midtop))
                self.lasertimer = 0

        # Restrictions
        self.rect.bottom = min(self.rect.bottom, 600)
        self.rect.top = max(self.rect.top, 0)
        self.rect.right = min(self.rect.right, 800)
        self.rect.left = max(self.rect.left, 0)

class Laser(pygame.sprite.Sprite):
    def __init__(self, pos):
        pygame.sprite.Sprite.__init__(self)
        self.image, self.rect = load_image("laser.png", -1)
        self.rect.center = pos

    def update(self):
        if self.rect.right > 800:
            self.kill()
        else:
            self.rect.move_ip(0, -15)

class Enemy(pygame.sprite.Sprite):
    def __init__(self, centerx):
        pygame.sprite.Sprite.__init__(self)
        self.image, self.rect = load_image("alien.png", -1)
        self.rect = self.image.get_rect()
        self.dy = 8
        self.reset()

    def update(self):
        self.rect.centerx += self.dx
        self.rect.centery += self.dy
        if self.rect.top > 600:
            self.reset()

        # Laser Collisions    
        if pygame.sprite.groupcollide(enemySprites, laserSprites, 1, 1):
           explosionSprites.add(EnemyExplosion(self.rect.center))

        # Ship Collisions
        if pygame.sprite.groupcollide(enemySprites, playerSprite, 1, 1):
           explosionSprites.add(EnemyExplosion(self.rect.center))
           explosionSprites.add(PlayerExplosion(self.rect.center))

    def reset(self):
        self.rect.bottom = 0
        self.rect.centerx = random.randrange(0, 600)
        self.dy = random.randrange(5, 10)
        self.dx = random.randrange(-2, 2)

class EnemyExplosion(pygame.sprite.Sprite):
    def __init__(self, pos):
        pygame.sprite.Sprite.__init__(self)
        self.image, self.rect = load_image("enemyexplosion.png", -1)
        self.rect.center = pos        
        self.counter = 0
        self.maxcount = 10

    def update(self):
        self.counter = self.counter + 1
        if self.counter == self.maxcount:
            self.kill()

class PlayerExplosion(pygame.sprite.Sprite):
    def __init__(self, pos):
        pygame.sprite.Sprite.__init__(self)
        self.image, self.rect = load_image("enemyexplosion.png", -1)
        self.rect.center = pos        
        self.counter = 0
        self.maxcount = 10

    def update(self):
        self.counter = self.counter + 1
        if self.counter == self.maxcount:
            self.kill()
            exit()

def main():       
# Initialize Everything

    pygame.init()

    screen = pygame.display.set_mode((800, 600))

    pygame.display.set_caption('UoN Invaders')

# Create The Backgound

    background = pygame.Surface(screen.get_size())

    background = background.convert()

    background.fill((000, 000, 000))

# Display The Background

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

    pygame.display.flip()

# Start Music   

    music = pygame.mixer.music.load ("data/spacequest.mp3")
    pygame.mixer.music.play(-1)



# Initialize Game Objects
    global clock

    clock = pygame.time.Clock()

    i = 0
    i += 1

    space1 = Space1(i)
    space2 = Space2()
    global player

    player = Player()


# Render Objects
    # Space
    space1 = pygame.sprite.RenderPlain((space1))
    space2 = pygame.sprite.RenderPlain((space2))

    # Player
    global playerSprite   
    playerSprite = pygame.sprite.RenderPlain((player))

    # Enemy
    global enemySprites
    enemySprites = pygame.sprite.RenderPlain(())
    enemySprites.add(Enemy(200))
    enemySprites.add(Enemy(300))
    enemySprites.add(Enemy(400))    

    # Projectiles    
    global laserSprites
    laserSprites = pygame.sprite.RenderPlain(())   

    # Collisions   
    global enemyExplosion
    enemyExplosion = pygame.sprite.RenderPlain(())
    global playerExplosion
    playerExplosion = pygame.sprite.RenderPlain(())
    global explosionSprites
    explosionSprites = pygame.sprite.RenderPlain(())


# Main Loop

    going = True

    while going:

        clock.tick(60)



        # Input Events

        for event in pygame.event.get():

            if event.type == QUIT:

                going = False

            elif event.type == KEYDOWN and event.key == K_ESCAPE:

                going = False

        # Update
        space1.update(i)
        space2.update()
        player.update()
        enemySprites.update()
        laserSprites.update()
        enemyExplosion.update()
        playerExplosion.update()
        explosionSprites.update()



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


        # Draw
        space1.draw(screen) 
        space2.draw(screen)          
        playerSprite.draw(screen)
        enemySprites.draw(screen)
        laserSprites.draw(screen)
        enemyExplosion.draw(screen)
        playerExplosion.draw(screen)
        explosionSprites.draw(screen)


        pygame.display.flip()



    pygame.quit()

if __name__ == '__main__':

    main()

2 个回答

0

我没有使用你提的方法,而是尝试了这个,似乎效果不错。不过,在两个Space之间有一个小缝隙,我正在尝试修复它。以下是修改后的代码:

#!/usr/bin/env python

from helpers import *

print("hello world")

class Space1(pygame.sprite.Sprite):
    def __init__(self, i):                      
        pygame.sprite.Sprite.__init__(self)
        self.image, self.rect = load_image("space.png", 10)
        self.dxy = -5
        self.reset(i)

    def update(self, i):
        self.rect.top += self.dxy
        if self.rect.top <= -600:
            self.__init__(i) 

    def reset(self, i):
        if i == 0:
            self.rect.top = 1
        else:
            self.rect.top = 600

class Space2(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.image, self.rect = load_image("space.png", 10)
        self.dx = -5
        self.reset()

    def update(self):
        self.rect.top += self.dx
        if self.rect.top <= -600:
            self.__init__() 

    def reset(self):
        self.rect.top = 600

class Player(pygame.sprite.Sprite):

    def __init__(self):

        pygame.sprite.Sprite.__init__(self)

        self.image, self.rect = load_image('ship.png', -1)
        self.x_dist = 5
        self.y_dist = 5
        self.lasertimer = 0
        self.lasermax = 5
        self.rect.centery = 400
        self.rect.centerx = 400

    def update(self):
        key = pygame.key.get_pressed()

        # Movement
        if key[K_UP]:
            self.rect.centery += -3
        if key[K_DOWN]:
            self.rect.centery += 3
        if key[K_RIGHT]:
            self.rect.centerx += 3
        if key[K_LEFT]:
            self.rect.centerx += -3

        # Lasers
        if key[K_SPACE]:
            self.lasertimer = self.lasertimer + 1
            if self.lasertimer == self.lasermax:
                laserSprites.add(Laser(self.rect.midtop))
                self.lasertimer = 0

        # Restrictions
        self.rect.bottom = min(self.rect.bottom, 600)
        self.rect.top = max(self.rect.top, 0)
        self.rect.right = min(self.rect.right, 800)
        self.rect.left = max(self.rect.left, 0)

class Laser(pygame.sprite.Sprite):
    def __init__(self, pos):
        pygame.sprite.Sprite.__init__(self)
        self.image, self.rect = load_image("laser.png", -1)
        self.rect.center = pos

    def update(self):
        if self.rect.right > 800:
            self.kill()
        else:
            self.rect.move_ip(0, -15)

class Enemy(pygame.sprite.Sprite):
    def __init__(self, centerx):
        pygame.sprite.Sprite.__init__(self)
        self.image, self.rect = load_image("alien.png", -1)
        self.rect = self.image.get_rect()
        self.dy = 8
        self.reset()

    def update(self):
        self.rect.centerx += self.dx
        self.rect.centery += self.dy
        if self.rect.top > 600:
            self.reset()

        # Laser Collisions    
        if pygame.sprite.groupcollide(enemySprites, laserSprites, 1, 1):
           explosionSprites.add(EnemyExplosion(self.rect.center))

        # Ship Collisions
        if pygame.sprite.groupcollide(enemySprites, playerSprite, 1, 1):
           explosionSprites.add(EnemyExplosion(self.rect.center))
           explosionSprites.add(PlayerExplosion(self.rect.center))

    def reset(self):
        self.rect.bottom = 0
        self.rect.centerx = random.randrange(0, 600)
        self.dy = random.randrange(5, 10)
        self.dx = random.randrange(-2, 2)

class EnemyExplosion(pygame.sprite.Sprite):
    def __init__(self, pos):
        pygame.sprite.Sprite.__init__(self)
        self.image, self.rect = load_image("enemyexplosion.png", -1)
        self.rect.center = pos        
        self.counter = 0
        self.maxcount = 10

    def update(self):
        self.counter = self.counter + 1
        if self.counter == self.maxcount:
            self.kill()

class PlayerExplosion(pygame.sprite.Sprite):
    def __init__(self, pos):
        pygame.sprite.Sprite.__init__(self)
        self.image, self.rect = load_image("enemyexplosion.png", -1)
        self.rect.center = pos        
        self.counter = 0
        self.maxcount = 10

    def update(self):
        self.counter = self.counter + 1
        if self.counter == self.maxcount:
            self.kill()
            exit()

def main():      
    pygame.init()

    screen = pygame.display.set_mode((800, 600))

    pygame.display.set_caption('UoN Invaders')

    background = pygame.Surface(screen.get_size())

    background = background.convert()

    background.fill((000, 000, 000))

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

    pygame.display.flip()

    music = pygame.mixer.music.load ("data/spacequest.mp3")
    pygame.mixer.music.play(-1)

    global clock

    clock = pygame.time.Clock()

    i = 0


    space1 = Space1(i)
    space2 = Space2()
    global player

    player = Player()

    space1 = pygame.sprite.RenderPlain((space1))
    space2 = pygame.sprite.RenderPlain((space2))

    global playerSprite   
    playerSprite = pygame.sprite.RenderPlain((player))

    global enemySprites
    enemySprites = pygame.sprite.RenderPlain(())
    enemySprites.add(Enemy(200))
    enemySprites.add(Enemy(300))
    enemySprites.add(Enemy(400))    

    global laserSprites
    laserSprites = pygame.sprite.RenderPlain(())   

    global enemyExplosion
    enemyExplosion = pygame.sprite.RenderPlain(())
    global playerExplosion
    playerExplosion = pygame.sprite.RenderPlain(())
    global explosionSprites
    explosionSprites = pygame.sprite.RenderPlain(())


# Main Loop
    going = True
    while going:
        clock.tick(60)
        for event in pygame.event.get():

            if event.type == QUIT:

                going = False

            elif event.type == KEYDOWN and event.key == K_ESCAPE:

                going = False
        # Update
        i += 1        
        space1.update(i)
        space2.update()
        player.update()
        enemySprites.update()
        laserSprites.update()
        enemyExplosion.update()
        playerExplosion.update()
        explosionSprites.update()
        screen.blit(background, (0, 0))

        # Draw
        space1.draw(screen) 
        space2.draw(screen)          
        playerSprite.draw(screen)
        enemySprites.draw(screen)
        laserSprites.draw(screen)
        enemyExplosion.draw(screen)
        playerExplosion.draw(screen)
        explosionSprites.draw(screen)
        pygame.display.flip()

    while going == False:
        gameover()


def gameover():
    print("hello world")

if __name__ == '__main__':
    main()
2
class Space(pygame.sprite.Sprite):
    def __init__(self, num):
        pygame.sprite.Sprite.__init__(self)
        self.rect.top = num * 600
        self.image, self.rect = load_image("space.png", 10)
        self.dx = -5
        self.reset()

    def update(self):
        self.rect.top += self.dx
        if self.rect.top <= -1200:
            self.reset() 

    def reset(self):
        self.rect.top = 600

这是一个用来存储你的精灵(sprite)的类。我觉得你不需要两个,因为你可以在主程序中有一个所有空间实例的列表,比如说...

space1 = Space1(i)
space2 = Space2()

我建议你可以这样做。

spaces = []
for x in range(2):
    spaces.append(Space(x))

然后把

space1 = pygame.sprite.RenderPlain((space1))
space2 = pygame.sprite.RenderPlain((space2))

改成

for space in spaces:
    space = pygame.sprite.RenderPlain((space))

然后不要用

space1.update(i)
space2.update()

而是用

for space in spaces:
    space.update()

最后,不要用

space1.draw(screen) 
space2.draw(screen)

而是用

for space in spaces:
    space.draw(screen) 

我希望这个方法对你有用,因为我认为这是存储空间实例的合理方式,并且可以让你的代码更简洁。如果你在实现过程中遇到任何问题,请随时留言,我会帮你解决。

祝好!

撰写回答