#animation #pygame #wait #python-3.7
#Анимация #pygame #подождите #python-3.7
Вопрос:
У меня возникла проблема с анимацией разных кадров спрайта. Моя программа работает со скоростью 60 кадров в секунду, и у некоторых моих спрайтов недостаточно кадров, чтобы выглядеть плавно и дать достаточно времени, чтобы быть видимыми для пользователя. Например, мой спрайт взрыва содержит 6 кадров. В то время как игра работает со скоростью 60 кадров в секунду, это означает, что вся анимация видна только в течение 1/10 секунды.
Я уже пробовал следующие функции: Pygame.подождите и Pygame.задержка и функция «//» floor. Pygame.wait / delay оба полностью приостанавливают программу, что будет означать, что просто для того, чтобы увидеть взрыв, пользователю придется остановить все, что они делают, и я не хочу дублировать кадры, чтобы получить 30 или 60 кадров, это просто кажется неэффективным.
Массив взрыва:
Expl = [pygame.image.load("EX1.png"),pygame.image.load("EX2.png"),pygame.image.load("EX3.png"),pygame.image.load("EX4.png"),pygame.image.load("EX5.png"),pygame.image.load("EX6.png")]
Где это происходит:
if self.explosionc 1 >= 6:
self.explosionc = 0
elif self.vel > 0:
win.blit(Expl[self.explosionc // 5],(self.x,self.y))
self.explosionc =1
Класс проигрывателя, если вам нужно так много информации
class Player(pygame.sprite.Sprite):
def __init__(self,x,y,width,height):
self.x = x
self.y = y
self.width = width
self.height = height
self.vel = 5
self.health = 10
self.visible = True
self.explosions = False
self.explosionc = 0
self.hitbox = (self.x 5,self.y 10,60,60)
self.canshoot = True
self.dead = False
def draw(self,win):
global bgvel
if self.y > 600:
win.blit(EFTNA,(self.x,self.y))
for enemy in enemies:
enemy.vel = 2
#bgvel = 1
elif self.y <= 600 and self.y > 400:
win.blit(EFTAL,(self.x,self.y))
for enemy in enemies:
enemy.vel = 3
#bgvel = 2
elif self.y <= 400 and self.y > 350:
win.blit(EFTAM,(self.x,self.y))
for enemy in enemies:
enemy.vel = 4
#bgvel = 3
elif self.y <= 450:
win.blit(EFTAH,(self.x,self.y))
for enemy in enemies:
enemy.vel = 5
#bgvel = 4
self.hitbox = (self.x 5,self.y 10,60,60)
#pygame.draw.rect(win,(255,0,0),self.hitbox,2)
if self.y self.height > HEIGHT:
self.y -= self.vel
if self.x < 0:
self.x = self.vel
if self.x self.width > WIDTH:
self.x -= self.vel
if self.explosions == True:
print("I exploded")
self.canshoot = False
self.dead = True
index = self.explosionc//10
if self.vel > 0:
win.blit(Expl[index % 6],(self.x,self.y))
self.explosionc = 1
#if self.explosionc >= 6*10:
# self.explosionc = 0
self.visible = False
def hit(self):
if self.health > 0:
self.health -=1
else:
self.explosions = True
Я ожидаю, что программа будет ждать определенное количество времени между каждым кадром без остановки всей программы. Я слышал, что «настил» — хороший способ сделать это, но он просто не кажется эффективным, поскольку либо делает его полностью невидимым для человеческого глаза, либо не дает эффекта.
Комментарии:
1. вы могли бы использовать pygame.time.get_ticks , чтобы контролировать, когда менять отображаемый кадр. В начале анимации вы получаете текущее время с помощью
pygame.time.get_ticks
, а позже в каждом цикле вы получаете время (также используяpygame.time.get_ticks
) и вычисляете разницу. если это ожидаемое значение, то вы меняете кадр и сохраняете текущее время для сравнения со временем в следующем цикле.2. вы также можете использовать pygame.time.set_timer для создания собственного события каждые несколько секунд / миллисекунд. И затем вы можете использовать это событие для изменения кадра в анимации.
3. Что делает
self.dead
иself.visible
? Не следует ли изменять состояния после взрыва, а не в начале?
Ответ №1:
Вы можете использовать pygame.time.get_ticks()
для использования времени, чтобы контролировать, как долго вы отображаете кадр
start_time = pygame.time.get_ticks()
while running:
current_time = pygame.time.get_ticks()
if current_time - start_time >= expected_delay_in_ms:
change_frame_in_animation()
start_time = current_time
Я создаю start_time
раньше while running
, но вы должны создать его при запуске анимации.
Вы также можете использовать pygame.time.set_timer()
для создания собственного события каждые несколько миллисекунд. И затем вы можете использовать это событие для изменения кадра в анимации
pygame.time.set_timer(pygame.USEREVENT 1, expected_delay_in_ms)
while running:
for event in pygame.event.get():
if event.type = pygame.USEREVENT 1:
change_frame_in_animation()
Я использовал pygame.time.set_timer()
раньше while running
, но вы должны использовать его при запуске анимации.
РЕДАКТИРОВАТЬ: Используя ваш новый код, о котором идет речь, это может быть (но я не могу его протестировать)
В self.__init__
я определяю
self.frame_delay = 200 # 200 milliseconds
Когда игрок умирает, я установил self.start_delay = 0
— он должен отображать первый кадр без задержки.
def hit(self):
if self.health > 0:
self.health -= 1
else:
self.explosions = True
self.start_delay = 0 # or pygame.time.get_ticks()
В draw
я использую self.start_delay
для сравнения с current_time
и self.frame_delay
if self.explosions == True:
current_time = pygame.time.get_ticks()
if current_time - self.start_delay >= self.frame_delay:
self.start_delay = current_time
print("I exploded")
self.canshoot = False
self.dead = True
self.explosionc = (self.explosionc 1) % 6
if self.vel > 0: # ???
win.blit(Expl[self.explosionc],(self.x,self.y))
self.visible = False
Я вычисляю следующий кадр с
self.explosionc = (self.explosionc 1) % 6
Я не знаю только, почему вы используете if self.vel > 0:
Полный код
class Player(pygame.sprite.Sprite):
def __init__(self,x,y,width,height):
self.x = x
self.y = y
self.width = width
self.height = height
self.vel = 5
self.health = 10
self.visible = True
self.explosions = False
self.explosionc = 0
self.hitbox = (self.x 5,self.y 10,60,60)
self.canshoot = True
self.dead = False
self.frame_delay = 200 # 200 milliseconds
def draw(self,win):
global bgvel
if self.y > 600:
win.blit(EFTNA,(self.x,self.y))
for enemy in enemies:
enemy.vel = 2
#bgvel = 1
elif self.y <= 600 and self.y > 400:
win.blit(EFTAL,(self.x,self.y))
for enemy in enemies:
enemy.vel = 3
#bgvel = 2
elif self.y <= 400 and self.y > 350:
win.blit(EFTAM,(self.x,self.y))
for enemy in enemies:
enemy.vel = 4
#bgvel = 3
elif self.y <= 450:
win.blit(EFTAH,(self.x,self.y))
for enemy in enemies:
enemy.vel = 5
#bgvel = 4
self.hitbox = (self.x 5,self.y 10,60,60)
#pygame.draw.rect(win,(255,0,0),self.hitbox,2)
if self.y self.height > HEIGHT:
self.y -= self.vel
if self.x < 0:
self.x = self.vel
if self.x self.width > WIDTH:
self.x -= self.vel
if self.explosions == True:
current_time = pygame.time.get_ticks()
if current_time - self.start_delay >= self.frame_delay:
self.start_delay = current_time
print("I exploded")
self.canshoot = False
self.dead = True
self.explosionc = (self.explosionc 1) % 6
if self.vel > 0: # ???
win.blit(Expl[self.explosionc],(self.x,self.y))
self.visible = False
def hit(self):
if self.health > 0:
self.health -= 1
else:
self.explosions = True
self.start_delay = 0 # or pygame.time.get_ticks()
Комментарии:
1. Что касается решения 1, я понимаю, что вы имеете в виду, но я не уверен, как бы я реализовал это «change_frame_in_animation()»
2. Вы должны получить следующий кадр и запустить его — так что, вероятно,
self.explosionc = (self.explosionc 1) % 6
иwin.blit(Expl[self.explosionc],(self.x,self.y))