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

在编程的世界里,复杂的技术可以与艺术产生美妙的碰撞。无论是通过代码实现动态效果,还是用算法绘制图案,程序员都可以成为数字艺术的创作者。而今天,我们将通过 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 = 1000self.generate_frame = generate_framefor 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 pygamedef 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 heartLabel(root, text="XXX", bg="black", fg="#FF69B4").place(relx=.5, rely=.5, anchor=CENTER)# Add text above the heartLabel(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 pygameCANVAS_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 colordef 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 shapex = 16 * (sin(t) ** 3)y = -(13 * cos(t) - 5 * cos(2 * t) - 2 * cos(3 * t) - cos(4 * t))# Scalex *= scale_factory *= scale_factor# Center the coordinates on the canvasx += CANVAS_CENTER_Xy += CANVAS_CENTER_Yreturn 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 - dydef 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 parameterdx = ratio * force * (x - CANVAS_CENTER_X)dy = ratio * force * (y - CANVAS_CENTER_Y)return x - dx, y - dydef 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 coordinatesself._edge_diffusion_points = set()  # Set of edge diffusion effect pointsself._center_diffusion_points = set()  # Set of center diffusion effect pointsself.all_points = {}  # Dynamic point coordinates for each frameself.build_heart(2000)self.random_halo = 1000self.frames_to_generate = frames_to_generatefor frame in range(frames_to_generate):self.calculate_frame(frame)def build_heart(self, number_of_points):# Create the heart shapefor _ in range(number_of_points):t = random.uniform(0, 2 * pi)  # Random gaps in the heart shapex, y = generate_heart_coordinates(t)self._original_points.add((x, y))# Edge diffusionfor _x, _y in list(self._original_points):  # Traverse heart outline pointsfor _ in range(3):  # Generate 3 diffusion points for each outline pointx, y = random_diffusion(_x, _y, 0.05)  # Slight random scatteringself._edge_diffusion_points.add((x, y))  # Add to edge diffusion set# Center diffusionpoint_list = list(self._original_points)  # Convert outline points to listfor _ in range(6000):  # Generate 6000 center diffusion pointsx, y = random.choice(point_list)  # Randomly select an outline pointx, y = random_diffusion(x, y, 0.17)  # Larger scattering around the selected pointself._center_diffusion_points.add((x, y))  # Add to center diffusion set@staticmethoddef calculate_position(x, y, ratio):# Adjust the scale factorforce = 1 / (((x - CANVAS_CENTER_X) ** 2 + (y - CANVAS_CENTER_Y) ** 2) ** 0.520)  # Magic parameterdx = 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 - dydef calculate_frame(self, frame_index):ratio = 10 * oscillate(frame_index / 10 * pi)  # Smooth scaling ratio# Halo radiushalo_radius = int(4 + 6 * (1 + oscillate(frame_index / 10 * pi)))# Number of halo pointshalo_point_count = int(3000 + 4000 * abs(oscillate(frame_index / 10 * pi) ** 2))all_points = []# Halo pointsheart_halo_points = set()  # Set of halo point coordinatesfor _ in range(halo_point_count):t = random.uniform(0, 4 * pi)  # Random gaps in the heart shapex, y = generate_heart_coordinates(t, scale_factor=11.5)  # Magic parameterx, y = apply_shrink_effect(x, y, halo_radius)if (x, y) not in heart_halo_points:# Process new pointsheart_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_pointsdef 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 heartLabel(root, text="XXX", bg="black", fg="#FF69B4").place(relx=.5, rely=.5, anchor=CENTER)# Add text above the heartLabel(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实现动态可视化,更传达了编程背后的情感与创意。
这个跳动的爱心不仅是技术的展示,更是对爱与美的深刻理解。希望它能带给你温暖与灵感,让我们一起在编程的世界中,感受爱的节奏!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/1541725.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

U-Boot顶层Makefile详解

直接参考【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.81 本文仅作为个人笔记使用,方便进一步记录自己的实践总结。 上一章我们详细的讲解了 uboot 的使用方法,其实就是各种命令的使用,学会 uboot 使用以后就可以尝试移植 uboot 到自己的开发…

linux操作系统的基本命令

1.linux下的文件系统 在linux操作目录下没有像window操作系统下盘符的概念,只有一个根目录/,所有文件目录都在它的下面 linux的目录结构: 在Linux系统中: 文件都从跟目录开始的,用/表示文件名称区分大小写路径都是以/俩进行分隔(windown用\分隔)以.开头的文件为隐藏文件 Li…

鸿蒙开发之ArkUI 界面篇 十七 购物综合案例

layoutWeight:子元素与兄弟元素主轴方向按照权重进行分配,参数是联合类型,数字或者是字符串,在指定的空间占多少份额,数字越大,表示在空间中占用的份额越多,如果父容器的子组件没有别的指定,剩下的空间全部…

10分钟一条童装走秀爆款Ai视频,小白轻松上手,新蓝海赛道,竞争小机会多!

今天我要给大家带来一个超级有趣的项目——童装走秀AI视频制作。 这不仅是一个充满创意的项目,而且操作简单,即使是视频制作的新手也能轻松上手。 更重要的是,这个项目竞争小,变现机会多,是进入新蓝海赛道的绝佳机会…

C++类之set与get理解

