数字世界中的浪漫:揭秘会跳动的爱心

在编程的世界里,复杂的技术可以与艺术产生美妙的碰撞。无论是通过代码实现动态效果,还是用算法绘制图案,程序员都可以成为数字艺术的创作者。而今天,我们将通过 Python 的强大 GUI 工具库 Tkinter,用简单的代码生成一颗会跳动的爱心。这个教程不仅能帮助你了解如何用 Tkinter 绘制图形,还能让你感受到编程的创造力与艺术的结合。

Tkinter 是 Python 中内置的 GUI 库,非常适合初学者入门。在这篇文章中,我们将带你从基础开始,逐步掌握如何使用 Tkinter 创建一个简单的 GUI 应用,并为后续动态生成爱心效果打下基础。

1.Tkinter概述

Tkinter 是 Python 提供的标准库之一,用于创建图形用户界面(GUI)。它简单易用,同时功能强大,适合小型应用程序的开发。通过 Tkinter,你可以快速构建窗口、按钮、文本框、标签等常见的 GUI 组件。以下是 Tkinter 的主要功能和基本用法:

1. Tkinter 的作用

  • 创建窗口:通过简单的几行代码即可生成应用程序窗口。
  • 图形界面组件:提供按钮、标签、文本框等丰富的 GUI 组件,便于构建交互式程序。
  • 事件处理:支持鼠标点击、键盘输入等事件监听,帮助你与用户交互。
  • 绘图功能:可以通过 Canvas 组件轻松绘制图形,例如直线、矩形、椭圆等,为后续的图像创作提供基础。

2. Tkinter 的基本用法

Tkinter 的使用非常直观,以下是创建一个基本窗口的步骤:

  • 导入 Tkinter 模块

    import tkinter as tk
    
  • 创建主窗口
    使用 Tk() 函数创建主窗口,并设置窗口的标题:

    root = tk.Tk()  # 创建主窗口
    root.title("我的第一个 Tkinter 应用")  # 设置窗口标题
    
  • 添加组件
    例如,向窗口中添加一个按钮和标签:

    label = tk.Label(root, text="你好,Tkinter!")  # 创建标签
    label.pack()  # 使用 pack 布局管理器将标签放置在窗口中
    
    button = tk.Button(root, text="点击我", command=root.quit)  # 创建按钮
    button.pack()  # 将按钮放置在窗口中
    
  • 启动主循环
    mainloop() 是 Tkinter 的主循环,用于显示窗口并等待用户的输入。窗口将在主循环运行时保持响应状态。

    root.mainloop()
    

完整代码示例:

import tkinter as tk

# 创建主窗口
root = tk.Tk()
root.title("我的第一个 Tkinter 应用")

# 添加标签和按钮
label = tk.Label(root, text="你好,Tkinter!")
label.pack()

button = tk.Button(root, text="点击我", command=root.quit)
button.pack()

# 启动主循环
root.mainloop()

3. 绘制图形:使用 Canvas

在 Tkinter 中,Canvas 组件非常强大,允许你在窗口中绘制各种图形,如矩形、椭圆、线条等。为了后续实现动态爱心,我们可以使用 Canvas 绘制图形。

创建一个简单的绘图窗口示例:

import tkinter as tk

# 创建主窗口
root = tk.Tk()
root.title("绘制图形")

# 创建画布
canvas = tk.Canvas(root, width=400, height=400)
canvas.pack()

# 绘制一个矩形
canvas.create_rectangle(50, 50, 150, 150, fill="blue")

# 启动主循环
root.mainloop()

以上代码会在窗口中显示一个蓝色的矩形。你可以用类似的方法绘制其他形状,为创建复杂的图案(如爱心)打下基础。

2.爱心曲线

在前面的介绍中,我们了解了 Tkinter 的基础知识,这个强大的 Python GUI 库让我们能够轻松创建各种图形界面。那么,在 Tkinter 的基础上,我们能否实现更复杂且有趣的图形呢?答案是肯定的!接下来我们将借助 Tkinter,通过一些基本的数学方程,绘制出一个动态跳动的爱心图案。

想要让爱心随着时间跳动,我们不仅需要掌握如何用 Tkinter 绘图,还需要理解一些关键的数学方程。这些方程将帮助我们生成爱心的形状,并使其产生类似心跳的动态效果。下面,我们将逐步介绍这些爱心方程,并通过 Python 代码进行可视化展示。

