pygame 粒子:从列表中删除问题
pygame particle: issues removing from list
我有粒子和爆炸类我正在使用pygame绘图。
爆炸代表一堆飞行的粒子。
一个粒子最终会消失;当它的 ttl 属性 变为 0 时,它应该不可见并且应该从 Explosion.particles 中删除。
我想让程序删除死粒子,这样它们就不会更新。
我遇到的问题是 Explosion.update()
方法。它似乎没有删除任何粒子。我遇到了一个错误,据说 'dead' 粒子仍然被绘制,但它们的运动没有更新。
我在 python 中的列表上进行了试验,并验证了迭代 [= =32=] 从其他列表中删除的列表有效。
任何关于此代码中错误所在的建议将不胜感激。
编辑:为了更好的上下文,我附上并缩短了两个源文件。
explosion.py
import sys
import pygame
from particleac import *
class App:
def __init__(self):
pygame.init()
self.screen = pygame.display.set_mode(SCREEN_SIZE, pygame.HWSURFACE|pygame.DOUBLEBUF)
self.clock = pygame.time.Clock()
self.running = True
self.explosions = []
self.frame_no = 0
def check_input(self):
for event in pygame.event.get():
if event.type == pygame.QUIT:
self.running = False
if event.type == pygame.MOUSEBUTTONDOWN or event.type == pygame.MOUSEMOTION:
x, y = pygame.mouse.get_pos()
self.explosions.append(Explosion(x, y))
def update_screen(self):
self.screen.fill(BLACK)
dead_explosions = []
# remove explosion if particles all gone
for e in self.explosions:
if len(e.particles) == 0:
dead_explosions.append(e)
else:
for p in e.particles:
pygame.draw.circle(self.screen, p.colour, [p.x, p.y], p.size)
p.update()
for e in dead_explosions:
self.explosions.remove(e)
pygame.display.flip()
self.frame_no += 1
self.frame_no %= 60
self.clock.tick(FRAMERATE)
def run(self):
while self.running:
self.check_input()
self.update_screen()
pygame.quit()
app = App()
app.run()
particleac.py
import random
import sys
BLACK = [ 0, 0, 0]
WHITE = [255, 255, 255]
BLUE = [0, 0, 255]
SCREEN_WIDTH = 600
SCREEN_HEIGHT = 400
SCREEN_CENTRE = [SCREEN_WIDTH/2, SCREEN_HEIGHT/2]
FRAMERATE = 40
SCREEN_SIZE = [SCREEN_WIDTH, SCREEN_HEIGHT]
GRAVITY = 1
TERMINAL_VELOCITY = 10
class Particle:
def __init__(self, x=SCREEN_CENTRE[0], y=SCREEN_CENTRE[1], colour=WHITE):
self.x = x
self.y = y
self.colour = colour
self.brightness = 255
self.size = 2
self.x_velocity = random.randrange(-4, 4)
self.y_velocity = random.randrange(-8, 3)
self.ttl = random.randrange(50, 200)
self.decay = (self.ttl / FRAMERATE) * 2
def update(self):
if self.ttl > 0:
self.ttl -= 1
self.brightness -= self.decay
if self.brightness < 0:
self.brightness = 0
self.colour[0] = self.colour[1] = self.colour[2] = self.brightness
self.y_velocity += GRAVITY
self.y += self.y_velocity
self.x += self.x_velocity
if self.y > SCREEN_HEIGHT:
self.y -= SCREEN_HEIGHT
class Explosion:
MAX_NUM_PARTICLES = 2
def __init__(self, x=0, y=0, colour=WHITE):
self.x = x
self.y = y
self.colour = colour
self.x_velocity = random.randrange(-4, 4)
self.y_velocity = random.randrange(-6, -1)
self.num_particles = random.randrange(1, self.MAX_NUM_PARTICLES)
self.particles = []
for i in range(self.MAX_NUM_PARTICLES):
p = Particle(self.x, self.y)
p.colour = self.colour
p.x_velocity += self.x_velocity
p.y_velocity += self.y_velocity
self.particles.append(p)
def update(self):
for p in self.particles:
p.update()
self.particles = [p for p in self.particles if p.ttl > 0]
sys.stdout.write("len(self.particles) == {}".format(len(self.particles)))
sys.stdout.flush()
问题可能 是因为self.particles
是在class 级别定义的。这可能会导致您的代码中其他地方出现一些问题,因为您创建了 Explosion
class 的多个实例。尝试在构造函数中移动 self.particle
,看看会发生什么。
(作为建议)既然你建立了一个列表,为什么不复制那些还活着的呢?
def update(self):
particles_alive = []
for p in self.particles:
p.update()
sys.out.write("p.ttl == {}\n".format(p.ttl))
if p.ttl == 0:
sys.out.write("Particle died.\n")
else:
particles_alive.append(p)
self.particles = particles_alive
一旦 sys.out.write()
更改为 sys.stdout.write()
,您的代码对我有用。由于您的代码中存在该错误,您确定 post 中的代码与失败的代码相同吗?
您可以将 Explosion.update()
简化为:
def update(self):
for p in self.particles:
p.update()
self.particles = [p for p in self.particles if p.ttl > 0]
这个更改可能会解决问题,因为您现在只处理一个列表,但我相信您的代码应该可以工作。
解决方案:我从来没有调用 e.update()
!
因此爆炸在遍历它们时没有更新,这意味着死粒子没有被删除。 Aaargh!
我将 e.update()
添加到 app.update_screen()
并删除了不正确的 p.update()
(为 e.update()
中的每个粒子调用)。
def update_screen(self):
self.screen.fill(BLACK)
dead_explosions = []
for e in self.explosions:
if len(e.particles) == 0:
dead_explosions.append(e)
else:
e.update()
for p in e.particles:
pygame.draw.circle(self.screen, p.colour, [p.x, p.y], p.size)
for e in dead_explosions:
self.explosions.remove(e)
pygame.display.flip()
self.clock.tick(FRAMERATE)
我现在知道在发布代码时提供更好的上下文。谢谢各位麻烦!
我有粒子和爆炸类我正在使用pygame绘图。
爆炸代表一堆飞行的粒子。
一个粒子最终会消失;当它的 ttl 属性 变为 0 时,它应该不可见并且应该从 Explosion.particles 中删除。
我想让程序删除死粒子,这样它们就不会更新。
我遇到的问题是 Explosion.update()
方法。它似乎没有删除任何粒子。我遇到了一个错误,据说 'dead' 粒子仍然被绘制,但它们的运动没有更新。
我在 python 中的列表上进行了试验,并验证了迭代 [= =32=] 从其他列表中删除的列表有效。
任何关于此代码中错误所在的建议将不胜感激。
编辑:为了更好的上下文,我附上并缩短了两个源文件。
explosion.py
import sys
import pygame
from particleac import *
class App:
def __init__(self):
pygame.init()
self.screen = pygame.display.set_mode(SCREEN_SIZE, pygame.HWSURFACE|pygame.DOUBLEBUF)
self.clock = pygame.time.Clock()
self.running = True
self.explosions = []
self.frame_no = 0
def check_input(self):
for event in pygame.event.get():
if event.type == pygame.QUIT:
self.running = False
if event.type == pygame.MOUSEBUTTONDOWN or event.type == pygame.MOUSEMOTION:
x, y = pygame.mouse.get_pos()
self.explosions.append(Explosion(x, y))
def update_screen(self):
self.screen.fill(BLACK)
dead_explosions = []
# remove explosion if particles all gone
for e in self.explosions:
if len(e.particles) == 0:
dead_explosions.append(e)
else:
for p in e.particles:
pygame.draw.circle(self.screen, p.colour, [p.x, p.y], p.size)
p.update()
for e in dead_explosions:
self.explosions.remove(e)
pygame.display.flip()
self.frame_no += 1
self.frame_no %= 60
self.clock.tick(FRAMERATE)
def run(self):
while self.running:
self.check_input()
self.update_screen()
pygame.quit()
app = App()
app.run()
particleac.py
import random
import sys
BLACK = [ 0, 0, 0]
WHITE = [255, 255, 255]
BLUE = [0, 0, 255]
SCREEN_WIDTH = 600
SCREEN_HEIGHT = 400
SCREEN_CENTRE = [SCREEN_WIDTH/2, SCREEN_HEIGHT/2]
FRAMERATE = 40
SCREEN_SIZE = [SCREEN_WIDTH, SCREEN_HEIGHT]
GRAVITY = 1
TERMINAL_VELOCITY = 10
class Particle:
def __init__(self, x=SCREEN_CENTRE[0], y=SCREEN_CENTRE[1], colour=WHITE):
self.x = x
self.y = y
self.colour = colour
self.brightness = 255
self.size = 2
self.x_velocity = random.randrange(-4, 4)
self.y_velocity = random.randrange(-8, 3)
self.ttl = random.randrange(50, 200)
self.decay = (self.ttl / FRAMERATE) * 2
def update(self):
if self.ttl > 0:
self.ttl -= 1
self.brightness -= self.decay
if self.brightness < 0:
self.brightness = 0
self.colour[0] = self.colour[1] = self.colour[2] = self.brightness
self.y_velocity += GRAVITY
self.y += self.y_velocity
self.x += self.x_velocity
if self.y > SCREEN_HEIGHT:
self.y -= SCREEN_HEIGHT
class Explosion:
MAX_NUM_PARTICLES = 2
def __init__(self, x=0, y=0, colour=WHITE):
self.x = x
self.y = y
self.colour = colour
self.x_velocity = random.randrange(-4, 4)
self.y_velocity = random.randrange(-6, -1)
self.num_particles = random.randrange(1, self.MAX_NUM_PARTICLES)
self.particles = []
for i in range(self.MAX_NUM_PARTICLES):
p = Particle(self.x, self.y)
p.colour = self.colour
p.x_velocity += self.x_velocity
p.y_velocity += self.y_velocity
self.particles.append(p)
def update(self):
for p in self.particles:
p.update()
self.particles = [p for p in self.particles if p.ttl > 0]
sys.stdout.write("len(self.particles) == {}".format(len(self.particles)))
sys.stdout.flush()
问题可能 是因为self.particles
是在class 级别定义的。这可能会导致您的代码中其他地方出现一些问题,因为您创建了 Explosion
class 的多个实例。尝试在构造函数中移动 self.particle
,看看会发生什么。
(作为建议)既然你建立了一个列表,为什么不复制那些还活着的呢?
def update(self):
particles_alive = []
for p in self.particles:
p.update()
sys.out.write("p.ttl == {}\n".format(p.ttl))
if p.ttl == 0:
sys.out.write("Particle died.\n")
else:
particles_alive.append(p)
self.particles = particles_alive
一旦 sys.out.write()
更改为 sys.stdout.write()
,您的代码对我有用。由于您的代码中存在该错误,您确定 post 中的代码与失败的代码相同吗?
您可以将 Explosion.update()
简化为:
def update(self):
for p in self.particles:
p.update()
self.particles = [p for p in self.particles if p.ttl > 0]
这个更改可能会解决问题,因为您现在只处理一个列表,但我相信您的代码应该可以工作。
解决方案:我从来没有调用 e.update()
!
因此爆炸在遍历它们时没有更新,这意味着死粒子没有被删除。 Aaargh!
我将 e.update()
添加到 app.update_screen()
并删除了不正确的 p.update()
(为 e.update()
中的每个粒子调用)。
def update_screen(self):
self.screen.fill(BLACK)
dead_explosions = []
for e in self.explosions:
if len(e.particles) == 0:
dead_explosions.append(e)
else:
e.update()
for p in e.particles:
pygame.draw.circle(self.screen, p.colour, [p.x, p.y], p.size)
for e in dead_explosions:
self.explosions.remove(e)
pygame.display.flip()
self.clock.tick(FRAMERATE)
我现在知道在发布代码时提供更好的上下文。谢谢各位麻烦!