Python 如何在Sprite的底部添加一个额外的图像或矩形?
我需要在SpritePython 如何在Sprite的底部添加一个额外的图像或矩形?,python,python-3.x,pygame,Python,Python 3.x,Pygame,我需要在Spriteworker的底部添加一个图标,然后在每次迭代中随机更改该图标。请注意,精灵工作者有两种状态:正在运行和空闲。在每种状态下,工作者都有一个特定的图像。我现在需要的是在worker的底部添加一个小图像,该图像将指定情绪状态:高兴的或生气的 在类Worker中,我创建数组emo\u images,并指定变量emo\u state。此变量表示员工的情绪状态:高兴或生气。每个情绪状态都将其图像存储在情绪图像中 在代码中,我随机生成变量state\u indicator。如果大于9,则
worker
的底部添加一个图标,然后在每次迭代中随机更改该图标。请注意,精灵<代码>工作者有两种状态:正在运行
和空闲
。在每种状态下,工作者
都有一个特定的图像。我现在需要的是在worker的底部添加一个小图像,该图像将指定情绪状态:高兴的或生气的
在类Worker
中,我创建数组emo\u images
,并指定变量emo\u state
。此变量表示员工的情绪状态:高兴或生气。每个情绪状态都将其图像存储在情绪图像中
在代码中,我随机生成变量state\u 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)
这可以相当容易地实现,只需在某个特定位置,相对于工作者的rect.x
和rect.y
坐标,快速点击每个工作者的情绪图像
不幸的是,我无法测试下面的代码示例,因为您的代码使用了很多我没有的图像。在实现这个代码之前,我需要看到的一个问题是,您正在初始化的背景< /Cord>对象正在添加到<代码> AljSpRistes < /代码>中,因此您可以考虑将<代码> ALL SpRistes < /代码>改为<代码> ALLWorksWorks<代码>,并且可以将<代码>背景<代码>添加到不同的组。
您还需要将offset\u x
和offset\u 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))
我希望这个答案对你有帮助!请让我知道这是否适用于您,如果您有任何进一步的问题,请随时在下面留下评论。我可以使用Micheal O'Dwyer的解决方案并在单独的for循环中blit图标图像,或者创建一个图标
精灵类,该类可以作为工作者
类的属性添加。然后,您可以在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()