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