绘制爱心形状有多种方法,最常见的是使用基于参数方程的方式。通过合适的数学公式,我们可以生成理想的心形。

1. 经典爱心形状的参数方程

经典的心形方程可以通过参数方程表示为:

x ( t ) = 16 sin ⁡ 3 ( t ) x(t) = 16 \sin^3(t) x(t)=16sin3(t)
y ( t ) = 13 cos ⁡ ( t ) − 5 cos ⁡ ( 2 t ) − 2 cos ⁡ ( 3 t ) − cos ⁡ ( 4 t ) y(t) = 13 \cos(t) - 5 \cos(2t) - 2 \cos(3t) - \cos(4t) y(t)=13cos(t)5cos(2t)2cos(3t)cos(4t)

其中, ( t ) 是参数,范围从 ( 0 ) 到 ( 2 π 2\pi 2π )。这个方程定义了一个平滑的心形曲线。

  • x(t)y(t) 分别定义了心形的横坐标和纵坐标。
  • sincos 函数的组合定义了心形的轮廓,使其看起来饱满且对称。

2. 随机内部扩散函数

该函数模拟了点从原始坐标的随机扩散效果。它通过引入随机性,使心形内的点从中心向外散开,形成一种分散的视觉效果。
公式解析
函数中的关键公式是:
x ′ = x − ( − β ⋅ log ⁡ ( random ( ) ) ⋅ ( x − CANVAS_CENTER_X ) ) x' = x - \left( - \beta \cdot \log(\text{random}()) \cdot (x - \text{CANVAS\_CENTER\_X}) \right) x=x(βlog(random())(xCANVAS_CENTER_X))
y ′ = y − ( − β ⋅ log ⁡ ( random ( ) ) ⋅ ( y − CANVAS_CENTER_Y ) ) y' = y - \left( - \beta \cdot \log(\text{random}()) \cdot (y - \text{CANVAS\_CENTER\_Y}) \right) y=y(βlog(random())(yCANVAS_CENTER_Y))

公式中的 log ⁡ ( random ( ) ) \log(\text{random}()) log(random()) 引入了随机扰动,用于控制每个点沿着 (x) 和 (y) 轴的位移,使得每个点以不同的强度从中心散开。这种随机性导致了心形的点分散开来,模拟出“跳动”的不规则性。

3. 缩放函数

此函数实现了点从中心向内或向外的缩放效果,基于计算出的力将点移动。
缩放的力通过下列公式计算:
force = − 1 ( ( x − CANVAS_CENTER_X ) 2 + ( y − CANVAS_CENTER_Y ) 2 ) 0.6 \text{force} = -\frac{1}{\left((x - \text{CANVAS\_CENTER\_X})^2 + (y - \text{CANVAS\_CENTER\_Y})^2\right)^{0.6}} force=((xCANVAS_CENTER_X)2+(yCANVAS_CENTER_Y)2)0.61

然后新的坐标计算如下:

x ′ = x − ( ratio ⋅ force ⋅ ( x − CANVAS_CENTER_X ) ) x' = x - \left( \text{ratio} \cdot \text{force} \cdot (x - \text{CANVAS\_CENTER\_X}) \right) x=x(ratioforce(xCANVAS_CENTER_X))
y ′ = y − ( ratio ⋅ force ⋅ ( y − CANVAS_CENTER_Y ) ) y' = y - \left( \text{ratio} \cdot \text{force} \cdot (y - \text{CANVAS\_CENTER\_Y}) \right) y=y(ratioforce(yCANVAS_CENTER_Y))

公式中的力会根据点距离中心的远近来决定,距离中心越远,受到的力越小。通过这种力的作用,点会向中心收缩,从而形成视觉上的“缩小”效果。

4. 心跳曲线函数

这是模拟心脏跳动的关键函数,通过正弦波函数产生周期性振荡效果,控制心形的扩展与收缩。

