pythonrecursionpygameeffectsparticles

Pygame particle effects


So I have this mini particle effect that produces circles that move up. I want to make it look like smoke. I'm having a lot of problems though.

  1. First off I want to make it recursive so that when the particle reaches the top it returns to its original spot and begins again, what I have works a little but not exactly.
  2. The other thing is I don't feel like it really looks like smoke can anyone suggest changes to make it look better?
  3. Also I want to add this into my game, how would I make this callable for my game so I could just call particle and give it a location and it appears there. Can anyone help with any of this?

My Code

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()

Solution

  • I have made some major edits to your code. For starters, I cleaned up your class a great deal. Let's start with the arguments and the __init__ function.

    First of all, instead of going down 500 to reset, particles go to the location that was set as their starting point. It's location that it starts out in is now chosen randomly in the __init__ function rather than in the game. I got rid of some of your unnecessary arguments as well.

    In the move function of your class, I simplified quite a bit. In order for the particle to detect if it should reset, it simply sees if it's above 0. The going up is just a simple decrease of the y by 1. A change I added in is that the x changes randomly and goes to the right and left. This will make the smoke look a lot better / more realistic.

    I didn't make many changes to the rest of your code. I changed your calling of the Particle class to fit the new arguments. I made a ton more particles, once again for visual effect. I also massively decreased the size of the circles drawn for (can you guess it?) visual effect. I added in a clock as well to keep the particles from going at supersonic speed.

    Here is the final code. I hope you like it.

    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()
    

    update

    In order to add particles into your code, just do what you did in the code above. It works fine. If you wanted to do something to show the smoke starting, just put a pause time into your arguments and inhibit the movement of the smoke until that amount of time has passed. New class with that added in:

    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
    

    The code you will need to create new particles:

    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 and B are variables (I reccomend around 300 for A, B will be the Y value)

    The new code will make particles spawn at the start location, and rise continously with no breaks. Hope you enjoy.