浪漫的不是代码,而是运行结果皆如你所愿:用 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

物联沃分享整理
物联沃-IOTWORD物联网 » 浪漫的不是代码,而是运行结果皆如你所愿:用 Python 画一个爱心表白

发表回复