公式解析
curve ( p ) = 2 ⋅ 2 ⋅ sin ⁡ ( 4 p ) 2 π \text{curve}(p) = 2 \cdot \frac{2 \cdot \sin(4p)}{2\pi} curve(p)=22π2sin(4p)
这个正弦函数生成周期性的波动,用来模拟心脏跳动的节奏。这里,§ 是控制心跳的参数,随着时间推进,心形在该曲线函数的作用下会产生规律性的扩张与收缩。

  • 正弦函数 sin ⁡ ( 4 p ) \sin(4p) sin(4p):这部分函数的作用是生成周期性的波动。由于正弦函数的特性,它在每个周期内从 -1 到 1 之间振荡。

  • 系数 4 p 4p 4p:将 (p) 乘以 4,使得心形在较短的时间内完成更多次跳动,模拟心跳的快速节奏。

  • 常数项 2 2 π \frac{2}{2\pi} 2π2:这个常数项保证了曲线的振幅适中,不会过度扩大或缩小。

# Curve function
def curve(p):
    return 2 * (2 * sin(4 * p)) / (2 * pi)
    
p_values = np.linspace(0, 2 * np.pi, 500)
curve_values = [curve(p) for p in p_values]

# Plot curve function
plt.figure(figsize=(6, 4))
plt.plot(p_values, curve_values, color='purple', label='Curve(p) = 2 * (2 * sin(4p)) / (2π)')
plt.title('Curve Function (Oscillation Effect)')
plt.xlabel('p')
plt.ylabel('Curve(p)')
plt.grid(True)
plt.show()

综合起来,整个函数 curve ( p ) = 2 ⋅ 2 ⋅ sin ⁡ ( 4 p ) 2 π \text{curve}(p) = 2 \cdot \frac{2 \cdot \sin(4p)}{2\pi} curve(p)=22π2sin(4p)用于生成周期性振荡,控制心形的尺寸变化,从而表现出类似“心脏跳动”的效果。随着时间 § 的变化,心形会周期性地扩大和收缩,看起来就像是在跳动。

5. 编码查看曲线

import numpy as np
import matplotlib.pyplot as plt
import random
from math import sin, pi, log

# Constants
CANVAS_CENTER_X = 0
CANVAS_CENTER_Y = 0

# Scatter inside function
def scatter_inside(x, y, beta=0.15):
    ratio_x = - beta * log(random.random())
    ratio_y = - beta * log(random.random())

    dx = ratio_x * (x - CANVAS_CENTER_X)
    dy = ratio_y * (y - CANVAS_CENTER_Y)

    return x - dx, y - dy

# Shrink function
def shrink(x, y, ratio):
    force = -1 / (((x - CANVAS_CENTER_X) ** 2 + (y - CANVAS_CENTER_Y) ** 2) ** 0.6)
    dx = ratio * force * (x - CANVAS_CENTER_X)
    dy = ratio * force * (y - CANVAS_CENTER_Y)
    return x - dx, y - dy

# Curve function
def curve(p):
    return 2 * (2 * sin(4 * p)) / (2 * pi)

# Generate heart shape points (parametric equations)
t = np.linspace(0, 2 * np.pi, 500)
x_heart = 16 * np.sin(t)**3
y_heart = 13 * np.cos(t) - 5 * np.cos(2*t) - 2 * np.cos(3*t) - np.cos(4*t)

# Scatter Inside effect
x_scatter = []
y_scatter = []
for i in range(len(x_heart)):
    x, y = scatter_inside(x_heart[i], y_heart[i])
    x_scatter.append(x)
    y_scatter.append(y)

# Shrink effect
x_shrink = []
y_shrink = []
for i in range(len(x_heart)):
    x, y = shrink(x_heart[i], y_heart[i], 0.8)
    x_shrink.append(x)
    y_shrink.append(y)

# Plot results
plt.figure(figsize=(12, 4))

# Original heart shape
plt.subplot(1, 3, 1)
plt.plot(x_heart, y_heart, color='red', label="Original Heart Shape")
plt.title("Original Heart Shape")
plt.axis('equal')

# Scattered heart shape
plt.subplot(1, 3, 2)
plt.scatter(x_scatter, y_scatter, color='blue', label="Scattered Heart Shape", s=5)
plt.title("Scattered Heart Shape")
plt.axis('equal')

# Shrunk heart shape
plt.subplot(1, 3, 3)
plt.plot(x_shrink, y_shrink, color='green', label="Shrunk Heart Shape")
plt.title("Shrunk Heart Shape")
plt.axis('equal')

plt.tight_layout()
plt.show()

在这里插入图片描述

