-
Notifications
You must be signed in to change notification settings - Fork 0
/
BallCollision3D.py
109 lines (86 loc) · 3.14 KB
/
BallCollision3D.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
import pygame
import random
import math
import numpy as np
# Initialize Pygame
pygame.init()
# Screen dimensions
WIDTH, HEIGHT = 800, 600
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption('3D Balls Collision Simulation')
# Colors
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
# Ball properties
NUM_BALLS = 10
RADIUS = 20
SPEED = 5
DEPTH = 500
class Ball:
def __init__(self, x, y, z, vx, vy, vz, color):
self.position = np.array([x, y, z], dtype='float64')
self.velocity = np.array([vx, vy, vz], dtype='float64')
self.color = color
def move(self):
self.position += self.velocity
# Bounce off the walls
if self.position[0] - RADIUS < 0 or self.position[0] + RADIUS > WIDTH:
self.velocity[0] = -self.velocity[0]
if self.position[1] - RADIUS < 0 or self.position[1] + RADIUS > HEIGHT:
self.velocity[1] = -self.velocity[1]
if self.position[2] - RADIUS < -DEPTH or self.position[2] + RADIUS > DEPTH:
self.velocity[2] = -self.velocity[2]
def draw(self):
# Simple perspective projection
f = WIDTH / (WIDTH + self.position[2])
x_2d = int(self.position[0] * f)
y_2d = int(self.position[1] * f)
pygame.draw.circle(screen, self.color, (x_2d, y_2d), int(RADIUS * f))
def check_collision(self, other):
delta_pos = other.position - self.position
distance = np.linalg.norm(delta_pos)
if distance < 2 * RADIUS:
# Elastic collision response
norm_delta_pos = delta_pos / distance
relative_velocity = self.velocity - other.velocity
velocity_along_normal = np.dot(relative_velocity, norm_delta_pos)
if velocity_along_normal > 0:
return
restitution = 1 # Elastic collision
impulse_magnitude = (-(1 + restitution) * velocity_along_normal) / 2
impulse = impulse_magnitude * norm_delta_pos
self.velocity += impulse
other.velocity -= impulse
def create_balls(num_balls):
balls = []
for _ in range(num_balls):
x = random.randint(RADIUS, WIDTH - RADIUS)
y = random.randint(RADIUS, HEIGHT - RADIUS)
z = random.randint(-DEPTH + RADIUS, DEPTH - RADIUS)
vx = random.uniform(-SPEED, SPEED)
vy = random.uniform(-SPEED, SPEED)
vz = random.uniform(-SPEED, SPEED)
color = (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))
balls.append(Ball(x, y, z, vx, vy, vz, color))
return balls
def main():
clock = pygame.time.Clock()
balls = create_balls(NUM_BALLS)
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
screen.fill(BLACK)
for ball in balls:
ball.move()
ball.draw()
# Check for collisions
for i in range(len(balls)):
for j in range(i + 1, len(balls)):
balls[i].check_collision(balls[j])
pygame.display.flip()
clock.tick(60)
pygame.quit()
if __name__ == '__main__':
main()