【问题标题】:Pygame sprite group using random.rand使用 random.rand 的 Pygame 精灵组
【发布时间】:2017-09-24 06:23:52
【问题描述】:

我正在处理一个包含 60 个精灵对象的精灵组。 每个对象代表一个小行星图像,并且以正确顺序依次显示的所有图像创建旋转小行星的动画,换句话说,我正在遍历精灵组,如下面的代码所示。

Evcerything 工作正常,直到对象超过屏幕高度并再次在顶部重置,然后对象开始出现在 x 方向上的随机位置。屏幕现在似乎在随机位置闪烁每个精灵,而小行星现在只是水平来回闪烁。

有没有办法在小行星 obj 通过屏幕后为所有精灵获取相同的新随机 x 位置,而不是给组中的每个精灵一个新的 x 值?

有什么建议吗?

import pygame
import sys
import os
import random
import time
import math

black = (0, 0, 0)
white = (255, 255, 255)
red = (200, 40, 60)
green = (50, 180, 50)
blue = (50, 30, 200)
skyblue = (135, 206, 250)
silver = (192, 192, 192)
darkgray = (47, 79, 79)
vegasgold = (197, 179, 88)
nightblue = (25, 25, 112)
steelblue = (70, 130, 180)
deepblue = (0, 26, 51)

screen_width = 1920
screen_height = 1080
half_width = screen_width/2
half_height = screen_height/2

screen = pygame.display.set_mode([screen_width, screen_height])
Title = pygame.display.set_caption('Space Mash')
clock = pygame.time.Clock()

class Spaceship(pygame.sprite.Sprite):

    def __init__(self, width=30, height=30, color=white):
        super(Spaceship, self).__init__()

        self.image = pygame.Surface([width, height])
        self.image.fill(color)
        self.rect = self.image.get_rect()
        self.rect.x = 0
        self.rect.y = 0

    def center_set_position(self, x, y):
        self.rect.x = x - self.rect.center[0]
        self.rect.y = y - self.rect.width

    def rotate_ship(self, dg):
        self.image = pygame.transform.rotate(self.image, dg)

    def set_image(self, filename):
        self.image = pygame.image.load(filename)
        self.rect = self.image.get_rect()

    def draw_ship(self):
        screen.blit(self.image, [self.rect.x, self.rect.y])


player_spaceship = Spaceship()
player_spaceship.set_image("main_ship.png")
player_spaceship.center_set_position(half_width, screen_height)
all_sprites_list = pygame.sprite.Group()
all_sprites_list.add(player_spaceship)