在类中,我们尝尝将一些变量设置为private或者protect里面,而我们经常会遇到在主函数(main.cpp)使用到这些private变量,而往往我们会下意识地在主函数直接调用在private里面的变量,但现实比较残酷&#xff0…

【linux】nice命令

Linux中的nice命令是一个强大的工具,用于调整进程的优先级,进而影响它们在CPU上的资源分配和执行顺序。以下是关于nice命令的详细解释,包括其用途、语法、参数、示例以及使用建议。 一、用途 nice命令主要用于控制进程在CPU上的调度优先级&…

K8S介绍+集群部署

Kubernetes介绍 官网:https://kubernetes.io/ 一、应用部署方式演变 1、传统部署:互联网早期,会直接将应用程序部署在物理机上 优点:简单,不需要其他技术的参与 缺点:不能为应用程序定义资源使用边界&a…

【论文笔记】BEVNeXt: Reviving Dense BEV Frameworks for 3D Object Detection

原文链接:https://arxiv.org/pdf/2312.01696 简介:最近,在摄像头3D目标检测任务中,基于查询的Transformer解码器正在超越传统密集BEV方法。但密集BEV框架有着更好的深度估计和目标定位能力,能全面精确地描绘3D场景。本…

初始网络编程(下)

所属专栏:Java学习 1. TCP 的简单示例 同时,由于 TCP 是面向字节流的传输,所以说传输的基本单位是字节,接受发送都是使用的字节流 方法签名 方法说明 Socket accept() 开始监听指定端口(创建时绑定的端口&…

Navicat导入Sql文件至Mysql数据库,事务失效

Mysql 版本:8.0.39 Navicat 版本:17.x、16.x 结论: Navicat 导入sql文件,事务不会生效,无论怎么设置 mysql.exe 导入sql文件,事务生效 测试 准备一张表 name约束不能为空,用于测试事务失败…

SpringBoot 整合 Caffeine 实现本地缓存

目录 1、Caffeine 简介1.1、Caffeine 简介1.2、对比 Guava cache 的性能主要优化项1.3、常见的缓存淘汰算法1.4、SpringBoot 集成 Caffeine 两种方式 2、SpringBoot 集成 Caffeine 方式一2.1、缓存加载策略2.1.1、手动加载2.1.2、自动加载【Loading Cache】2.1.3、异步加载【As…

7、论等保的必要性

数据来源:7.论等保的必要性_哔哩哔哩_bilibili 等级保护必要性 降低信息安全风险 等级保护旨在降低信息安全风险,提高信息系统的安全防护能力。 风险发现与整改 开展等级保护的最重要原因是通过测评工作,发现单位系统内外部的安全风险和脆弱…

Linux启动流程,0,1,2进程,init进程,idle进程,内核态到用户态的kernel_execve(一)

?是,如果定义了,就按Makefile的,如果如下make编译时,就按如下 linux内核入口 进程0在用户空间看不到,因为他是内核进程 进程2就是守护进程,维护内涵运转的 一生二,二生三&#xff…

Navicate 链接Oracle 提示 Oracle Library is not loaded ,账号密码都正确地址端口也对

Navicate 链接Oracle 提示 Oracle Library is not loaded ,账号密码都正确地址端口也对的问题 解决办法 出现 Oracle Library is not loaded 错误提示,通常是因为 Navicat 无法找到或加载 Oracle 客户端库(OCI.dll)。要解决这个问题&#x…

IntelliJ IDEA 2024.1.4 (Ultimate Edition)找不到Add Framework Support解决方法

目录 背景: 解决方法: 步骤1: 步骤2: 步骤3: 创建Web项目的完整流程: 步骤1: 步骤2: 步骤3: 步骤4: Web优点: 背景: 我的IDE版本是IntelliJ IDEA 2024.1.4 (Ultimate Edition),当我…

Java调用数据库 笔记05(查询篇)

一. 数据库(通过各种驱动来实现调用): (应用程序通过接口控制的各种数据库驱动来调用数据库-->jdbc方法) 1.创建Java的普通class类 2.加载驱动 Class.forName("com.mysql.jdbc.Driver"); 3.驱动管理类…

nginx upstream转发连接错误情况研究

本次测试用到3台服务器: 192.168.10.115:转发服务器A 192.168.10.209:upstream下服务器1 192.168.10.210:upstream下服务器2 1台客户端:192.168.10.112 服务器A中nginx主要配置如下: log_format main…

C++之职工管理系统(细节Q)

指针初始化类 && 普通变量初始化类 抽象基类worker,只需编写 .h ,无需 .cpp 底层实现 类 记得声明权限public!!!不然默认private,主函数访问不了 记得继承父类 Worker * worker:指向Wo…

山东潍坊戴尔存储服务器维修 md3800f raid恢复

山东戴尔存储故障维修 存储型号:DELL PowerVault md3800f 故障问题:存储除尘后通电开机,发现有物理硬盘没有插到位,用户带电拔插了多块物理盘,导致关连的磁盘阵列掉线,卷失败; 处理方式&#xf…

RK3588/RK3588s运行yolov8达到27ms

前言 Hello,小伙伴们~~我最近做了一个比较有意思的东西,想起来也好久没有写博客了,就记录一下吧。希望和大家一起学习,一起进步! 我简单介绍一下我最近做的这个东西的经过哈~上个月在B站上看到了一个博主发了一条视频关…