当前位置: 首页 > article >正文

Python:动态粒子爱心

预览

在这里插入图片描述

代码结构概述

这段代码使用了 pygame 库来创建一个动态的图形窗口,绘制一个心形图案,并在其中显示闪烁的文本。代码主要分为以下几个部分:

  1. 初始化和设置
  2. 心形曲线的计算
  3. 粒子类的定义
  4. 生成粒子
  5. 文本设置
  6. 主循环

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) ** 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
  • 计算心形的尺寸:这个函数遍历从 0 到 360 度的每个角度,计算心形的坐标,并找到心形的最大和最小 x、y 值,以便计算出心形的宽度和高度。

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 类,表示一个粒子。
    • 初始化方法:设置粒子的初始位置、大小、颜色、角度、速度和生命周期。
    • 移动方法:更新粒子的位置,减少大小和生命周期。如果粒子的大小或生命周期小于等于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 = 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()

补充解说

让我详细解释这个代码的运行逻辑:

  1. 初始化阶段
# 初始化基本设置
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
  1. 粒子系统
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)
  1. 粒子移动和重置逻辑
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
    # 重置其他属性

运行流程:

  1. 初始化

    • 创建10000个随机分布的粒子
    • 每个粒子有随机的位置、大小、速度和生命周期
  2. 主循环

while running:
    screen.fill(BLACK)  # 清空屏幕
    
    # 绘制心形轮廓
    # 更新和绘制所有粒子
    for particle in particles:
        particle.move()
        particle.draw(screen)
  1. 粒子运动机制
    • 每个粒子按照自己的角度和速度移动
    • 当粒子生命周期结束时,通过reset()函数重生在心形曲线上
    • 这创造了粒子似乎在"靠近"心形的视觉效果

关于"靠近"效果的实现:

  • 这个效果是通过粒子的生命周期系统实现的
  • 当粒子消失时,它们会在心形曲线上重生(reset()函数)
  • 随着时间推移,越来越多的粒子会重生在心形曲线上
  • 这创造了粒子群似乎在向心形聚集的视觉效果

核心实现在reset()函数:

def reset(self):
    angle_rad = random.uniform(0, math.pi * 2)
    x, y = heart_curve(angle_rad)  # 在心形曲线上选择新位置

这不是真正的"靠近"运动,而是通过粒子的死亡和重生机制,逐渐在心形轮廓上形成粒子群,创造出视觉上的聚集效果。


http://www.kler.cn/a/444387.html

相关文章:

  • 中国新能源汽车公共充电桩数据合集(2002-2023年)
  • 常用es命令
  • ViEW生命周期
  • @PostConstruct注解解释!!!!
  • 基于Python3编写的Golang程序多平台交叉编译自动化脚本
  • C# winform 字符串通过枚举类型转成int类型的数据
  • Spring IOC 和 AOP的学习笔记
  • Spring篇--xml方式整合第三方框架
  • linux CentOS系统上卸载docker
  • Android Binder 进程间通信
  • 肝了半年,我整理出了这篇云计算学习路线(新手必备,从入门到精通)
  • Diffusino Policy学习note
  • Unbuntu下怎么生成SSL自签证书?
  • 聊聊开源的虚拟化平台--PVE
  • 02、10个富士胶片模拟的设置
  • 使用 Canal 监听 MySQL Binlog 日志实现最终一致性
  • 《算法SM3》题目
  • 零基础开始学习鸿蒙开发-交友软件页面设计
  • 【开源免费】基于Vue和SpringBoot的靓车汽车销售网站(附论文)
  • 系统移植——Linux 内核顶层 Makefile 详解
  • 谈谈网络流量控制
  • python学opencv|读取图像(十六)修改HSV图像HSV值
  • 【自用】通信内网部署rzgxxt项目_01,后端pipeDemo部署(使用nssm.exe仿照nohup)
  • 1、数据库概念和mysql表的管理
  • c语言----选择结构
  • clickhouse一直重启,日志提示structure needs cleaning