class Asteroids(pygame.sprite.Sprite):
    def __init__(self, nr):
        super(Asteroids, self).__init__()

        self.image = pygame.image.load('Asteroid_{0}.png'.format(nr))
        self.rect = self.image.get_rect()
        self.rect.x = 0
        self.rect.y = 0

    def update(self):
        self.rect.y += 5

        if self.rect.y > screen_height + 50:
            self.rect.y = -50
            self.rect.x = random.randrange(0, (screen_width - (self.rect.width))


asteroids_list = pygame.sprite.LayeredUpdates() 

for i in range(1, 61):
    asteroid = Asteroids(nr=i)

    asteroids_list.add(asteroid)
    all_sprites_list.add(asteroid)



class Stars(pygame.sprite.Sprite):
    def __init__(self):
        super(Stars, self).__init__()

        self.image = pygame.Surface([1, 1])
        self.image.fill(white)
        self.rect = self.image.get_rect()

stars_group = pygame.sprite.Group()


def making_star_objects():

    for i in range(100):
        x_loc = random.randint(0, screen_width - 1)
        y_loc = random.randint(0, screen_height - 1)
        star = Stars()
        star.rect.x = x_loc
        star.rect.y = y_loc

        stars_group.add(star)


def gameloop():
    ending = False
    x_change = 0
    y_change = 0
    making_star_objects()
    frame = 0

    while not ending:

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                quit()

            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_RIGHT:
                    x_change = 10
                elif event.key == pygame.K_LEFT:
                    x_change = -10
                elif event.key == pygame.K_UP:
                    y_change = -8
                elif event.key == pygame.K_DOWN:
                    y_change = 8
            if event.type == pygame.KEYUP:
                if event.key == pygame.K_RIGHT:
                    x_change = 0
                elif event.key == pygame.K_LEFT:
                    x_change = 0


        player_spaceship.rect.x += x_change
        player_spaceship.rect.y += y_change
        if frame > 59:
            frame = 0

        asteroids_list.update()


        asteroids_hit_list = pygame.sprite.spritecollide(player_spaceship, asteroids_list, False)

        screen.fill(deepblue)
        stars_group.draw(screen)
        screen.blit(asteroids_list.get_sprite(frame).image, (asteroids_list.get_sprite(frame).rect.x,
                                                        asteroids_list.get_sprite(frame).rect.y))



        frame += 1

        player_spaceship.draw_ship()
        pygame.display.update()
        clock.tick(30)

    pygame.quit()
    quit()

gameloop()

【问题讨论】:

    标签: python animation random pygame


    【解决方案1】:

    您可以添加 类变量 属性并存储分配的第一个坐标 X,然后在需要时重新使用该值。它可以从所有对象访问,因为它是一个类全局变量。

    如果你用这种方式给变量赋值,在程序的所有执行过程中它都是一样的(如果你不改变它),因为它的值是在创建类时赋值的。

    rectXCopy = random.randrange(0, (screen_width - (self.rect.width))

    最后,你的班级会变成这样:

    class Asteroids(pygame.sprite.Sprite):
        rectXCopy = random.randrange(0, (screen_width - (self.rect.width))
        def __init__(self, nr):
            super(Asteroids, self).__init__()
    
            self.image = pygame.image.load('Asteroid_{0}.png'.format(nr))
            self.rect = self.image.get_rect()
            self.rect.x = 0
            self.rect.y = 0
            self.rectYCopy = 0
            self.copied = False
    
        def update(self):
            self.rect.y += 5
    
            if self.rect.y > screen_height + 50:
                self.rect.y = -50
                self.rect.x = self.rectXcopy
    

    【讨论】:

    • update 方法将组中的所有精灵设置为一个新的单个 rect.x 值,但我希望所有对象的 rect.x 都相同,因为它们都是同一动画的一部分。跨度>
    • 所以您希望分配给所有精灵的第一个rect.x 值都相同?
    • 如果你安装了 python 和 pygame,你可以复制我的代码并让程序运行:)
    • 这样的话,我马上更新代码,请稍等。
    • 代码已更新,请查看并告诉我 ;) PS:我没有 pygame,所以无法查看 :( @DanielBäck
    【解决方案2】:

    问题是你在asteroids_list sprite 组中将所有动画帧作为单独的 sprite 对象。它们都有自己的矩形,如果你更新其中一个,其他的不会受到影响。因此,当精灵离开屏幕时,您将它们全部设置为不同的随机位置。

    我建议只创建一个小行星对象,将图像放入列表或字典(无论你喜欢什么),然后在其更新方法中更改单个小行星精灵的图像以创建动画。

    # Put the images / pygame.Surfaces into a global constant list.
    ASTEROID_FRAMES = [surface1, surface2]  # etc. (use a list comprehension)
    
    class Asteroids(pygame.sprite.Sprite):
    
        def __init__(self, nr):
            super(Asteroids, self).__init__()
            self.image = ASTEROID_FRAMES[0]
            self.rect = self.image.get_rect(topleft=(0, 0))
            self.frame = 0
    
        def update(self):
            self.rect.y += 5
    
            if self.rect.y > screen_height + 50:
                self.rect.y = -50
                self.rect.x = random.randrange(0, (screen_width - (self.rect.width)))
    
            # Update the image (this is frame rate bound, but you can also
            # add a timer to change the frame after some time has passed).
            self.frame += 1
            # Keep the index in the correct range.
            self.frame %= len(ASTEROID_FRAMES)
            self.image = ASTEROID_FRAMES[self.frame]
    

    【讨论】:

    • 这个答案有帮助还是我应该解释更详细的内容?
    猜你喜欢
    • 1970-01-01
    • 2017-09-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多