浪漫的不是代码,而是运行结果皆如你所愿:用 Python 画一个爱心表白
在编程的世界里,浪漫可以通过代码实现,用简单的逻辑和几行代码,就能创造出令人心动的瞬间。今天,就用 Python 带你实现一个浪漫的创意——画一个动态的爱心,并向你的特别之人表白!话不多说直接先看效果图!
一、工具准备
在开始之前,确保你的 Python 环境中安装了 pygame
库。如果没有,可以运行以下命令安装:
pip install pygame
二、代码实现
以下是完整代码,运行后会显示一个动态跳动的有背景音乐且能变色的爱心图形,同时在屏幕上展示你的表白文字:
# -*- coding = utf-8 -*-
# @Time: 2024/11/24 上午11:13
# @Author: 风我风格
# @File: heart_effect.py
# @Email: 1090461393@qq.com
# @SoftWare: PyCharm
# 导入 Pygame 库
import pygame
import random
import math
import os
# 初始化 Pygame 库
pygame.init()
# 获取当前显示设备的信息
info = pygame.display.Info() # 获取当前显示设备的信息,如分辨率
width, height = info.current_w, info.current_h # 获取屏幕宽度和高度
# 设置全屏模式,创建一个全屏的显示窗口
screen = pygame.display.set_mode((width, height), pygame.FULLSCREEN) # 使用全屏模式
pygame.display.set_caption("扑通扑通爱心粒子表白效果") # 设置窗口标题为 "扑通扑通爱心粒子表白效果"
clock = pygame.time.Clock() # 创建时钟对象,用于控制帧率(即每秒更新的次数)
# 获取当前脚本的绝对路径
BASE_DIR = os.path.dirname(os.path.abspath(__file__)) # 获取当前脚本所在目录的绝对路径
# 加载和播放背景音乐
pygame.mixer.init() # 初始化音频模块,准备播放音频
# 加载背景音乐文件,使用 os.path.join 使得路径兼容多平台
pygame.mixer.music.load(os.path.join(BASE_DIR, "Falling_You.mp3")) # 加载名为 "Falling_You.mp3" 的音乐文件
# 播放音乐,参数 -1 表示无限循环播放音乐
pygame.mixer.music.play(-1) # 无限循环播放音乐
class ColorGradient:
"""生成颜色渐变效果"""
def __init__(self, max_value):
"""
初始化 ColorGradient 实例,设置最大值。
:param max_value: 渐变计算的最大值,用于决定颜色变化的范围。
"""
self.max_value = max_value # 设置最大值,影响颜色变化的周期
def get_color(self, value):
"""
根据输入的值生成 RGB 颜色值。颜色值会在红、绿、蓝三色之间变化。
:param value: 当前的值,用于计算颜色。
:return: 一个包含 RGB 值的元组。
"""
# 计算红色通道的值,正弦函数根据 value 调整波动,达到渐变效果
r = int(255 * (0.5 + 0.5 * math.sin(value / self.max_value * math.pi * 2)))
# 计算绿色通道的值,添加一个相位偏移,产生不同的渐变效果
g = int(255 * (0.5 + 0.5 * math.sin(value / self.max_value * math.pi * 2 + 2)))
# 计算蓝色通道的值,同样添加不同的相位偏移
b = int(255 * (0.5 + 0.5 * math.sin(value / self.max_value * math.pi * 2 + 4)))
return r, g, b # 返回红、绿、蓝三种颜色通道的值
class HeartShape:
"""生成爱心形状的点"""
def __init__(self, width, height):
"""
初始化 HeartShape 实例,设置画布的宽度和高度。
:param width: 画布的宽度,用于计算爱心的 X 坐标。
:param height: 画布的高度,用于计算爱心的 Y 坐标。
"""
self.width = width # 存储画布宽度
self.height = height # 存储画布高度
def generate_point(self, t):
"""
根据给定的时间 t 计算爱心形状上的一个点的位置。
:param t: 当前时间或参数,用于生成动态的爱心形状。
:return: 爱心形状上的一个 (x, y) 坐标点。
"""
# 跳动幅度,通过正弦函数让爱心的跳动效果更自然
scale_factor = 1 + 0.1 * math.sin(t * 2) # 根据 t 来调整跳动的幅度
# 使用爱心曲线的参数方程生成 x 坐标
x = int(self.width / 2 + 16 * math.sin(t) ** 3 * 20 * scale_factor)
# 使用爱心曲线的参数方程生成 y 坐标
y = int(self.height / 2 - (
13 * math.cos(t) - 5 * math.cos(2 * t) - 2 * math.cos(3 * t) - math.cos(4 * t)) * 20 * scale_factor)
return x, y # 返回计算得到的 (x, y) 坐标
class Particle:
"""粒子类,控制粒子的运动、大小和形状"""
def __init__(self, x, y, color, lifetime, shape="circle", text=None):
"""
初始化粒子类实例,设置粒子的位置、颜色、生命周期、大小等属性。
:param x: 粒子的初始 X 坐标。
:param y: 粒子的初始 Y 坐标。
:param color: 粒子的颜色。
:param lifetime: 粒子的生命周期(持续时间)。
:param shape: 粒子的形状,默认为圆形,可以设置为 "heart" 来绘制爱心形状。
:param text: 如果粒子上要显示文字,传入文字内容。默认为 None。
"""
self.x = x # 粒子的 X 坐标
self.y = y # 粒子的 Y 坐标
self.color = color # 粒子的颜色
self.lifetime = lifetime # 粒子的生命周期,表示它存活的时间
self.size = random.randint(2, 4) # 粒子的初始大小,随机在 2 到 4 之间
self.vx = random.uniform(-1, 1) # 粒子沿 X 轴的速度,随机在 -1 到 1 之间
self.vy = random.uniform(-1, 1) # 粒子沿 Y 轴的速度,随机在 -1 到 1 之间
self.shape = shape # 粒子的形状,可以是 "circle" 或 "heart"
self.text = text # 如果有文本,显示的内容(默认为 None)
def move(self):
"""更新粒子的位置和生命周期"""
self.x += self.vx # 根据 X 轴的速度更新粒子位置
self.y += self.vy # 根据 Y 轴的速度更新粒子位置
self.lifetime -= 1 # 粒子的生命周期减少
self.size = max(1, self.size - 0.05) # 粒子逐渐减小,最小为 1
def draw(self, screen):
"""绘制粒子"""
if self.lifetime > 0: # 仅在粒子生命期内绘制
if self.shape == "circle":
# 如果粒子是圆形,使用 pygame.draw.circle 绘制
pygame.draw.circle(screen, self.color, (int(self.x), int(self.y)), int(self.size))
elif self.shape == "heart":
# 如果粒子是爱心形状,调用绘制爱心的方法
self.draw_heart(screen)
if self.text:
# 如果粒子需要显示文字,调用显示文字的方法
self.display_text(screen)
def draw_heart(self, screen):
"""绘制爱心形状粒子"""
size = int(self.size) # 爱心的大小
points = [
(self.x, self.y - size), # 爱心的上端
(self.x - size, self.y - size // 2), # 爱心左侧
(self.x - size, self.y + size // 2), # 爱心底部左侧
(self.x + size, self.y + size // 2), # 爱心底部右侧
(self.x + size, self.y - size // 2), # 爱心右侧
]
# 使用 pygame.draw.polygon 绘制多边形的爱心形状
pygame.draw.polygon(screen, self.color, points)
def display_text(self, screen):
"""在粒子上显示中文文字(我爱你)"""
# 加载字体,确保字体文件路径正确,支持中文显示
font_path = os.path.join(BASE_DIR, "simhei.ttf")
font = pygame.font.Font(font_path, 20) # 设置字体大小为 20
text_surface = font.render(self.text, True, self.color) # 渲染文字
screen.blit(text_surface, (self.x, self.y)) # 将渲染后的文字绘制到屏幕上的粒子位置
class ParticleSystem:
"""粒子系统,控制粒子的生成、更新和绘制"""
def __init__(self, heart_shape, color_gradient):
# 初始化粒子系统
# heart_shape: 生成爱心形状轨迹的对象,用于计算每个粒子的生成位置
# color_gradient: 生成颜色渐变的对象,用于控制粒子颜色的变化
# particles: 存储粒子的列表
self.particles = []
# 将生成爱心形状和颜色渐变对象存储到对应的属性中
self.heart_shape = heart_shape
self.color_gradient = color_gradient
# last_particle_time: 记录上一次生成粒子的时间,用于控制粒子生成频率
self.last_particle_time = 0
def generate_particles(self, t):
"""生成新的粒子,控制生成频率"""
# 获取当前时间,单位是毫秒
current_time = pygame.time.get_ticks()
# 控制粒子生成的频率,每 100 毫秒生成一次
if current_time - self.last_particle_time > 100:
# 每次生成 520 个粒子
for _ in range(520):
# 根据当前时间 t 和随机偏移量计算粒子的位置
# 通过调用 heart_shape 对象的 generate_point 方法,得到粒子的位置
x, y = self.heart_shape.generate_point(t + random.uniform(0, 2 * math.pi))
# 根据时间 t 获取粒子的颜色
color = self.color_gradient.get_color(t)
# 随机生成粒子的生命周期,范围在 40 到 100 之间
lifetime = random.randint(40, 100)
# 随机决定粒子的形状,10%的概率是爱心形状,90%的概率是圆形
shape = "heart" if random.random() < 0.1 else "circle"
# 随机决定是否在粒子上显示文本,0.052%的概率显示“我爱你”
text = "我喜欢你" if random.random() < 0.00052 else None
# 创建一个粒子对象并将其添加到粒子列表中
self.particles.append(Particle(x, y, color, lifetime, shape, text))
# 更新最后一次生成粒子的时间
self.last_particle_time = current_time
def update_particles(self):
"""更新和绘制粒子"""
# 遍历粒子列表中的每个粒子
for particle in self.particles[:]:
# 更新粒子的位置
particle.move()
# 绘制粒子到屏幕上
particle.draw(screen)
# 如果粒子的生命周期结束,移除该粒子
if particle.lifetime <= 0:
self.particles.remove(particle)
class HeartParticleEffect:
"""主动画类,负责控制整个效果的运行"""
def __init__(self, width, height):
# 初始化动画效果,设置画布的宽度和高度
# width, height: 设置屏幕的宽度和高度
self.width = width
self.height = height
# 创建 HeartShape 对象,用于生成爱心形状的粒子路径
self.heart_shape = HeartShape(width, height)
# 创建 ColorGradient 对象,用于生成颜色渐变效果
self.color_gradient = ColorGradient(100)
# 创建 ParticleSystem 对象,控制粒子的生成、更新和绘制
self.particle_system = ParticleSystem(self.heart_shape, self.color_gradient)
# t: 用于控制时间的变量,决定粒子的生成和运动
self.t = 0
# running: 控制动画是否继续运行
self.running = True
def run(self):
"""运行主动画循环"""
# 主动画循环,直到用户关闭窗口或按下 ESC 键
while self.running:
# 填充屏幕背景为黑色
screen.fill((0, 0, 0)) # 黑色背景
# 增加 t 的值,以便使粒子的位置、颜色等随时间变化
self.t += 0.1
# 生成新的粒子
self.particle_system.generate_particles(self.t)
# 更新并绘制粒子
self.particle_system.update_particles()
# 处理事件
for event in pygame.event.get():
# 如果用户点击了关闭窗口按钮或按下了 ESC 键,结束动画
if event.type == pygame.QUIT or (event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE):
self.running = False
# 更新屏幕,显示当前帧的内容
pygame.display.flip()
# 控制帧率,保持在 60 帧每秒
clock.tick(60)
# 运行主程序
if __name__ == "__main__": # 如果是直接运行这个脚本(而不是被导入作为模块),就执行以下代码
effect = HeartParticleEffect(width, height) # 创建一个 HeartParticleEffect 对象,传入宽度和高度
effect.run() # 调用该对象的 run 方法,开始运行主动画循环
pygame.quit() # 退出 pygame 模块,清理资源
三、总结
用代码表达情感是一件很特别的事情,它不仅让人感受到编程的乐趣,更赋予了程序新的意义。希望这颗 Python 爱心能带给你和特别的人一个难忘的瞬间!
💡 浪漫的不是代码,而是那些充满爱与诚意的运行结果。
作者:手可摘星辰938