]> Skullheadx's Git Forge - Collision-Simulation.git/commitdiff
particle collisions #1
authorSkullheadx <admonty1@gmail.com>
Thu, 26 Jan 2023 20:50:12 +0000 (15:50 -0500)
committerSkullheadx <admonty1@gmail.com>
Thu, 26 Jan 2023 20:50:12 +0000 (15:50 -0500)
box.py
collision.py
display.py
particle.py

diff --git a/box.py b/box.py
index 2e146309cd89b2f76a6914f66b4948dace7dd8c4..d43b2bbed2a9a8735acc9b43db248b1cb32d818c 100644 (file)
--- a/box.py
+++ b/box.py
@@ -20,4 +20,4 @@ class Box:
         pass
 
     def draw(self, surf):
-        pygame.draw.rect(surf, BLACK, pygame.Rect(self.left, self.top, self.width, self.height), self.line_thickness)
+        pygame.draw.rect(surf, GRAY, pygame.Rect(self.left, self.top, self.width, self.height), self.line_thickness)
index 492a576979e0d4c0b439ebd3a5b51388d5c0d7e0..d35547a08be7a86f0360a9b23a96418b2eddd353 100644 (file)
@@ -1,4 +1,5 @@
 from pygame import Vector2
+from itertools import combinations
 
 
 def handleBoxCollision(particle, box):  # Discrete Collision Detection
@@ -36,3 +37,50 @@ def handleParticleCollision(particle1, particle2):  # https://www.vobarian.com/c
 
         particle1.velocity = v1_prime
         particle2.velocity = v2_prime
+
+
+def sweepAndPrune(particle_list):
+    particles = particle_list.copy()
+
+    particles.sort(key=lambda x: x.position.x)
+    x_checks = []
+    active = [particles[0]]
+    for particle in particles:
+        if particle == active[0]:
+            continue
+
+        start_x = active[-1].position.x - active[-1].radius
+        end_x = active[-1].position.x + active[-1].radius
+        if (start_x <= particle.position.x - particle.radius <= end_x or
+                start_x <= particle.position.x <= end_x or
+                start_x <= particle.position.x + particle.radius <= end_x):
+            active.append(particle)
+        if len(active) > 1:
+            x_checks.extend(tuple(combinations(active, 2)))
+        active = [particle]
+
+    particles.sort(key=lambda x: x.position.y)
+    y_checks = []
+    active = [particles[0]]
+    for particle in particles:
+        if particle == active[0]:
+            continue
+        start_y = active[-1].position.y - active[-1].radius
+        end_y = active[-1].position.y + active[-1].radius
+        if (start_y <= particle.position.y - particle.radius <= end_y or
+                start_y <= particle.position.y <= end_y or
+                start_y <= particle.position.y + particle.radius <= end_y):
+            active.append(particle)
+        if len(active) > 1:
+            y_checks.extend(tuple(combinations(active, 2)))
+        active = [particle]
+
+    return remove_duplicates(x_checks, y_checks)
+
+
+def intersection(arr1, arr2):
+    return [value for value in arr1 if value in set(arr2)]
+
+
+def remove_duplicates(arr1, arr2):
+    return list(set(arr1 + arr2))
index 4aed9b9012d6b3ef1de8f74ce11a6aa6e6d43a28..cf30ebf14ff41618ae84b0fd571e2a1cd97a468e 100644 (file)
@@ -4,6 +4,7 @@ import random
 from box import Box
 from colours import *
 from particle import Particle
+from collision import sweepAndPrune, handleParticleCollision
 
 pygame.init()
 
@@ -24,20 +25,25 @@ class Display:
         self.collision_objects = {layer: [] for layer in range(self.COLLISION_LAYERS)}
         self.particles = []
 
-        n = 5
-        for i in range(1, n):
-            for j in range(1, n):
-                m = random.randint(35, 45)
+        rows = 10
+        cols = 10
+
+        w, h = self.WIDTH / cols, self.HEIGHT / rows
+
+        for i in range(1, 1 + cols):
+            for j in range(1, 1 + rows):
+                r = random.randint(10, 30)
                 speed = 0.1
-                self.particles.append(Particle((self.WIDTH / n * i, self.HEIGHT / n * j),
+                self.particles.append(Particle((w * i - w / 2, h * j - h / 2),
                                                ((random.random() - 0.5) * speed, (random.random() - 0.5) * speed),
-                                               (0, 0), m, 100, self.collision_objects[0]))
+                                               (0, 0), r, r ** 2 * 3.14, self.collision_objects[0]))
 
         self.box = Box((0, 0), self.WIDTH, self.HEIGHT)
 
-        self.collision_objects[0] += self.particles
         self.collision_objects[0].append(self.box)
 
+        self.collided_last_frame = set()
+
     def show(self):
         screen = pygame.display.set_mode(self.DIMENSIONS)
         clock = pygame.time.Clock()
@@ -46,9 +52,9 @@ class Display:
         while self.is_running:
             self.update(delta)
             self.draw(screen)
-            pygame.display.flip()
-            delta = clock.tick(self.FPS)
-            print(delta)
+            pygame.display.update()
+            delta = clock.tick()
+            print(delta)
         pygame.quit()
 
     def update(self, delta):
@@ -61,10 +67,26 @@ class Display:
         for particle in self.particles:
             particle.update(delta)
 
+        for particle1, particle2 in sweepAndPrune(self.particles):
+            if (particle1, particle2) not in self.collided_last_frame and (
+            particle2, particle1) not in self.collided_last_frame:
+                handleParticleCollision(particle1, particle2)
+
+                self.collided_last_frame.add((particle1, particle2))
+                self.collided_last_frame.add((particle2, particle1))
+
+            if particle1.position.distance_to(particle2.position) > particle1.radius + particle2.radius and \
+                    particle1 != particle2:
+                self.collided_last_frame.remove((particle1, particle2))
+                self.collided_last_frame.remove((particle2, particle1))
+
     def draw(self, surf):
-        surf.fill(WHITE)
+        surf.fill(BLACK)
 
         self.box.draw(surf)
 
         for particle in self.particles:
             particle.draw(surf)
+
+        for p1, p2 in sweepAndPrune(self.particles):
+            pygame.draw.line(surf, GREEN, p1.position, p2.position, 3)
index 45961cc94a0dd47c38d330570c05202d3775232a..8cb73902a3570ae81a550940494225fefe821ef5 100644 (file)
@@ -24,6 +24,9 @@ class Particle:
 
         self.collision_layer = collision_layer
 
+        self.colour = RED
+
+
     def get_next_frame(self, position, velocity, delta):
         vel = pygame.Vector2()
         pos = pygame.Vector2()
@@ -46,11 +49,7 @@ class Particle:
         self.top = self.position.y - self.radius
         self.bottom = self.position.y + self.radius
 
-        for thing in self.collision_layer:
-            if isinstance(thing, Box):
-                handleBoxCollision(self, thing)
-            elif isinstance(thing, Particle):
-                handleParticleCollision(self, thing)
+        handleBoxCollision(self, self.collision_layer[0])
 
     def draw(self, surf):
-        pygame.draw.circle(surf, RED, self.position, self.radius)
+        pygame.draw.circle(surf, self.colour, self.position, self.radius)