在掌握了 Tkinter 的基础知识以及心形的数学方程后,我们就可以结合 Tkinter 的绘图能力,生成一个在屏幕上跳动的动态爱心。接下来,我们将进一步讲解如何使用这些方程在 Tkinter 中实现,并构建一个带有心跳效果的图形界面。

通过这个有趣的项目,不仅可以进一步学习 Tkinter 的应用,还能加深对数学图形生成和动画效果的理解。让我们继续深入探索,开启我们的跳动爱心绘制之旅!

3.Heart跳动爱心

这个 Heart 类实现了一个动态的爱心图案生成和渲染过程,包含边缘扩散、中心扩散和光环效果。下面是对该类的详细分析,帮助你快速理解每个功能的作用和流程:

1. 类的属性与初始化

def __init__(self, generate_frame=20):
    self._points = set()  # 原始爱心坐标集合
    self._edge_diffusion_points = set()  # 边缘扩散效果点坐标集合
    self._center_diffusion_points = set()  # 中心扩散效果点坐标集合
    self.all_points = {
    
    }  # 每帧动态点坐标
    self.build(2000)

    self.random_halo = 1000

    self.generate_frame = generate_frame
    for frame in range(generate_frame):
        self.calc(frame)
  • self._points: 保存原始的爱心轮廓坐标点。
  • self._edge_diffusion_points: 存放爱心边缘扩散效果的点集合。
  • self._center_diffusion_points: 存放爱心中心扩散效果的点集合。
  • self.all_points: 保存所有帧对应的点数据,用于动画的逐帧渲染。
  • self.random_halo: 一个随机生成光环的参数,未在 __init__ 中直接使用。
  • self.generate_frame: 动画总帧数,默认20帧。
  • self.build(2000): 生成2000个爱心轮廓的点并进行扩散计算。
  • self.calc(frame): 对每一帧执行动态点计算,生成该帧的点数据。

2. 爱心形状生成与扩散build 方法):

def build(self, number):
    # 爱心
    for _ in range(number):
        t = random.uniform(0, 2 * pi)  # 随机不到的地方造成爱心有缺口
        x, y = heart_function(t)
        self._points.add((x, y))

    # 爱心内扩散
    for _x, _y in list(self._points):
        for _ in range(3):
            x, y = scatter_inside(_x, _y, 0.05)
            self._edge_diffusion_points.add((x, y))

    # 爱心内再次扩散
    point_list = list(self._points)
    for _ in range(6000):
        x, y = random.choice(point_list)
        x, y = scatter_inside(x, y, 0.17)
        self._center_diffusion_points.add((x, y))
  • 爱心形状生成:通过 heart_function(t) 生成一组爱心形状的坐标,并保存到 _points 集合中,参数 t 是从 (0) 到 (2\pi) 的随机值,用于控制爱心的完整性。

  • 边缘扩散:每个爱心点坐标经过 scatter_inside() 函数的随机散射后,得到扩散后的点,这些点被存储在 _edge_diffusion_points 中,模拟边缘的扩散效果。

  • 中心扩散:进一步随机选择部分原始爱心点,并使用较大的散射系数再次扩散,生成中心的扩散效果,结果保存在 _center_diffusion_points

3. 缩放计算calc_position 方法):

@staticmethod
def calc_position(x, y, ratio):
    # 调整缩放比例
    force = 1 / (((x - CANVAS_CENTER_X) ** 2 + (y - CANVAS_CENTER_Y) ** 2) ** 0.520)  # 魔法参数

    dx = ratio * force * (x - CANVAS_CENTER_X) + random.randint(-1, 1)
    dy = ratio * force * (y - CANVAS_CENTER_Y) + random.randint(-1, 1)

    return x - dx, y - dy
  • force:根据点离中心的距离计算力(缩放因子),越远的点,受到的力越小,使得远离中心的点缩小得更少。
  • dxdy:调整后的坐标变化量,基于 ratio 比例调整。这个方法对点进行一定的缩放和随机抖动,模拟动态变化。

4. 计算每帧的点位置calc 方法):

