【问题标题】:Pygame particle effectsPygame 粒子效果
【发布时间】:2013-02-13 08:26:23
【问题描述】:

所以我有这个产生向上移动的圆圈的迷你粒子效果。我想让它看起来像烟雾。我有很多问题。

  1. 首先我想让它递归,这样当粒子到达顶部时 回到原来的位置并重新开始,我的工作有点但不完全。
  2. 另一件事是我不觉得它看起来真的像烟雾有没有人可以建议进行更改以使其看起来更好?
  3. 另外,我想将它添加到我的游戏中,我如何让我的游戏可以调用它,这样我就可以调用粒子并给它一个位置,它就会出现在那里。有人可以帮忙吗?

我的代码

import pygame,random
from pygame.locals import *

xmax = 1000    #width of window
ymax = 600     #height of window

class Particle():
    def __init__(self, x, y, dx, dy, col):
        self.x = x
        self.y = y
        self.col = col
        self.ry = y
        self.rx = x
        self.dx = dx
        self.dy = dy

    def move(self):
        if self.y >= 10:
            if self.dy < 0:
                self.dy = -self.dy

        self.ry -= self.dy
        self.y = int(self.ry + 0.5)

        self.dy -= .1
        if self.y < 1:
            self.y += 500

def main():
    pygame.init()
    screen = pygame.display.set_mode((xmax,ymax))
    white = (255, 255, 255)
    black = (0,0,0)
    grey = (128,128,128)

    particles = []
    for part in range(25):
        if part % 2 > 0: col = black
        else: col = grey
        particles.append( Particle(random.randint(500, 530), random.randint(0, 500), 0, 0, col))

    exitflag = False
    while not exitflag:
        for event in pygame.event.get():
            if event.type == QUIT:
                exitflag = True
            elif event.type == KEYDOWN:
                if event.key == K_ESCAPE:
                    exitflag = True

        screen.fill(white)
        for p in particles:
            p.move()
            pygame.draw.circle(screen, p.col, (p.x, p.y), 8)

        pygame.display.flip()
    pygame.quit()

if __name__ == "__main__":
    main()

