Create main.py
This commit is contained in:
parent
aa4e288c3d
commit
b407560bde
218
only-particles-game/main.py
Normal file
218
only-particles-game/main.py
Normal file
@ -0,0 +1,218 @@
|
||||
import pygame
|
||||
import math
|
||||
import random
|
||||
|
||||
# Initialize pygame
|
||||
pygame.init()
|
||||
|
||||
# Screen dimensions
|
||||
WIDTH, HEIGHT = 800, 600
|
||||
SCREEN = pygame.display.set_mode((WIDTH, HEIGHT))
|
||||
pygame.display.set_caption("Neon Breaker with Particles")
|
||||
|
||||
# Colors (RGB)
|
||||
BLACK = (0, 0, 0)
|
||||
NEON_BLUE = (50, 255, 255)
|
||||
NEON_PINK = (255, 50, 255)
|
||||
NEON_GREEN = (50, 255, 50)
|
||||
|
||||
money = 0
|
||||
|
||||
# Helper function to draw a neon glow circle using multiple layers
|
||||
def draw_neon_circle(surface, color, center, radius, glow_layers=10):
|
||||
for i in range(glow_layers, 0, -1):
|
||||
# Calculate alpha for the glow (decreases with each layer)
|
||||
alpha = max(10, int(255 * (i / glow_layers) * 0.5))
|
||||
glow_color = (*color, alpha)
|
||||
glow_radius = radius + i
|
||||
temp_surface = pygame.Surface((glow_radius * 2, glow_radius * 2), pygame.SRCALPHA)
|
||||
pygame.draw.circle(temp_surface, glow_color, (glow_radius, glow_radius), glow_radius)
|
||||
surface.blit(temp_surface, (center[0] - glow_radius, center[1] - glow_radius))
|
||||
pygame.draw.circle(surface, color, center, radius)
|
||||
|
||||
# Helper function to draw a neon glow rectangle
|
||||
def draw_neon_rect(surface, color, rect, glow_layers=8):
|
||||
for i in range(glow_layers, 0, -1):
|
||||
alpha = max(10, int(255 * (i / glow_layers) * 0.5))
|
||||
glow_color = (*color, alpha)
|
||||
temp_rect = rect.inflate(i * 2, i * 2)
|
||||
temp_surface = pygame.Surface((temp_rect.width, temp_rect.height), pygame.SRCALPHA)
|
||||
pygame.draw.rect(temp_surface, glow_color, (0, 0, temp_rect.width, temp_rect.height), border_radius=4)
|
||||
surface.blit(temp_surface, temp_rect.topleft)
|
||||
pygame.draw.rect(surface, color, rect, border_radius=4)
|
||||
|
||||
# Particle class: updated using dt, with fading effect
|
||||
class Particle:
|
||||
def __init__(self, x, y, angle, speed, lifetime, color, size):
|
||||
self.x = x
|
||||
self.y = y
|
||||
self.angle = angle # in radians
|
||||
self.speed = speed # pixels per second
|
||||
self.lifetime = lifetime # seconds
|
||||
self.color = color
|
||||
self.size = size # initial size
|
||||
|
||||
def update(self, dt):
|
||||
# Move particle using dt
|
||||
self.x += math.cos(self.angle) * self.speed * dt
|
||||
self.y += math.sin(self.angle) * self.speed * dt
|
||||
self.lifetime -= dt
|
||||
|
||||
def draw(self, surface):
|
||||
if self.lifetime > 0:
|
||||
# Compute fade effect: size and brightness fade with remaining lifetime
|
||||
fade = max(0, self.lifetime)
|
||||
current_size = max(1, int(self.size * (fade)))
|
||||
# Draw with the neon glow effect.
|
||||
draw_neon_circle(surface, self.color, (int(self.x), int(self.y)), current_size, glow_layers=4)
|
||||
|
||||
# Particle system to manage all particles
|
||||
class ParticleSystem:
|
||||
def __init__(self):
|
||||
self.particles = []
|
||||
|
||||
def add_explosion(self, x, y, count, base_speed, lifetime, color, size):
|
||||
for _ in range(count):
|
||||
angle = random.uniform(0, 2 * math.pi)
|
||||
speed = random.uniform(0.5 * base_speed, base_speed)
|
||||
# lifetime is given in seconds; each particle will have a slightly variable lifetime
|
||||
part_lifetime = random.uniform(0.5 * lifetime, lifetime)
|
||||
self.particles.append(Particle(x, y, angle, speed, part_lifetime, color, size))
|
||||
|
||||
def update(self, dt):
|
||||
for p in self.particles:
|
||||
p.update(dt)
|
||||
# Remove dead particles
|
||||
self.particles = [p for p in self.particles if p.lifetime > 0]
|
||||
|
||||
def draw(self, surface):
|
||||
for p in self.particles:
|
||||
p.draw(surface)
|
||||
|
||||
# Ball class: uses dt in its movement and adds a neon glow.
|
||||
class Ball:
|
||||
def __init__(self, x, y, radius=10, color=NEON_BLUE):
|
||||
self.x = x
|
||||
self.y = y
|
||||
self.radius = radius
|
||||
self.color = color
|
||||
self.vx = random.choice([-200, 200]) # pixels per second
|
||||
self.vy = random.choice([-200, 200]) # pixels per second
|
||||
|
||||
def update(self, dt):
|
||||
self.x += self.vx * dt
|
||||
self.y += self.vy * dt
|
||||
|
||||
# Bounce off the walls
|
||||
if self.x - self.radius <= 0 or self.x + self.radius >= WIDTH:
|
||||
self.vx *= -1
|
||||
self.x = max(self.radius, min(WIDTH - self.radius, self.x))
|
||||
if self.y - self.radius <= 0 or self.y + self.radius >= HEIGHT:
|
||||
self.vy *= -1
|
||||
self.y = max(self.radius, min(HEIGHT - self.radius, self.y))
|
||||
|
||||
def draw(self, surface):
|
||||
draw_neon_circle(surface, self.color, (int(self.x), int(self.y)), self.radius)
|
||||
|
||||
def get_rect(self):
|
||||
return pygame.Rect(self.x - self.radius, self.y - self.radius,
|
||||
self.radius * 2, self.radius * 2)
|
||||
|
||||
# Block class with dt-independent health and neon visuals.
|
||||
class Block:
|
||||
def __init__(self, x, y, width=80, height=30, health=3, color=NEON_PINK):
|
||||
self.rect = pygame.Rect(x, y, width, height)
|
||||
self.max_health = health
|
||||
self.health = health
|
||||
self.color = color
|
||||
|
||||
def draw(self, surface):
|
||||
intensity = self.health / self.max_health
|
||||
mod_color = (int(self.color[0] * intensity),
|
||||
int(self.color[1] * intensity),
|
||||
int(self.color[2] * intensity))
|
||||
draw_neon_rect(surface, mod_color, self.rect)
|
||||
|
||||
def hit(self, damage):
|
||||
self.health -= damage
|
||||
if self.health < 0:
|
||||
self.health = 0
|
||||
|
||||
def is_destroyed(self):
|
||||
return self.health <= 0
|
||||
|
||||
def main():
|
||||
global money
|
||||
clock = pygame.time.Clock()
|
||||
particle_system = ParticleSystem()
|
||||
running = True
|
||||
|
||||
# Create a neon ball at the center.
|
||||
ball = Ball(WIDTH // 2, HEIGHT // 2)
|
||||
|
||||
# Create blocks in a grid layout.
|
||||
blocks = []
|
||||
rows, cols = 3, 7
|
||||
padding = 10
|
||||
block_width = (WIDTH - (cols + 1) * padding) // cols
|
||||
block_height = 30
|
||||
for row in range(rows):
|
||||
for col in range(cols):
|
||||
x = padding + col * (block_width + padding)
|
||||
y = padding + row * (block_height + padding)
|
||||
blocks.append(Block(x, y, block_width, block_height, health=3, color=NEON_PINK))
|
||||
|
||||
font = pygame.font.SysFont("Arial", 24)
|
||||
|
||||
while running:
|
||||
# Calculate delta time in seconds.
|
||||
dt = clock.tick() / 1000.0
|
||||
|
||||
for event in pygame.event.get():
|
||||
if event.type == pygame.QUIT:
|
||||
running = False
|
||||
|
||||
# Update game objects using dt.
|
||||
ball.update(dt)
|
||||
particle_system.update(dt)
|
||||
|
||||
# Collision check between ball and blocks.
|
||||
ball_rect = ball.get_rect()
|
||||
for block in blocks[:]:
|
||||
if ball_rect.colliderect(block.rect):
|
||||
# Reflect the ball vertically.
|
||||
ball.vy *= -1
|
||||
|
||||
# Add particle explosion at collision point.
|
||||
collision_x = ball.x
|
||||
collision_y = ball.y
|
||||
particle_system.add_explosion(collision_x, collision_y, count=20,
|
||||
base_speed=150, lifetime=0.5,
|
||||
color=NEON_GREEN, size=4)
|
||||
|
||||
# Damage the block.
|
||||
block.hit(1)
|
||||
# When block is destroyed, add additional particle explosion.
|
||||
if block.is_destroyed():
|
||||
money += 10
|
||||
particle_system.add_explosion(block.rect.centerx, block.rect.centery,
|
||||
count=40, base_speed=200, lifetime=0.7,
|
||||
color=NEON_PINK, size=6)
|
||||
blocks.remove(block)
|
||||
# Stop checking after one collision per frame.
|
||||
break
|
||||
|
||||
# Draw everything.
|
||||
SCREEN.fill(BLACK)
|
||||
ball.draw(SCREEN)
|
||||
for block in blocks:
|
||||
block.draw(SCREEN)
|
||||
particle_system.draw(SCREEN)
|
||||
money_text = font.render(f"Money: ${money}", True, NEON_GREEN)
|
||||
SCREEN.blit(money_text, (10, HEIGHT - 40))
|
||||
pygame.display.flip()
|
||||
|
||||
pygame.quit()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
Loading…
Reference in New Issue
Block a user