我目前正在尝试根据游戏工厂与僵尸之间的关系制作游戏动画。当僵尸在屏幕上移动并接触植物时,植物精灵会保存在一个名为plant_eaten_list的列表中。僵尸也停止向左移动。在1秒钟的延迟后(当plants_eaten_event被触发时),植物失去10个健康点。当植物的生命值达到0时,植物精灵会通过plant.kill()命令死亡。
设置计时器的代码(pygame.time.set_timer(plants_eaten_event,1000)必须位于主while循环内,以便不断检查plants_eaten_list中的植物,但是,我的问题是每次刷新在while循环中,plants_eaten_event的计时器重置为1秒,因此plants_eaten_event永远不会发生。
有什么办法可以构造此程序的逻辑来减轻此问题?
我不拥有任何这些图像的版权,并且这些图像仅供私人使用。 僵尸图片是从http://plantsvszombies.wikia.com/wiki/Zombie/Gallery?file=Regular_Zombie.png下载的 植物图像是从http://plantsvszombies.wikia.com/wiki/File:Peashooter.png
下载的这是我的代码:
import pygame
import random
BLACK = (0,0,0)
WHITE = (255,255,255)
RED = (255,0,0)
BLUE = (0,0,255)
GREEN = (0,255,0)
pygame.init()
borders_sound = pygame.mixer.Sound("bump.wav")
class Zombie(pygame.sprite.Sprite):
def __init__(self, x, y):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("Regular_Zombie.png").convert()
self.image.set_colorkey(WHITE)
# Make our top-left corner the passed-in location.
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
# -- Attributes
# Set speed vector
self.change_x = -1
self.change_y = 0
def changespeed(self, x, y):
""" Change the speed of the player"""
self.change_x += x
self.change_y += y
def move(self):
""" Find a new position for the player"""
#self.change_x = -1
self.rect.x += self.change_x
#print(self.rect.x)
#times = 0
if self.rect.x < 0:
self.rect.x = 0
def eatplant(self,plant):
pygame.time.set_timer(plants_eaten_event,6000)
self.change_x = 0
plant.health = plant.health - 10
class Plant(pygame.sprite.Sprite):
def __init__(self, x, y):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("Peashooter.png").convert()
self.image.set_colorkey(BLUE)
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.alive = True
self.health = 60
screen_width = 700
screen_height = 400
screen = pygame.display.set_mode([screen_width, screen_height])
all_sprites_list = pygame.sprite.Group()
plants_list = pygame.sprite.Group()
zombies_list = pygame.sprite.Group()
zombie1 = Zombie(690, 15)
plant1 = Plant(300,15)
all_sprites_list.add(zombie1)
all_sprites_list.add(plant1)
plants_list.add(plant1)
zombies_list.add(zombie1)
done = False
clock = pygame.time.Clock()
plants_eaten_event = pygame.USEREVENT + 1
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
# If plant.health = 0 at the end of the timer, the plant is eaten.
# If plant.health != 0 at the end of the timer, the entire event
# must happen again in the while loop until the health = 0
elif event.type == plants_eaten_event:
print("Zombie 1 ate plant 1")
zombie1.eatplant(plant)
# Set timer equal to 0 until another plant gets eaten or zombie continues eating current plant
pygame.time.set_timer(plants_eaten_event, 0)
if plant.health == 0:
plant.alive = False
plant.kill()
zombie1.change_x = -1
zombie1.move()
elif event.type == zombie_eaten_plant_event:
zombie1.change_x = -1
zombie1.move()
print("Zombie 1 is eating plant")
pygame.time.set_timer(zombie_eaten_plant_event, 0)
screen.fill(WHITE)
zombie1.move()
if times == 0 and zombie1.rect.x <= 0:
times = times + 1
borders_sound.play()
all_sprites_list.draw(screen)
all_sprites_list.update()
# I set the do kill command in spritecollide command to False because I
# needed to delay the plants that were eaten before they were removed. They
# will be removed after six seconds(symbolize zombies eating plants). Aftera
# a period of time, then I will create a loop that will loop through all plants
# in the plants_eaten_list and use .kill() . I will need to create a separate
# collision function that will stall the zombies until the plants are killed.
plants_eaten_list = pygame.sprite.spritecollide(zombie1,plants_list,False)
# I changed the delay to 6 seconds, and plant 1 still died instantly. The zombie
# stayed frozen in place for 6 seconds before teh 2nd plant was instantly destroyed
for plant in plants_eaten_list:
# If I remove this, plant1 is not killed, even though
# there is the same code within the plants_eaten_event function.
if plant1.health == 0:
plant1.kill()
# The while loop loops so fast that the timer doesnot have a chance to
# finish its countdown before it restarts again. Will I need some kind of a threading
# module to prevent the timers from restarting until they end?
pygame.time.set_timer(plants_eaten_event, 1000)
for plant_eaten in plants_eaten_list:
borders_sound.play()
clock.tick(60)
pygame.display.flip()
pygame.quit()
答案 0 :(得分:1)
我的问题是,对于while循环的每次刷新,plants_eaten_event的计时器都会重置为1秒,因此没发生plants_eaten_event。
之所以发生这种情况,是因为僵尸的rect在下一帧中仍然与植物的rect发生冲突,spritecollide
返回带有冲突植物的列表和for plant in plants_eaten_list:
循环,您在其中调用{{1 }}每帧再次执行。
您需要做的第一件事是在第一次碰撞后将set_timer
的位置设置为zombie.rect.left
,以使子画面在下一帧中不再发生碰撞:
plant.rect.right
但是,一旦开始添加更多的僵尸,代码就会中断,因为您在事件循环中使用了for plant in plants_eaten_list:
zombie1.change_x = 0 # Stop the zombie.
# Move the rect so that it doesn't touch the plant's rect anymore.
zombie1.rect.left = plant.rect.right
if plant1.health <= 0:
plant1.kill()
pygame.time.set_timer(plants_eaten_event, 1000)
borders_sound.play()
和zombie1
变量(取决于plant
循环),因此它仅适用于该僵尸和最后一次碰撞的植物。不幸的是,发送的信息不能超过使用for plant in plants_eaten_list:
的事件类型,否则您可以将特定的僵尸和植物附加到事件上,以便在事件循环中处理它们。
另一种解决方案是为每个僵尸都提供自己的计时器属性(只是一个数字),您可以在其pygame.time.set_timer
方法中对其进行更新。
因此,当僵尸接触植物时,我将计时器设置为1(秒),然后将其递减每帧的增量时间(最后一帧所需的时间),以启动计时器。我也停止了僵尸update
,将矩形移回self.change_x = 0
并存储对植物的引用,因为我们需要它来减少计时器结束时的运行状况。
一旦计时器为self.rect.left = plant.rect.right
,僵尸就会再次移动,咬住植物,精灵再次接触,计时器重新开始。
<= 0