def calc(self, generate_frame):
    ratio = 10 * curve(generate_frame / 10 * pi)  # 圆滑的周期的缩放比例

    halo_radius = int(4 + 6 * (1 + curve(generate_frame / 10 * pi)))
    halo_number = int(3000 + 4000 * abs(curve(generate_frame / 10 * pi) ** 2))

    all_points = []

    # 光环
    heart_halo_point = set()  # 光环的点坐标集合
    for _ in range(halo_number):
        t = random.uniform(0, 4 * pi)
        x, y = heart_function(t, shrink_ratio=11.5)
        x, y = shrink(x, y, halo_radius)
        if (x, y) not in heart_halo_point:
            heart_halo_point.add((x, y))
            x += random.randint(-14, 14)
            y += random.randint(-14, 14)
            size = random.choice((1, 2, 2))
            all_points.append((x, y, size))

    # 轮廓
    for x, y in self._points:
        x, y = self.calc_position(x, y, ratio)
        size = random.randint(1, 3)
        all_points.append((x, y, size))

    # 内容
    for x, y in self._edge_diffusion_points:
        x, y = self.calc_position(x, y, ratio)
        size = random.randint(1, 2)
        all_points.append((x, y, size))

    for x, y in self._center_diffusion_points:
        x, y = self.calc_position(x, y, ratio)
        size = random.randint(1, 2)
        all_points.append((x, y, size))

    self.all_points[generate_frame] = all_points
  • ratio:通过 curve 函数生成一个随时间(帧数)变化的比例,用于让爱心有周期性的呼吸(脉动)效果。
  • 光环:随机生成多个光环点,通过 shrink 函数缩小,使这些点围绕在爱心外部。同时给这些点加上随机抖动和大小。
  • 轮廓、边缘扩散、中心扩散:分别对这三类点调用 calc_position 进行缩放和调整,生成每一帧中对应的点数据。

5. 渲染函数render 方法):

def render(self, render_canvas, render_frame):
    for x, y, size in self.all_points[render_frame % self.generate_frame]:
        render_canvas.create_rectangle(x, y, x + size, y + size, width=0, fill=HEART_COLOR)
  • render_frame:根据帧数选择合适的点进行绘制。
  • create_rectangle(x, y, x + size, y + size):通过绘制小矩形模拟每个点的位置和大小,实现爱心的形状和效果。

该方法循环绘制每帧预先计算好的点,并基于帧数进行切换,产生动画效果。

  • 这个 Heart 类构建了一个多层次的动态爱心动画,通过光环、边缘和中心的扩散效果让爱心更加生动。
  • 每帧的点坐标由多种效果组合而成,生成了不断“呼吸”与“脉动”的视觉体验。

4.添加背景音乐

为了让整个项目更加生动有趣,我们将加入背景音乐。使用 pygame 模块可以方便地播放音频文件。在此之前需要安装 pygame:

pip install pygame

然后,我们可以通过以下代码加载和播放背景音乐:

import pygame

def play_background_music():
    pygame.mixer.init()  # 初始化音频播放器
    pygame.mixer.music.load("background_music.mp3")  # 加载音乐文件
    pygame.mixer.music.play(-1)  # 循环播放音乐

最后将背景音乐播放函数放置在程序的启动部分,确保在绘制爱心时播放背景音乐:

if __name__ == '__main__':
	play_background_music()
    root = Tk()
    root.title('Beating Heart Animation')
    canvas = Canvas(root, bg='black', height=CANVAS_HEIGHT, width=CANVAS_WIDTH)
    canvas.pack()
    heart = Heart()
    draw_animation(root, canvas, heart)
    # Add text to the center of the heart
    Label(root, text="XXX", bg="black", fg="#FF69B4").place(relx=.5, rely=.5, anchor=CENTER)
    # Add text above the heart
    Label(root, text="XXX XXX", bg="black", fg="#FF69B4", font=('宋体', 18)).place(relx=.50, rely=.1, anchor=CENTER)
    root.mainloop()

5.整体代码展示

import random
from math import sin, cos, pi, log
from tkinter import *
import pygame

CANVAS_WIDTH = 640  # Width of the canvas
CANVAS_HEIGHT = 480  # Height of the canvas
CANVAS_CENTER_X = CANVAS_WIDTH / 2  # X coordinate of the canvas center
CANVAS_CENTER_Y = CANVAS_HEIGHT / 2  # Y coordinate of the canvas center
IMAGE_ENLARGE_FACTOR = 11  # Enlargement factor
HEART_COLOR = "#FF69B4"  # Heart color



