预览
代码结构概述
这段代码使用了 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:调用
pygame.init()
来初始化所有的 pygame 模块。 - 设置屏幕尺寸:定义窗口的宽度和高度,并创建一个窗口。
- 设置窗口标题:使用
set_caption
设置窗口的标题。
2. 颜色定义
# 颜色定义
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
PURPLE = (128, 0, 128) # 紫色的RGB值
- 定义颜色:使用 RGB 颜色模式定义了白色、黑色和紫色。
3. 心形曲线的计算
# 心形方程
def heart_curve(t):x = 16 * math.sin(t) ** 3y = 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 = xif x < min_x: min_x = xif -y > max_y: max_y = -y # 注意:这里取负是因为pygame坐标系y轴向下if -y < min_y: min_y = -ywidth = max_x - min_xheight = max_y - min_yreturn width, height
- 计算心形的尺寸:这个函数遍历从 0 到 360 度的每个角度,计算心形的坐标,并找到心形的最大和最小 x、y 值,以便计算出心形的宽度和高度。
5. 粒子类的定义
class Particle:def __init__(self, x, y):self.x = xself.y = yself.size = random.randint(2, 5)self.color = PURPLEself.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.speedself.y -= math.cos(self.angle) * self.speedself.size -= 0.05self.lifetime -= 1if 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 // 2self.y = -y * scale_factor + HEIGHT // 2self.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
类,表示一个粒子。- 初始化方法:设置粒子的初始位置、大小、颜色、角度、速度和生命周期。
- 移动方法:更新粒子的位置,减少大小和生命周期。如果粒子的大小或生命周期小于等于0,则重置粒子。
- 重置方法:随机生成新的位置、大小、角度和速度。
- 绘制方法:在屏幕上绘制粒子。
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)]
- 创建粒子:生成 10,000 个粒子,并将它们存储在
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 = Falsescreen.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 // 2y = -y * scale_factor + HEIGHT // 2points.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 += 1pygame.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) ** 3y = 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 = xif x < min_x: min_x = xif -y > max_y: max_y = -y # 注意:这里取负是因为pygame坐标系y轴向下if -y < min_y: min_y = -ywidth = max_x - min_xheight = max_y - min_yreturn width, heightwidth, height = get_heart_dimensions()
scale_factor = min(WIDTH / (width * 1.2), HEIGHT / (height * 1.2)) # 增加一点额外的空间# 粒子类
class Particle:def __init__(self, x, y):self.x = xself.y = yself.size = random.randint(2, 5)self.color = PURPLEself.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.speedself.y -= math.cos(self.angle) * self.speedself.size -= 0.05self.lifetime -= 1if 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 // 2self.y = -y * scale_factor + HEIGHT // 2self.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 = Falsescreen.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 // 2y = -y * scale_factor + HEIGHT // 2points.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 += 1pygame.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) ** 3y = 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 = xself.y = yself.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.speedself.y -= math.cos(self.angle) * self.speedself.size -= 0.05self.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 // 2self.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) # 在心形曲线上选择新位置
这不是真正的"靠近"运动,而是通过粒子的死亡和重生机制,逐渐在心形轮廓上形成粒子群,创造出视觉上的聚集效果。