Skip to content

Commit 465f6bd

Browse files
some new ideas...
1 parent fc1ff0c commit 465f6bd

File tree

1 file changed

+134
-0
lines changed

1 file changed

+134
-0
lines changed

src/1000 bouncy balls.py

+134
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
import pygame
2+
import pmma
3+
import random
4+
import math
5+
import time
6+
7+
pygame.init()
8+
pmma.init()
9+
10+
display = pygame.display.set_mode((1920, 1080), pygame.FULLSCREEN)
11+
clock = pygame.time.Clock()
12+
13+
GRAVITY = 0.5 # Acceleration due to gravity
14+
FRICTION = 0.9 # Energy retention on wall bounces
15+
EXPLOSION_SPEED = 15 # Speed of explosion
16+
17+
class BouncyBall:
18+
def __init__(self, x, y, angle):
19+
self.x = x
20+
self.y = y
21+
self.radius = 10
22+
self.vx = math.cos(angle) * EXPLOSION_SPEED # Velocity in x direction
23+
self.vy = math.sin(angle) * EXPLOSION_SPEED # Velocity in y direction
24+
color = pmma.ColorConverter()
25+
self.color = color.generate_color_from_perlin_noise()
26+
self.start_time = time.perf_counter()
27+
28+
def render(self):
29+
pygame.draw.circle(display, self.color, (int(self.x), int(self.y)), self.radius)
30+
31+
def compute(self, balls):
32+
# Apply gravity
33+
self.vy += GRAVITY
34+
35+
# Update position
36+
self.x += self.vx
37+
self.y += self.vy
38+
39+
# Wall collisions
40+
if self.x - self.radius < 0: # Left wall
41+
self.x = self.radius
42+
self.vx = -self.vx * FRICTION
43+
elif self.x + self.radius > display.get_width(): # Right wall
44+
self.x = display.get_width() - self.radius
45+
self.vx = -self.vx * FRICTION
46+
47+
if self.y - self.radius < 0: # Ceiling
48+
self.y = self.radius
49+
self.vy = -self.vy * FRICTION
50+
elif self.y + self.radius > display.get_height(): # Floor
51+
self.y = display.get_height() - self.radius
52+
self.vy = -self.vy * FRICTION
53+
54+
if (time.perf_counter() - self.start_time) < 1:
55+
return False
56+
# Check collisions with other balls
57+
for other in balls:
58+
if other is not self:
59+
self.check_collision(other)
60+
61+
if abs(self.vy) < 0.237 and int(self.y) == display.get_height() - self.radius:
62+
return True
63+
return False
64+
65+
def check_collision(self, other):
66+
# Vector between ball centers
67+
dx = self.x - other.x
68+
dy = self.y - other.y
69+
distance = math.sqrt(dx**2 + dy**2)
70+
71+
# Check if balls are overlapping
72+
if distance < self.radius + other.radius:
73+
# Resolve collision
74+
angle = math.atan2(dy, dx)
75+
76+
# Velocity components along the collision axis
77+
self_vx = self.vx * math.cos(angle) + self.vy * math.sin(angle)
78+
other_vx = other.vx * math.cos(angle) + other.vy * math.sin(angle)
79+
80+
# Exchange velocities
81+
self.vx, other.vx = (
82+
other_vx * math.cos(angle) - self_vx * math.sin(angle),
83+
self_vx * math.cos(angle) - other_vx * math.sin(angle),
84+
)
85+
86+
# Resolve overlap
87+
overlap = (self.radius + other.radius - distance) / 2
88+
self.x += overlap * math.cos(angle)
89+
self.y += overlap * math.sin(angle)
90+
other.x -= overlap * math.cos(angle)
91+
other.y -= overlap * math.sin(angle)
92+
93+
94+
def create_explosion(center_x, center_y, num_balls):
95+
"""Create balls exploding outward from the center."""
96+
balls = []
97+
for i in range(num_balls):
98+
angle = i * (2 * math.pi / num_balls) # Evenly spaced angles
99+
balls.append(BouncyBall(center_x, center_y, angle))
100+
return balls
101+
102+
103+
# Initialize explosion
104+
number_of_balls = random.randint(10, 120)
105+
balls = create_explosion(display.get_width() / 2, display.get_height() / 2, number_of_balls)
106+
107+
surface = pygame.Surface((display.get_width(), display.get_height()))
108+
# Main loop
109+
while True:
110+
for event in pygame.event.get():
111+
if event.type == pygame.QUIT:
112+
pygame.quit()
113+
quit()
114+
115+
surface.blit(display, (0, 0))
116+
display.fill([0, 0, 0]) # Clear screen
117+
surface.set_alpha(200)
118+
display.blit(surface, (0, 0))
119+
120+
index = 0
121+
while index < len(balls):
122+
ball = balls[index]
123+
if ball.compute(balls):
124+
balls.remove(ball)
125+
else:
126+
ball.render()
127+
index += 1
128+
129+
if len(balls) == 0:
130+
number_of_balls = random.randint(10, 120)
131+
balls = create_explosion(display.get_width() / 2, display.get_height() / 2, number_of_balls)
132+
133+
pygame.display.flip()
134+
clock.tick(60)

0 commit comments

Comments
 (0)