python - 如何在动画过程中改变 Sprite 的图像?

标签 python pygame

我想在每次停止时更改对象 worker 的图像。

Worker是根据@sloth的答案创建的在 this thread .

class Worker(pygame.sprite.Sprite):
    def __init__(self, image_file, location, *groups):
        # we set a _layer attribute before adding this sprite to the sprite groups
        # we want the workers on top
        self._layer = 1
        pygame.sprite.Sprite.__init__(self, groups)
        self.image = pygame.transform.scale(pygame.image.load(image_file).convert_alpha(), (40, 40))
        self.rect = self.image.get_rect(topleft=location)
        # let's call this handy function to set a random direction for the worker
        self.change_direction()
        # speed is also random
        self.speed = random.randint(1, 3)

    def change_direction(self):
        # let's create a random vector as direction, so we can move in every direction
        self.direction = pygame.math.Vector2(random.randint(-1,1), random.randint(-1,1))

        # we don't want a vector of length 0, because we want to actually move
        # it's not enough to account for rounding errors, but let's ignore that for now
        while self.direction.length() == 0:
            self.direction = pygame.math.Vector2(random.randint(-1,1), random.randint(-1,1)) 

        # always normalize the vector, so we always move at a constant speed at all directions
        self.direction = self.direction.normalize()

    def update(self, screen):
        # there is a less than 1% chance every time that direction is changed
        if random.uniform(0,1)<0.005:
            self.change_direction()

        # now let's multiply our direction with our speed and move the rect
        vec = [int(v) for v in self.direction * self.speed]
        self.rect.move_ip(*vec)

        # if we're going outside the screen, move back and change direction
        if not screen.get_rect().contains(self.rect):
            self.change_direction()
        self.rect.clamp_ip(screen.get_rect())

我尝试创建预加载图像的缓存

image_cache = {}
def get_image(key):
    if not key in image_cache:
        image_cache[key] = pygame.image.load(key)
    return image_cache[key]

那么我假设有必要将以下代码添加到def __init__中:

images = ["worker.png", "worker_stopped.png"]
for i in range(0,len(images)):
   self.images[i] = get_image(images[i])

并将以下代码放入def update(self)中:

if self.direction.length() == 0:
    self.image = self.images[1]
else:
    self.image = self.images[0]

但是,它似乎无法正常工作。旧图像 worker.png 不会消失,整个动画被锁定。

最佳答案

我认为你应该引入某种状态来指示工作线程是否正在运行。这是一个例子。请注意评论:

class Worker(pygame.sprite.Sprite):

    # we introduce to possible states: RUNNING and IDLE
    RUNNING = 0
    IDLE = 1

    def __init__(self, location, *groups):

        # each state has it's own image
        self.images = {
            Worker.RUNNING: pygame.transform.scale(get_image("worker.png"), (40, 40)),
            Worker.IDLE: pygame.transform.scale(get_image("worker_stopped.png"), (40, 40))
        }

        self._layer = 1
        pygame.sprite.Sprite.__init__(self, groups)

        # let's keep track of the state and how long we are in this state already            
        self.state = Worker.IDLE
        self.ticks_in_state = 0

        self.image = self.images[self.state]
        self.rect = self.image.get_rect(topleft=location)

        self.direction = pygame.math.Vector2(0, 0)
        self.speed = random.randint(2, 4)
        self.set_random_direction()

    def set_random_direction(self):
        # random new direction or standing still
        vec = pygame.math.Vector2(random.randint(-100,100), random.randint(-100,100)) if random.randint(0, 5) > 1 else pygame.math.Vector2(0, 0)

        # check the new vector and decide if we are running or fooling around
        length = vec.length()
        speed = sum(abs(int(v)) for v in vec.normalize() * self.speed) if length > 0 else 0

        if length == 0 or speed == 0:
            new_state = Worker.IDLE
            self.direction = pygame.math.Vector2(0, 0)
        else:
            new_state = Worker.RUNNING
            self.direction = vec.normalize()

        self.ticks_in_state = 0
        self.state = new_state

        # use the right image for the current state
        self.image = self.images[self.state]

    def update(self, screen):
        self.ticks_in_state += 1
        # the longer we are in a certain state, the more likely is we change direction
        if random.randint(0, self.ticks_in_state) > 30:
            self.set_random_direction()

        # now let's multiply our direction with our speed and move the rect
        vec = [int(v) for v in self.direction * self.speed]
        self.rect.move_ip(*vec)

        # if we're going outside the screen, change direction
        if not screen.get_rect().contains(self.rect):
            self.direction = self.direction * -1

        self.rect.clamp_ip(screen.get_rect())

关于python - 如何在动画过程中改变 Sprite 的图像?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51724335/

相关文章:

python - 我在这个乒乓球游戏中画了一个边界,但 Racket 可以越过它。我该如何阻止它?

python - lxml 找到 ID 为 ='post-[0-9]*' 的 <div>

python - Airflow Scheduler 为同一个 dag 创建 PID 以每次生成任务

python - 如何在用beat再次运行之前检查celery任务是否已经在运行?

处理二进制文件的python性能

python - 如何在Flask中使用SubmitField的onclick函数(WTF SubmitField问题)

python - 从列表中删除未引用的对象

python - 如何在不影响其余部分的情况下延迟程序的一部分?

python - 如何使用python将鼠标光标置于屏幕中央

python-3.x - 如何使该 Sprite 可点击,然后关闭它以便渲染新 map ?