如何为同一类的多个对象设置动画? [英] How to animate multiple objects of the same class?

查看:67
本文介绍了如何为同一类的多个对象设置动画?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想让 3 个工人(Worker 类的对象)在屏幕上以不同的随机方向和不同的速度移动.换句话说,我只想运行这样的东西:worker1.makeRandomStep(x,y,1), worker2.makeRandomStep(x,y,2) 和 <代码>worker1.makeRandomStep(x,y,3).

I want to have 3 workers (objects of the class Worker) that move on the screen in different random directions and with a different speed. In other words, I just want to run something like this: worker1.makeRandomStep(x,y,1), worker2.makeRandomStep(x,y,2) and worker1.makeRandomStep(x,y,3).

这是我当前的代码,其中我只有一个 worker:

This is my current code in which I have only one worker:

import pygame, random
import sys

WHITE = (255, 255, 255)
GREEN = (20, 255, 140)
GREY = (210, 210 ,210)
RED = (255, 0, 0)
PURPLE = (255, 0, 255)

SCREENWIDTH=1000
SCREENHEIGHT=578  


class Background(pygame.sprite.Sprite):
    def __init__(self, image_file, location):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.image.load(image_file)
        self.rect = self.image.get_rect()
        self.rect.left, self.rect.top = location



class Worker(pygame.sprite.Sprite):
    def __init__(self, image_file, location):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.image.load(image_file)
        self.rect = self.image.get_rect()
        self.direction = 2
        self.rect.left, self.rect.top = location


    def makeRandomStep(self,x,y,step):
        # there is a less than 1% chance every time that direction is changed
        if random.uniform(0,1)<0.005:
            self.direction = random.randint(1,4)

        if self.direction == 1:
            return x, y+step # up
        elif self.direction == 2:
            return x+step, y # right
        elif self.direction == 3:
            return x, y-step # down
        elif self.direction == 4:
            return x-step, y # left
        else:
            return x, y # stop


pygame.init()

size = (SCREENWIDTH, SCREENHEIGHT)
screen = pygame.display.set_mode(size)
screen_rect=screen.get_rect()
pygame.display.set_caption("TEST")

worker = Worker("worker.png", [0,0])
w_x = worker.rect.left
w_y = worker.rect.top

bg = Background("background.jpg", [0,0])

#sprite_group = pygame.sprite.Group()
#sprite_group.add(worker)

carryOn = True
clock=pygame.time.Clock()

while carryOn:
        for event in pygame.event.get():
            if event.type==pygame.QUIT:
                carryOn=False
                pygame.display.quit()
                pygame.quit()
                quit()

        # Draw floor layout 
        screen.blit(pygame.transform.scale(bg.image, (SCREENWIDTH, SCREENHEIGHT)), bg.rect)

        # Draw geo-fences
        geofence1 = pygame.draw.rect(screen, GREEN, [510,150,75,52])
        geofence2 = pygame.draw.rect(screen, GREEN, [450,250,68,40])

        w_x,w_y = worker.makeRandomStep(w_x,w_y,1)

        # Worker should not go outside the screen area
        if (w_x + worker.rect.width > SCREENWIDTH): w_x = SCREENWIDTH - worker.rect.width
        if (w_x < 0): w_x = 0
        if (w_y + worker.rect.height > SCREENHEIGHT): w_y = SCREENHEIGHT - worker.rect.height
        if (w_y < 0): w_y = 0      
        worker.rect.clamp_ip(screen_rect)

        screen.blit(worker.image, (w_x,w_y))

        # Refresh Screen
        pygame.display.flip()

        #sprite_group.update()
        #sprite_group.draw(screen)

        #Number of frames per secong e.g. 60
        clock.tick(20)

pygame.display.quit()
pygame.quit()
quit()

我不太清楚我应该如何实现我的目标.我想使用 sprite_group,但我误解了如何正确更新 while 循环内的所有精灵(工人).任何帮助都受到高度赞赏.谢谢.

It is not very clear to me how should I proceed to my goal. I was thinking to use sprite_group, but I misunderstand how to correctly update all sprites (workers) inside the while loop. Any help is highly appreciated. Thanks.

推荐答案

您必须将所有工作逻辑移到 Worker 类中(设置随机值、更新位置等).然后创建多个实例.

You have to move all worker logic into the Worker class (setting random values, updating position etc). Then create multiple instances.

这是一个运行示例.请注意解释的注释:

Here's a running example. Note the comments for explanations:

import pygame, random
import sys

WHITE = (255, 255, 255)
GREEN = (20, 255, 140)
GREY = (210, 210 ,210)
RED = (255, 0, 0)
PURPLE = (255, 0, 255)

SCREENWIDTH=1000
SCREENHEIGHT=578  


class Background(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 background to be actually in the back
        self._layer = -1
        pygame.sprite.Sprite.__init__(self, groups)
        # let's resize the background image now and only once
        # always call convert() (or convert_alpha) after loading an image
        # so the surface will have to correct pixel format
        self.image = pygame.transform.scale(pygame.image.load(image_file).convert(), (SCREENWIDTH, SCREENHEIGHT))
        self.rect = self.image.get_rect(topleft=location)

# we do everthing with sprites now, because that will make our live easier
class GeoFence(pygame.sprite.Sprite):
    def __init__(self, rect, *groups):
        # we set a _layer attribute before adding this sprite to the sprite groups
        self._layer = 0
        pygame.sprite.Sprite.__init__(self, groups)
        self.image = pygame.surface.Surface((rect.width, rect.height))
        self.image.fill(GREEN)
        self.rect = rect

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(2, 4)

    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(-100, 100), random.randint(-100, 100))

        # 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(-100, 100), random.randint(-100, 100)) 

        # 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())

pygame.init()

# currently, one group would be enough
# but if you want to use some collision handling in the future
# it's best to group all sprites into special groups (no pun intended)
all_sprites = pygame.sprite.LayeredUpdates()
workers = pygame.sprite.Group()
fences = pygame.sprite.Group()

screen = pygame.display.set_mode((SCREENWIDTH, SCREENHEIGHT))
pygame.display.set_caption("TEST")

# create multiple workers
for pos in ((0,0), (100, 100), (200, 100)):
    Worker("worker.png", pos, all_sprites, workers)

# create multiple of these green thingies
for rect in (pygame.Rect(510,150,75,52), pygame.Rect(450,250,68,40)):
    GeoFence(rect, all_sprites, fences)

# and the background
Background("background.jpg", [0,0], all_sprites)

carryOn = True
clock = pygame.time.Clock()

while carryOn:
    for event in pygame.event.get():
        if event.type==pygame.QUIT:
            carryOn = False

    # see how clean our main loop is
    # just calling update and draw on the all_sprites group
    all_sprites.update(screen)
    all_sprites.draw(screen)

    pygame.display.flip()

    clock.tick(20)

这篇关于如何为同一类的多个对象设置动画?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