Python:动态粒子爱心
预览
代码结构概述
这段代码使用了 pygame
库来创建一个动态的图形窗口,绘制一个心形图案,并在其中显示闪烁的文本。代码主要分为以下几个部分:
- 初始化和设置
- 心形曲线的计算
- 粒子类的定义
- 生成粒子
- 文本设置
- 主循环
1. 初始化和设置
import pygame
import random
import math
import os
# 初始化pygame
pygame.init()
# 屏幕尺寸
WIDTH, HEIGHT = 800, 600
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Dynamic Particle Heart")
pygame
用于图形处理,random
用于生成随机数,math
用于数学计算。pygame.init()
来初始化所有的 pygame 模块。set_caption
设置窗口的标题。2. 颜色定义
# 颜色定义
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
PURPLE = (128, 0, 128) # 紫色的RGB值
3. 心形曲线的计算
# 心形方程
def heart_curve(t):
x = 16 * math.sin(t) ** 3
y = 13 * math.cos(t) - 5 * math.cos(2 * t) - 2 * math.cos(3 * t) - math.cos(4 * t)
return x, y
heart_curve
,接受一个参数 t
(角度),并计算心形曲线的 x 和 y 坐标。这个公式通过三角函数生成心形的坐标。4. 计算心形的最大宽度和高度
def get_heart_dimensions():
max_x, min_x, max_y, min_y = -float('inf'), float('inf'), -float('inf'), float('inf')
for i in range(0, 360, 1):
angle_rad = math.radians(i)
x, y = heart_curve(angle_rad)
if x > max_x: max_x = x
if x < min_x: min_x = x
if -y > max_y: max_y = -y # 注意:这里取负是因为pygame坐标系y轴向下
if -y < min_y: min_y = -y
width = max_x - min_x
height = max_y - min_y
return width, height
5. 粒子类的定义
class Particle:
def __init__(self, x, y):
self.x = x
self.y = y
self.size = random.randint(2, 5)
self.color = PURPLE
self.angle = random.uniform(0, math.pi * 2)
self.speed = random.uniform(1, 3)
self.lifetime = random.randint(50, 100)
def move(self):
self.x += math.sin(self.angle) * self.speed
self.y -= math.cos(self.angle) * self.speed
self.size -= 0.05
self.lifetime -= 1
if self.size <= 0 or self.lifetime <= 0:
self.reset()
def reset(self):
angle_rad = random.uniform(0, math.pi * 2)
x, y = heart_curve(angle_rad)
self.x = x * scale_factor + WIDTH // 2
self.y = -y * scale_factor + HEIGHT // 2
self.size = random.randint(2, 5)
self.angle = random.uniform(0, math.pi * 2)
self.speed = random.uniform(1, 3)
self.lifetime = random.randint(50, 100)
def draw(self, screen):
s = pygame.Surface((self.size * 2, self.size * 2), pygame.SRCALPHA)
pygame.draw.circle(s, (*self.color[:3], self.lifetime * 2.55), (self.size, self.size), self.size)
screen.blit(s, (self.x - self.size, self.y - self.size))
Particle
类,表示一个粒子。
6. 生成粒子
# 生成初始粒子
particles = [Particle(random.uniform(-width/2, width/2) * scale_factor + WIDTH // 2,
random.uniform(-height/2, height/2) * scale_factor + HEIGHT // 2) for _ in range(10000)]
particles
列表中。每个粒子的位置是随机的,基于心形的尺寸和缩放因子。7. 文本设置
# 字体设置
font_size = 48 # 字体大小
font_path = "./test.ttf" # 确保字体文件在当前目录下
font = pygame.font.Font(font_path, font_size) # 使用指定字体
text = "多想再见你 哪怕一眼匆匆就别离"
text_surface = font.render(text, True, WHITE) # 渲染文本
text_rect = text_surface.get_rect(center=(WIDTH // 2, HEIGHT // 2)) # 文本居中
8. 主循环
# 主循环
running = True
clock = pygame.time.Clock()
blink_counter = 0
blink_rate = 10 # 每10帧闪烁一次
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
screen.fill(BLACK)
# 绘制心形曲线
points = []
for i in range(0, 360, 1):
angle_rad = math.radians(i)
x, y = heart_curve(angle_rad)
x = x * scale_factor + WIDTH // 2
y = -y * scale_factor + HEIGHT // 2
points.append((x, y))
pygame.draw.lines(screen, PURPLE, False, points, 2) # 使用lines代替polygon
# 更新和绘制粒子
for particle in particles:
particle.move()
particle.draw(screen)
# 绘制闪烁的文本
if blink_counter % blink_rate < blink_rate / 2: # 每隔一段时间闪烁
# 随机生成颜色
random_color = (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))
text_surface = font.render(text, True, random_color) # 渲染文本
screen.blit(text_surface, text_rect) # 绘制文本
blink_counter += 1
pygame.display.flip()
clock.tick(60)
pygame.quit()
pygame.display.flip()
更新屏幕,clock.tick(60)
控制帧率为 60 帧每秒。9. 退出
pygame.quit()
pygame.quit()
关闭窗口并清理资源。总结
这段代码结合了图形绘制、动画效果和文本渲染,展示了如何使用 pygame
创建一个动态的视觉效果。通过理解每个部分的功能,你可以更好地掌握 pygame
的使用,并进行更复杂的项目开发。
完整代码
import pygame
import random
import math
import os
# 初始化pygame
pygame.init()
# 屏幕尺寸
WIDTH, HEIGHT = 800, 600
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Dynamic Particle Heart")
# 颜色定义
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
PURPLE = (128, 0, 128) # 紫色的RGB值
# 心形方程
def heart_curve(t):
x = 16 * math.sin(t) ** 3
y = 13 * math.cos(t) - 5 * math.cos(2 * t) - 2 * math.cos(3 * t) - math.cos(4 * t)
return x, y
# 计算心形的最大宽度和高度
def get_heart_dimensions():
max_x, min_x, max_y, min_y = -float('inf'), float('inf'), -float('inf'), float('inf')
for i in range(0, 360, 1):
angle_rad = math.radians(i)
x, y = heart_curve(angle_rad)
if x > max_x: max_x = x
if x < min_x: min_x = x
if -y > max_y: max_y = -y # 注意:这里取负是因为pygame坐标系y轴向下
if -y < min_y: min_y = -y
width = max_x - min_x
height = max_y - min_y
return width, height
width, height = get_heart_dimensions()
scale_factor = min(WIDTH / (width * 1.2), HEIGHT / (height * 1.2)) # 增加一点额外的空间
# 粒子类
class Particle:
def __init__(self, x, y):
self.x = x
self.y = y
self.size = random.randint(2, 5)
self.color = PURPLE
self.angle = random.uniform(0, math.pi * 2)
self.speed = random.uniform(1, 3)
self.lifetime = random.randint(50, 100)
def move(self):
self.x += math.sin(self.angle) * self.speed
self.y -= math.cos(self.angle) * self.speed
self.size -= 0.05
self.lifetime -= 1
if self.size <= 0 or self.lifetime <= 0:
self.reset()
def reset(self):
angle_rad = random.uniform(0, math.pi * 2)
x, y = heart_curve(angle_rad)
self.x = x * scale_factor + WIDTH // 2
self.y = -y * scale_factor + HEIGHT // 2
self.size = random.randint(2, 5)
self.angle = random.uniform(0, math.pi * 2)
self.speed = random.uniform(1, 3)
self.lifetime = random.randint(50, 100)
def draw(self, screen):
s = pygame.Surface((self.size * 2, self.size * 2), pygame.SRCALPHA)
pygame.draw.circle(s, (*self.color[:3], self.lifetime * 2.55), (self.size, self.size), self.size)
screen.blit(s, (self.x - self.size, self.y - self.size))
# 生成初始粒子
particles = [Particle(random.uniform(-width/2, width/2) * scale_factor + WIDTH // 2,
random.uniform(-height/2, height/2) * scale_factor + HEIGHT // 2) for _ in range(10000)]
# 字体设置
font_size = 48 # 字体大小
font_path = "./test.ttf" # 确保字体文件在当前目录下
font = pygame.font.Font(font_path, font_size) # 使用指定字体
text = "多想再见你 哪怕一眼匆匆就别离"
text_surface = font.render(text, True, WHITE) # 渲染文本
text_rect = text_surface.get_rect(center=(WIDTH // 2, HEIGHT // 2)) # 文本居中
# 主循环
running = True
clock = pygame.time.Clock()
blink_counter = 0
blink_rate = 10 # 每10帧闪烁一次
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
screen.fill(BLACK)
# 绘制心形曲线
points = []
for i in range(0, 360, 1):
angle_rad = math.radians(i)
x, y = heart_curve(angle_rad)
x = x * scale_factor + WIDTH // 2
y = -y * scale_factor + HEIGHT // 2
points.append((x, y))
pygame.draw.lines(screen, PURPLE, False, points, 2) # 使用lines代替polygon
# 更新和绘制粒子
for particle in particles:
particle.move()
particle.draw(screen)
# 绘制闪烁的文本
if blink_counter % blink_rate < blink_rate / 2: # 每隔一段时间闪烁
# 随机生成颜色
random_color = (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))
text_surface = font.render(text, True, random_color) # 渲染文本
screen.blit(text_surface, text_rect) # 绘制文本
blink_counter += 1
pygame.display.flip()
clock.tick(60)
pygame.quit()
补充解说
让我详细解释这个代码的运行逻辑:
- 初始化阶段:
# 初始化基本设置
pygame.init()
WIDTH, HEIGHT = 800, 600
screen = pygame.display.set_mode((WIDTH, HEIGHT))
# 心形方程定义
def heart_curve(t):
x = 16 * math.sin(t) ** 3
y = 13 * math.cos(t) - 5 * math.cos(2 * t) - 2 * math.cos(3 * t) - math.cos(4 * t)
return x, y
- 粒子系统:
class Particle:
def __init__(self, x, y):
# 初始化粒子位置、大小、速度等属性
self.x = x
self.y = y
self.size = random.randint(2, 5)
self.angle = random.uniform(0, math.pi * 2)
self.speed = random.uniform(1, 3)
self.lifetime = random.randint(50, 100)
- 粒子移动和重置逻辑:
def move(self):
# 移动粒子
self.x += math.sin(self.angle) * self.speed
self.y -= math.cos(self.angle) * self.speed
self.size -= 0.05
self.lifetime -= 1
# 当粒子生命周期结束时重置
if self.size <= 0 or self.lifetime <= 0:
self.reset()
def reset(self):
# 重置粒子到心形曲线上的随机位置
angle_rad = random.uniform(0, math.pi * 2)
x, y = heart_curve(angle_rad)
self.x = x * scale_factor + WIDTH // 2
self.y = -y * scale_factor + HEIGHT // 2
# 重置其他属性
运行流程:
-
初始化:
- 创建10000个随机分布的粒子
- 每个粒子有随机的位置、大小、速度和生命周期
-
主循环:
while running:
screen.fill(BLACK) # 清空屏幕
# 绘制心形轮廓
# 更新和绘制所有粒子
for particle in particles:
particle.move()
particle.draw(screen)
- 粒子运动机制:
- 每个粒子按照自己的角度和速度移动
- 当粒子生命周期结束时,通过
reset()
函数重生在心形曲线上 - 这创造了粒子似乎在"靠近"心形的视觉效果
关于"靠近"效果的实现:
reset()
函数)核心实现在reset()
函数:
def reset(self):
angle_rad = random.uniform(0, math.pi * 2)
x, y = heart_curve(angle_rad) # 在心形曲线上选择新位置
这不是真正的"靠近"运动,而是通过粒子的死亡和重生机制,逐渐在心形轮廓上形成粒子群,创造出视觉上的聚集效果。
作者:百年孤独_