def play_background_music():
    pygame.mixer.init()  # 初始化音频播放器
    pygame.mixer.music.load("background_music.mp3")  # 加载音乐文件
    pygame.mixer.music.play(-1)  # 循环播放音乐

def generate_heart_coordinates(t, scale_factor: float = IMAGE_ENLARGE_FACTOR):
    """
    Generates coordinates for the heart shape.
    :param scale_factor: Enlargement factor
    :param t: Parameter
    :return: Coordinates
    """
    # Base function for heart shape
    x = 16 * (sin(t) ** 3)
    y = -(13 * cos(t) - 5 * cos(2 * t) - 2 * cos(3 * t) - cos(4 * t))

    # Scale
    x *= scale_factor
    y *= scale_factor

    # Center the coordinates on the canvas
    x += CANVAS_CENTER_X
    y += CANVAS_CENTER_Y

    return int(x), int(y)


def random_diffusion(x, y, strength=0.15):
    """
    Random diffusion effect inside the heart.
    :param x: Original x
    :param y: Original y
    :param strength: Intensity
    :return: New coordinates
    """
    ratio_x = - strength * log(random.random())
    ratio_y = - strength * log(random.random())

    dx = ratio_x * (x - CANVAS_CENTER_X)
    dy = ratio_y * (y - CANVAS_CENTER_Y)

    return x - dx, y - dy


def apply_shrink_effect(x, y, ratio):
    """
    Apply shaking effect.
    :param x: Original x
    :param y: Original y
    :param ratio: Ratio
    :return: New coordinates
    """
    force = -1 / (((x - CANVAS_CENTER_X) ** 2 + (y - CANVAS_CENTER_Y) ** 2) ** 0.6)  # Magic parameter
    dx = ratio * force * (x - CANVAS_CENTER_X)
    dy = ratio * force * (y - CANVAS_CENTER_Y)
    return x - dx, y - dy


def oscillate(p):
    """
    Custom oscillation function to adjust the heartbeat cycle.
    :param p: Parameter
    :return: Sine value
    """
    return 2 * (2 * sin(4 * p)) / (2 * pi)


class Heart:
    """
    Heart shape class.
    """

    def __init__(self, frames_to_generate=20):
        self._original_points = set()  # Set of original heart coordinates
        self._edge_diffusion_points = set()  # Set of edge diffusion effect points
        self._center_diffusion_points = set()  # Set of center diffusion effect points
        self.all_points = {
    
    }  # Dynamic point coordinates for each frame
        self.build_heart(2000)

        self.random_halo = 1000

        self.frames_to_generate = frames_to_generate
        for frame in range(frames_to_generate):
            self.calculate_frame(frame)

    def build_heart(self, number_of_points):
        # Create the heart shape
        for _ in range(number_of_points):
            t = random.uniform(0, 2 * pi)  # Random gaps in the heart shape
            x, y = generate_heart_coordinates(t)
            self._original_points.add((x, y))

        # Edge diffusion
        for _x, _y in list(self._original_points):  # Traverse heart outline points
            for _ in range(3):  # Generate 3 diffusion points for each outline point
                x, y = random_diffusion(_x, _y, 0.05)  # Slight random scattering
                self._edge_diffusion_points.add((x, y))  # Add to edge diffusion set

        # Center diffusion
        point_list = list(self._original_points)  # Convert outline points to list
        for _ in range(6000):  # Generate 6000 center diffusion points
            x, y = random.choice(point_list)  # Randomly select an outline point
            x, y = random_diffusion(x, y, 0.17)  # Larger scattering around the selected point
            self._center_diffusion_points.add((x, y))  # Add to center diffusion set

    @staticmethod
    def calculate_position(x, y, ratio):
        # Adjust the scale factor
        force = 1 / (((x - CANVAS_CENTER_X) ** 2 + (y - CANVAS_CENTER_Y) ** 2) ** 0.520)  # Magic parameter

        dx = ratio * force * (x - CANVAS_CENTER_X) + random.randint(-1, 1)
        dy = ratio * force * (y - CANVAS_CENTER_Y) + random.randint(-1, 1)

        return x - dx, y - dy

    def calculate_frame(self, frame_index):
        ratio = 10 * oscillate(frame_index / 10 * pi)  # Smooth scaling ratio
        # Halo radius
        halo_radius = int(4 + 6 * (1 + oscillate(frame_index / 10 * pi)))
        # Number of halo points
        halo_point_count = int(3000 + 4000 * abs(oscillate(frame_index / 10 * pi) ** 2))

        all_points = []

        # Halo points
        heart_halo_points = set()  # Set of halo point coordinates
        for _ in range(halo_point_count):
            t = random.uniform(0, 4 * pi)  # Random gaps in the heart shape
            x, y = generate_heart_coordinates(t, scale_factor=11.5)  # Magic parameter
            x, y = apply_shrink_effect(x, y, halo_radius)
            if (x, y) not in heart_halo_points:
                # Process new points
                heart_halo_points.add((x, y))
                x += random.randint(-14, 14)
                y += random.randint(-14, 14)
                size = random.choice((1, 2, 2))
                all_points.append((x, y, size))

        for x, y in self._original_points:
            x, y = self.calculate_position(x, y, ratio)
            size = random.randint(1, 3)
            all_points.append((x, y, size))

        for x, y in self._edge_diffusion_points:
            x, y = self.calculate_position(x, y, ratio)
            size = random.randint(1, 2)
            all_points.append((x, y, size))

        for x, y in self._center_diffusion_points:
            x, y = self.calculate_position(x, y, ratio)
            size = random.randint(1, 2)
            all_points.append((x, y, size))

        self.all_points[frame_index] = all_points

    def render(self, render_canvas, render_frame):
        for x, y, size in self.all_points[render_frame % self.frames_to_generate]:
            render_canvas.create_rectangle(x, y, x + size, y + size, width=0, fill=HEART_COLOR)


