在编程的世界里,复杂的技术可以与艺术产生美妙的碰撞。无论是通过代码实现动态效果,还是用算法绘制图案,程序员都可以成为数字艺术的创作者。而今天,我们将通过 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) 分别定义了心形的横坐标和纵坐标。
- sin 和 cos 函数的组合定义了心形的轮廓,使其看起来饱满且对称。
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())⋅(x−CANVAS_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())⋅(y−CANVAS_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=−((x−CANVAS_CENTER_X)2+(y−CANVAS_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−(ratio⋅force⋅(x−CANVAS_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−(ratio⋅force⋅(y−CANVAS_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)=2⋅2π2⋅sin(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)=2⋅2π2⋅sin(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
:根据点离中心的距离计算力(缩放因子),越远的点,受到的力越小,使得远离中心的点缩小得更少。dx
和dy
:调整后的坐标变化量,基于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.效果展示
在这个项目中,我们实现了一个动态跳动的爱心,通过精巧的代码逻辑与图形绘制相结合,展现出令人心动的视觉效果。每当程序运行时,爱心形状在画布上以优雅的方式跳动,仿佛在传达着深情的讯息。
-
生动的心形轮廓:利用数学函数生成爱心的轮廓,展现出经典的心形图案。我们通过参数化的方式,使爱心在画布中央稳稳地展示,配合随机化的特性,增添了自然流畅的感觉。
-
内部扩散效果:在爱心的边缘和中心,增加了内部扩散的点,这些点在跳动的过程中随机变化,产生了温柔的动态效果,仿佛心中涌动着的爱意不断向外散发。
-
周期性的跳动:使用正弦波函数调整跳动的节奏,使爱心的跳动看起来更加自然。这个动态效果不仅仅是简单的上下移动,而是通过精心设计的曲线,使爱心的运动既有力量又富有美感。
-
光环效果:在爱心周围,添加了光环效果,通过随机化的点和色彩,使整个图像更加生动、梦幻。光环随着心跳的频率而变化,营造出一种温暖而浪漫的氛围。
-
个性化文本:在爱心的中央,我们添加了个性化的文本,进一步提升了整体效果,使得这不仅是一个简单的动画,更是表达情感的载体。无论是情人节的祝福,还是对爱的宣言,这样的设计都为它增添了情感的深度。
通过这段代码,我们不仅展示了如何利用Python实现动态可视化,更传达了编程背后的情感与创意。
这个跳动的爱心不仅是技术的展示,更是对爱与美的深刻理解。希望它能带给你温暖与灵感,让我们一起在编程的世界中,感受爱的节奏!