代码之家  ›  专栏  ›  技术社区  ›  ScalaBoy

如何在精灵的底部放置一个附加图像或矩形?

  •  3
  • ScalaBoy  · 技术社区  · 6 年前

    worker 然后在每次迭代时随机更改此图标。请注意雪碧 工人 有两种状态: RUNNING IDLE . 在每一个州 额外的 上的小图像 工人底层 会具体说明 情绪状态 HAPPY ANGRY

    在课堂上 Worker 我创建数组 emo_images emo_state . 这个变量表示 工人 :高兴或生气。每种情绪状态都有它的图像存储在 emotional_images

    在代码中,我随机生成变量 state_indicator . 如果它大于9,那么 更改为 愤怒的 . 否则,它是快乐的。

       state_indicator = random.randint(0,10)
        if state_indicator > 9:
            print(state_indicator)
            self.alert_notif_worker()
    
        def alert_notif_worker(self):
            self.emo_state = Worker.ANGRY
    

    但是我不知道如何把情感形象放在 工人 映像(空闲、运行)。我只需要在底部添加另一个图像,这个额外的图像应该与

    如果很难做到,那么用红色和绿色两种颜色的长方形代替图像来表示情感状态也是可以的。

    import sys
    import pygame, random
    from pygame.math import Vector2
    from scipy.optimize import minimize
    import math
    
    
    WHITE = (255, 255, 255)
    GREEN = (20, 255, 140)
    GREY = (210, 210 ,210)
    BLACK = (0, 0 ,0)
    RED = (255, 0, 0)
    PURPLE = (255, 0, 255)
    
    
    SCREENWIDTH=1000
    SCREENHEIGHT=578
    # Create point vectors for the corners.
    corners = [
        Vector2(0, 0), Vector2(SCREENWIDTH, 0),
        Vector2(SCREENWIDTH, SCREENHEIGHT), Vector2(0, SCREENHEIGHT)
        ]
    
    ABS_PATH = "/Users/sb/Desktop/"
    IMG_BACKGROUND = ABS_PATH + "images/background.jpg"
    IMG_WORKER_RUNNING = ABS_PATH + "images/workers/worker_1.png"
    IMG_WORKER_IDLE = ABS_PATH + "images/workers/worker_2.png"
    IMG_WORKER_ACCIDENT = ABS_PATH + "images/workers/accident.png"
    IMG_WORKER_HAPPY = ABS_PATH + "images/workers/happy.png"
    IMG_WORKER_ANGRY = ABS_PATH + "images/workers/angry.png"
    
    
    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
            self.image = pygame.transform.scale(pygame.image.load(image_file).convert(), (SCREENWIDTH, SCREENHEIGHT))
            self.rect = self.image.get_rect(topleft=location)
    
    
    class Worker(pygame.sprite.Sprite):
    
        RUNNING = 0
        IDLE = 1
        HAPPY = 0
        ANGRY = 1
        IMAGE_CACHE = {}
    
        def __init__(self, idw, image_running, image_idle, image_happy, image_angry, location, *groups):
    
            self.font = pygame.font.SysFont('Arial', 20)
    
            # each state has it's own image
            self.images = {
                Worker.RUNNING: pygame.transform.scale(self.get_image(image_running), (45, 45)),
                Worker.IDLE: pygame.transform.scale(self.get_image(image_idle), (20, 45))
            }
    
            self.emo_images = {
                Worker.HAPPY: pygame.transform.scale(self.get_image(image_happy), (20, 20)),
                Worker.ANGRY: pygame.transform.scale(self.get_image(image_angry), (20, 20))
            }
    
    
            # we set a _layer attribute before adding this sprite to the sprite groups
            # we want the workers on top
            self._layer = 0
            pygame.sprite.Sprite.__init__(self, groups)
    
            self.idw = idw
    
            # let's keep track of the state and how long we are in this state already            
            self.state = Worker.IDLE
            self.emo_state = Worker.HAPPY
            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(1, 3)
            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 not
            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) and (self.state != Worker.ACCIDENT):
                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]
            #self.emo_image = self.emo_images[self.emo_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) > 70:
                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
    
    
            send_alert = random.randint(0,10)
            if send_alert > 9:
                print(send_alert)
                self.alert_notif_worker()
    
            self.rect.clamp_ip(screen.get_rect())
    
    
        def alert_notif_worker(self):
            self.emo_state = Worker.ANGRY
    
    
        def get_image(self,key):
            if not key in Worker.IMAGE_CACHE:
                Worker.IMAGE_CACHE[key] = pygame.image.load(key)
            return Worker.IMAGE_CACHE[key]
    
    
    
    
    pygame.init()
    
    all_sprites = pygame.sprite.LayeredUpdates()
    workers = pygame.sprite.Group()
    
    screen = pygame.display.set_mode((SCREENWIDTH, SCREENHEIGHT))
    pygame.display.set_caption("TEST")
    
    # create multiple workers
    idw = 1
    for pos in ((30,30), (50, 400), (200, 100), (700, 200)):
        Worker(idw, IMG_WORKER_RUNNING, IMG_WORKER_IDLE, 
               IMG_WORKER_HAPPY, IMG_WORKER_ANGRY, 
               pos, all_sprites, workers)
        idw+=1
    
    # and the background
    Background(IMG_BACKGROUND, [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
                pygame.display.quit()
                pygame.quit()
                quit()
    
        all_sprites.update(screen)
        all_sprites.draw(screen)
    
        pygame.display.flip()
    
        clock.tick(20)
    
    2 回复  |  直到 6 年前
        1
  •  2
  •   skrx    6 年前

    我要么使用Micheal O'Dwyer的解决方案,在一个单独的for循环中blit图标图像,要么创建一个 Icon Worker 上课。然后你可以更新图标精灵在 update 方法,并在工作状态更改时交换图像。

    你需要一个 LayeredUpdates

    import pygame as pg
    from pygame.math import Vector2
    
    
    pg.init()
    WORKER_IMG = pg.Surface((30, 50))
    WORKER_IMG.fill(pg.Color('dodgerblue1'))
    ICON_HAPPY = pg.Surface((12, 12))
    ICON_HAPPY.fill(pg.Color('yellow'))
    ICON_ANGRY = pg.Surface((10, 10))
    ICON_ANGRY.fill(pg.Color('red'))
    
    
    class Worker(pg.sprite.Sprite):
    
        def __init__(self, pos, all_sprites):
            super().__init__()
            self._layer = 0
            self.image = WORKER_IMG
            self.rect = self.image.get_rect(center=pos)
            self.state = 'happy'
            self.emo_images = {'happy': ICON_HAPPY, 'angry': ICON_ANGRY}
            # Create an Icon instance pass the image, the position
            # and add it to the all_sprites group.
            self.icon = Icon(self.emo_images[self.state], self.rect.bottomright)
            self.icon.add(all_sprites)
    
        def update(self):
            # Update the position of the icon sprite.
            self.icon.rect.topleft = self.rect.bottomright
    
        def change_state(self):
            """Change the state from happy to angry and update the icon."""
            self.state = 'happy' if self.state == 'angry' else 'angry'
            # Swap the icon image.
            self.icon.image = self.emo_images[self.state]
    
    
    class Icon(pg.sprite.Sprite):
    
        def __init__(self, image, pos):
            super().__init__()
            self._layer = 1
            self.image = image
            self.rect = self.image.get_rect(topleft=pos)
    
    
    def main():
        screen = pg.display.set_mode((640, 480))
        clock = pg.time.Clock()
        all_sprites = pg.sprite.LayeredUpdates()
        worker = Worker((50, 80), all_sprites)
        all_sprites.add(worker)
    
        done = False
    
        while not done:
            for event in pg.event.get():
                if event.type == pg.QUIT:
                    done = True
                elif event.type == pg.MOUSEMOTION:
                    worker.rect.center = event.pos
                elif event.type == pg.KEYDOWN:
                    worker.change_state()
    
            all_sprites.update()
            screen.fill((30, 30, 30))
            all_sprites.draw(screen)
    
            pg.display.flip()
            clock.tick(60)
    
    
    if __name__ == '__main__':
        main()
        pg.quit()
    
        2
  •  2
  •   Micheal O'Dwyer    6 年前

    这可以相当容易地实现,只需将每个 Worker 的情感图像,在某个位置,与 工人 rect.x ,和 rect.y 坐标。

    Background 正在将您正在初始化的对象添加到 all_sprites ,所以你可以考虑改变 所有精灵 all_workers ,并可能添加 背景

    您还需要初始化 offset_x ,和 offset_y 为你工作的价值观。下面使用的值只会将图像移动到工作者的左下角。

    for worker in all_workers:
       offset_x = 0
       offset_y = worker.rect.height
       screen.blit(worker.emo_images[worker.emo_state], (worker.rect.x+offset_x, worker.rect.y+offset_y))
    

    我希望这个答案能帮助你!请让我知道这是否适合你,如果你有任何进一步的问题,请在下面留下评论。