def draw_animation(main: Tk, render_canvas: Canvas, heart: Heart, frame_index=0):
    render_canvas.delete('all')
    heart.render(render_canvas, frame_index)
    main.after(160, draw_animation, main, render_canvas, heart, frame_index + 1)


if __name__ == '__main__':
	play_background_music()
    root = Tk()
    root.title('Beating Heart Animation')
    canvas = Canvas(root, bg='black', height=CANVAS_HEIGHT, width=CANVAS_WIDTH)
    canvas.pack()
    heart = Heart()
    draw_animation(root, canvas, heart)
    # Add text to the center of the heart
    Label(root, text="XXX", bg="black", fg="#FF69B4").place(relx=.5, rely=.5, anchor=CENTER)
    # Add text above the heart
    Label(root, text="XXX XXX", bg="black", fg="#FF69B4", font=('宋体', 18)).place(relx=.50, rely=.1, anchor=CENTER)
    root.mainloop()

6.效果展示

在这个项目中,我们实现了一个动态跳动的爱心,通过精巧的代码逻辑与图形绘制相结合,展现出令人心动的视觉效果。每当程序运行时,爱心形状在画布上以优雅的方式跳动,仿佛在传达着深情的讯息。

  1. 生动的心形轮廓:利用数学函数生成爱心的轮廓,展现出经典的心形图案。我们通过参数化的方式,使爱心在画布中央稳稳地展示,配合随机化的特性,增添了自然流畅的感觉。

  2. 内部扩散效果:在爱心的边缘和中心,增加了内部扩散的点,这些点在跳动的过程中随机变化,产生了温柔的动态效果,仿佛心中涌动着的爱意不断向外散发。

  3. 周期性的跳动:使用正弦波函数调整跳动的节奏,使爱心的跳动看起来更加自然。这个动态效果不仅仅是简单的上下移动,而是通过精心设计的曲线,使爱心的运动既有力量又富有美感。

  4. 光环效果:在爱心周围,添加了光环效果,通过随机化的点和色彩,使整个图像更加生动、梦幻。光环随着心跳的频率而变化,营造出一种温暖而浪漫的氛围。

  5. 个性化文本:在爱心的中央,我们添加了个性化的文本,进一步提升了整体效果,使得这不仅是一个简单的动画,更是表达情感的载体。无论是情人节的祝福,还是对爱的宣言,这样的设计都为它增添了情感的深度。

在这里插入图片描述
通过这段代码,我们不仅展示了如何利用Python实现动态可视化,更传达了编程背后的情感与创意。
这个跳动的爱心不仅是技术的展示,更是对爱与美的深刻理解。希望它能带给你温暖与灵感,让我们一起在编程的世界中,感受爱的节奏!

猜你喜欢

转载自blog.csdn.net/qq_51447436/article/details/142422612