Josh Brown
Josh Brown

Reputation: 67

Unexpected particle simulation behavior

Working on a basic particle simulator where rules can be applied to groups of particles (eg. reds attract blues, blues repel yellows, etc). Using this video as a guide, I created a simple python application that works, but the particles don't behave as expected. The below code is an example where the blue particle starts attracted to the red particle but instead of oscillating, the blue particle bounces off the red particle and becomes chaotic.

import pygame
import random

class Particle():
    def __init__(self, x, y, mass, color):
        self.x = x
        self.y = y
        self.xvel = 0
        self.yvel = 0
        self.mass = mass
        self.color = color

def main():
    random.seed(1662443792)

    # initialize screen
    pygame.init()
    width = 1000
    height = 800
    screen = pygame.display.set_mode((width, height))
    clock = pygame.time.Clock()
    running = True

    # spawn some particles
    blue = []
    for i in range(1):
        x = random.randint(0, width)
        y = random.randint(0, height)
        p = Particle(x, y, 1, (0, 0, 255))
        blue.append(p)
    red = []
    for i in range(1):
        x = random.randint(0, width)
        y = random.randint(0, height)
        p = Particle(x, y, 10, (255, 0, 0))
        red.append(p)

    while running:
        pygame.display.flip()
        screen.fill((0, 0, 0))
        draw_particles(screen, blue)
        draw_particles(screen, red)
        rule(blue, red, -1)
        clock.tick(144)

        # quit simulation
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                return
            elif event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
                pygame.quit()

# PHYSICS FOR PARTICLES DONE HERE               
def rule(set1, set2, g):
    for a in set1:
        fx = 0
        fy = 0
        for b in set2:
            # calculate distance between particles
            dx = a.x - b.x
            dy = a.y - b.y
            d = (dx * dx + dy * dy) ** .5
            if (d > 0):
                # calculate force between particles
                force = (g * a.mass * b.mass) / (d*d)
                fx += force * dx
                fy += force * dy
        # update force and position
        a.xvel = (a.xvel + fx)
        a.yvel =  (a.yvel + fy)
        a.x += a.xvel
        a.y += a.yvel
        # if particle wants to leave screen, flip velocity
        if (a.x >= 1000 or a.x <= 0):
            a.xvel *= -1
        if (a.y >= 800 or a.y <= 0):
            a.yvel *= -1

def draw_particles(screen, particle_set1):
    for p in particle_set1:
        pygame.draw.circle(screen, p.color, (p.x, p.y), 5, 2)

if __name__ == '__main__':
    main()

Upvotes: 0

Views: 186

Answers (1)

Limtorak
Limtorak

Reputation: 81

I believe your estimation of the force is ill-posed. You multiply it by dx, I guess to get the "direction" of the force, but then you should divide by d.

Also, regarding your velocity and position updates, I think you over-estimate variations of both, instead of a.xvel += fx I would have expected a.xvel += fx*dt, with dt your integration step, here 0.144s I guess.

Upvotes: 1

Related Questions