【问题讨论】:

    标签: python recursion pygame effects particles


    【解决方案1】:

    我对您的代码进行了一些重大修改。首先,我清理了你的课很多。让我们从参数和__init__ 函数开始。

    首先,粒子不会下降 500 来重置,而是会转到设置为起点的位置。它开始的位置现在是在__init__ 函数中随机选择的,而不是在游戏中。我也摆脱了你的一些不必要的争论。

    在你类的move 函数中,我简化了很多。为了让粒子检测它是否应该重置,它只是查看它是否高于 0。上升只是 y 简单地减少 1。我添加的一个变化是 x 随机变化并向右移动走了。这将使烟雾看起来更好/更逼真。

    我没有对您的其余代码进行太多更改。我更改了您对 Particle 类的调用以适应新参数。我制作了更多的粒子,再次用于视觉效果。我还大大减小了为(你能猜到吗?)视觉效果绘制的圆圈的大小。我还添加了一个时钟,以防止粒子以超音速运行。

    这是最终代码。希望你喜欢。

    import pygame,random
    from pygame.locals import *
    
    xmax = 1000    #width of window
    ymax = 600     #height of window
    
    class Particle():
        def __init__(self, startx, starty, col):
            self.x = startx
            self.y = random.randint(0, starty)
            self.col = col
            self.sx = startx
            self.sy = starty
    
        def move(self):
            if self.y < 0:
                self.x=self.sx
                self.y=self.sy
    
            else:
                self.y-=1
    
            self.x+=random.randint(-2, 2)
    
    def main():
        pygame.init()
        screen = pygame.display.set_mode((xmax,ymax))
        white = (255, 255, 255)
        black = (0,0,0)
        grey = (128,128,128)
    
        clock=pygame.time.Clock()
    
        particles = []
        for part in range(300):
            if part % 2 > 0: col = black
            else: col = grey
            particles.append( Particle(515, 500, col) )
    
        exitflag = False
        while not exitflag:
            for event in pygame.event.get():
                if event.type == QUIT:
                    exitflag = True
                elif event.type == KEYDOWN:
                    if event.key == K_ESCAPE:
                        exitflag = True
    
            screen.fill(white)
            for p in particles:
                p.move()
                pygame.draw.circle(screen, p.col, (p.x, p.y), 2)
    
            pygame.display.flip()
            clock.tick(50)
        pygame.quit()
    
    if __name__ == "__main__":
        main()
    

    更新

    要将粒子添加到您的代码中,只需执行您在上面代码中所做的操作。它工作正常。如果你想做一些事情来显示烟雾开始,只需在你的论点中暂停时间并抑制烟雾的移动,直到这段时间过去。添加的新类:

    class Particle():
        def __init__(self, startx, starty, col, pause):
            self.x = startx
            self.y = starty
            self.col = col
            self.sx = startx
            self.sy = starty
            self.pause = pause
    
        def move(self):
            if self.pause==0:
                if self.y < 0:
                    self.x=self.sx
                    self.y=self.sy
    
                else:
                    self.y-=1
    
                self.x+=random.randint(-2, 2)
    
            else:
                self.pause-=1
    

    创建新粒子所需的代码:

    for part in range(1, A):
        if part % 2 > 0: col = black
        else: col = grey
        particles.append( Particle(515, B, col, round(B*part/A)) )
    

    A 和 B 是变量(我建议 A 约为 300,B 将是 Y 值)

    新代码将使粒子在起始位置产生,并不断上升而没有中断。希望你喜欢。

    【讨论】:

      【解决方案2】:

      我对您的代码进行了很多更改,尤其是在 Particle 类中。
      尽管这段代码中有一些令人费解的地方,但它会比你当前的代码更灵活。

      这里,
      我已经相当有文字地重写了你Particle类。
      除了更改 __init__ 以获取许多参数(准确地说是 7 个)之外,
      我使用三角函数和math 模块到move 粒子,使其更易于管理(如果你擅长数学!)。我还在Particle 中添加了bouncedraw 方法,并使代码更具可读性。
      就像@PygameNerd 一样,我添加了一个时钟,用于限制最大 fps。 我没有更改任何事件处理,但在for p in particles: 循环中使用了bouncedraw 函数。

      import pygame, random, math
      
      def radians(degrees):
          return degrees*math.pi/180
      
      class Particle:
          def __init__(self, (x, y), radius, speed, angle, colour, surface):
              self.x = x
              self.y = y
              self.speed = speed
              self.angle = angle
              self.radius = 3
              self.surface = surface
              self.colour = colour
              self.rect = pygame.draw.circle(surface,(255,255,0),
                                 (int(round(x,0)),
                                  int(round(y,0))),
                                 self.radius)
          def move(self):
              """ Update speed and position based on speed, angle """
              # for constant change in position values.
              self.x += math.sin(self.angle) * self.speed
              self.y -= math.cos(self.angle) * self.speed
              # pygame.rect likes int arguments for x and y
              self.rect.x = int(round(self.x))
              self.rect.y = int(round(self.y))
      
          def draw(self):
              """ Draw the particle on screen"""
              pygame.draw.circle(self.surface,self.colour,self.rect.center,self.radius)
      
          def bounce(self):
              """ Tests whether a particle has hit the boundary of the environment """
      
              if self.x > self.surface.get_width() - self.radius: # right
                  self.x = 2*(self.surface.get_width() - self.radius) - self.x
                  self.angle = - self.angle
      
              elif self.x < self.radius: # left
                  self.x = 2*self.radius - self.x
                  self.angle = - self.angle            
      
              if self.y > self.surface.get_height() - self.radius: # bottom
                  self.y = 2*(self.surface.get_height() - self.radius) - self.y
                  self.angle = math.pi - self.angle
      
              elif self.y < self.radius: # top
                  self.y = 2*self.radius - self.y
                  self.angle = math.pi - self.angle
      
      def main():
          xmax = 640    #width of window
          ymax = 480     #height of window
          white = (255, 255, 255)
          black = (0,0,0)
          grey = (128,128,128)
      
          pygame.init()
          screen = pygame.display.set_mode((xmax,ymax))
          clock = pygame.time.Clock()
      
          particles = []
      
          for i in range(1000):
              if i % 2:
                  colour = black
              else:
                  colour = grey
              # for readability
              x = random.randint(0, xmax)
              y = random.randint(0, ymax)
              speed = random.randint(0,20)*0.1
              angle = random.randint(0,360)
              radius = 3
              particles.append( Particle((x, y), radius, speed, angle, colour, screen) )
      
          done = False
          while not done:
              for event in pygame.event.get():
                  if event.type == pygame.QUIT:
                      done = True
                      break
                  elif event.type == pygame.KEYDOWN:
                      if event.key == pygame.K_ESCAPE:
                          done = True
                          break
              if done:
                  break
      
              screen.fill(white)
              for p in particles:
                  p.move()
                  p.bounce()
                  p.draw()
      
              clock.tick(40)
      
              pygame.display.flip()
          pygame.quit()
      
      if __name__ == "__main__":
          main()
      

      【讨论】:

      • 在我看来,这看起来一点也不像烟雾。它有点像一大团烟雾,但如果你把它放在一个带火的程序中,它看起来就不会真的像烟雾;它看起来就像一堆弹跳的球体。但是,您可以有自己的意见,我对此无能为力。
      • @PygameNerd 是的,我同意你的观点,这不像烟雾。但是通过在一个方向上应用重力,(更新即将到来),我可以得到一个很像你的结果。顺便问一下,我的意见是什么意思?我没有详细阅读他的问题,但感谢指出,我需要更改我的代码。
      • @PygameNerd 是的,我明白了,我完全错了,这无法解决他的问题......
      • 我只是想避免极端侮辱意见。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-04-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-03
      • 1970-01-01
      相关资源
      最近更新 更多