🎉 欢迎阅读程序员的浪漫代码教程!
本文将详细介绍如何使用Python和tkinter库创建一颗会跳动的爱心,包含数学原理、代码分析、运行效果和可执行文件下载,适合Python爱好者和寻找创意代码的程序员。

📝 前言

各位亲爱的程序员朋友们,今天,我要给大家介绍一个神奇的代码项目,它能在你的屏幕上画出一颗会跳动的爱心,而且效果还非常酷炫!

什么?你说你不会画画?没关系,我们有数学!什么?你说你没有艺术细胞?没关系,我们有代码!让我们一起看看,如何用几行代码,创造出属于程序员的浪漫。


📋 目录


🎨 项目介绍

这个项目使用Python的tkinter库创建一个图形界面,通过数学函数生成心形曲线,并添加动画效果使其看起来像一颗跳动的心脏。项目的主要特点包括:

  • 数学驱动:使用经典的心形曲线参数方程生成基本形状
  • 动态效果:爱心会有规律地收缩和膨胀,模拟跳动效果
  • 视觉层次感:通过随机扩散算法生成边缘模糊效果
  • 光晕效果:爱心周围有淡淡的光晕,增强视觉效果
  • 颜色渐变:内芯使用粉色,外层使用红色,形成层次感

🔢 数学原理:心形曲线的生成

心形曲线是如何通过数学公式生成的呢?这里使用了一个经典的心形曲线参数方程:

1
2
3
4
5
6
7
8
def heart_function(t, shrink_ratio=IMAGE_ENLARGE):
x = 16 * (sin(t) ** 3)
y = -(13 * cos(t) - 5 * cos(2 * t) - 2 * cos(3 * t) - cos(4 * t))
x *= shrink_ratio
y *= shrink_ratio
x += CANVAS_CENTER_X
y += CANVAS_CENTER_Y
return int(x), int(y)

这个方程是如何工作的呢?让我们来分解一下:

  1. 参数t:从0到2π变化,遍历心形曲线上的所有点
  2. x坐标计算:使用正弦函数的三次方,形成心形的左右对称结构
  3. y坐标计算:使用多个余弦函数的组合,形成心形的底部尖角和顶部曲线
  4. 缩放和平移:将生成的点放大并移动到画布中心

这种参数方程的优点是计算简单,生成的曲线平滑美观,非常适合用于创建心形图案。


💻 代码分析:爱心是如何跳动的?

1. 扩散效果:让爱心更有层次感

1
2
3
4
5
6
def scatter_points(x, y, beta=SCATTER_BETA):
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

为了让爱心看起来更有层次感,代码使用了随机扩散算法:

  • 使用对数函数生成扩散比例,使得扩散点更集中在心形中心
  • 从基本心形的点向外扩散,生成边缘模糊的效果
  • 这种随机扩散模拟了粒子效果,让爱心看起来更生动

2. 动画效果:让爱心跳动起来

1
2
3
4
5
6
7
8
def curve(p):
return 2 * (3 * sin(4 * p)) / (2 * pi)

def calc(self, generate_frame):
ratio = CURVE_RATIO * 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))
# ... 计算所有点的位置 ...

为了让爱心跳动起来,代码使用了:

  • 一个周期性的正弦曲线函数,模拟心跳的节奏
  • 通过改变参数来调整爱心的大小和光晕效果
  • 随着时间的推移,爱心会有规律地收缩和膨胀

3. 渲染效果:颜色和细节的处理

1
2
3
4
5
6
def render(self, render_canvas, render_frame):
for x, y, size in self.parameters.all_points[render_frame % self.generate_frame]:
if size == 2:
render_canvas.create_rectangle(x, y, x + size, y + size, width=0, fill=INNER_HEART_COLOR)
else:
render_canvas.create_rectangle(x, y, x + size, y + size, width=0, fill=OUTER_HEART_COLOR)

在渲染时,代码:

  • 根据点的大小选择不同的颜色,形成层次感
  • 使用小矩形而不是圆形来绘制点,密集排列时产生更柔和的效果
  • 清除画布并重新绘制每一帧,实现动画效果

📄 完整代码

以下是完整的Python代码,你可以直接复制到本地运行:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
import random 
from math import sin, cos, pi, log
from tkinter import *


# Constants
CANVAS_WIDTH = 640
CANVAS_HEIGHT = 640
CANVAS_CENTER_X = CANVAS_WIDTH / 2
CANVAS_CENTER_Y = CANVAS_HEIGHT / 2
IMAGE_ENLARGE = 11
INNER_HEART_COLOR = "pink"
OUTER_HEART_COLOR = "red"
SCATTER_BETA = 0.15
SHRINK_RATIO = 15
CURVE_RATIO = 10
FRAME_DELAY = 160
NUM_POINTS = 2000
NUM_HALO_POINTS = 3000


class HeartParameters:
def __init__(self):
self.points = set()
self.edge_diffusion_points = set()
self.center_diffusion_points = set()
self.all_points = {}


# Heart function
def heart_function(t, shrink_ratio=IMAGE_ENLARGE):
x = 16 * (sin(t) ** 3)
y = -(13 * cos(t) - 5 * cos(2 * t) - 2 * cos(3 * t) - cos(4 * t))
x *= shrink_ratio
y *= shrink_ratio
x += CANVAS_CENTER_X
y += CANVAS_CENTER_Y
return int(x), int(y)


# Scatter points
def scatter_points(x, y, beta=SCATTER_BETA):
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 points
def shrink_points(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 * (3 * sin(4 * p)) / (2 * pi)


# Heart class
class Heart:
def __init__(self, generate_frame=20):
self.parameters = HeartParameters()
self.generate_frame = generate_frame
self.build(NUM_POINTS)
for frame in range(generate_frame):
self.calc(frame)


def build(self, number):
for _ in range(number):
t = random.uniform(0, 2 * pi)
x, y = heart_function(t)
self.parameters.points.add((x, y))
for _x, _y in list(self.parameters.points):
for _ in range(3):
x, y = scatter_points(_x, _y)
self.parameters.edge_diffusion_points.add((x, y))
point_list = list(self.parameters.points)
for _ in range(NUM_HALO_POINTS):
x, y = random.choice(point_list)
x, y = scatter_points(x, y, 0.17)
self.parameters.center_diffusion_points.add((x, y))


@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


def calc(self, generate_frame):
ratio = CURVE_RATIO * 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, 2 * pi)
x, y = heart_function(t, shrink_ratio=SHRINK_RATIO)
x, y = shrink_points(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.parameters.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.parameters.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.parameters.center_diffusion_points:
x, y = self.calc_position(x, y, ratio)
size = random.randint(1, 2)
all_points.append((x, y, size))
self.parameters.all_points[generate_frame] = all_points


def render(self, render_canvas, render_frame):
for x, y, size in self.parameters.all_points[render_frame % self.generate_frame]:
if size == 2:
render_canvas.create_rectangle(x, y, x + size, y + size, width=0, fill=INNER_HEART_COLOR)
else:
render_canvas.create_rectangle(x, y, x + size, y + size, width=0, fill=OUTER_HEART_COLOR)


def draw(main: Tk, render_canvas: Canvas, render_heart: Heart, render_frame=0):
render_canvas.delete('all')
render_heart.render(render_canvas, render_frame)
main.after(FRAME_DELAY, draw, main, render_canvas, render_heart, render_frame + 1)


if __name__ == '__main__':
root = Tk()
root.title('')
canvas = Canvas(root, bg='black', height=CANVAS_HEIGHT, width=CANVAS_WIDTH)
canvas.pack()
heart = Heart()
draw(root, canvas, heart)
root.mainloop()

🎬 运行效果展示

当你运行这段代码时,你会看到一个黑色的画布上,一颗红色的爱心正在有规律地跳动。爱心的边缘有一些模糊的效果,中心部分则更亮更密集,就像一颗真正的心脏在跳动一样。

而且,爱心的周围还有一些淡淡的光晕,随着爱心的跳动而变化,使得整个效果更加梦幻和浪漫。

🖼️ 界面预览

💾 可执行文件下载

为了方便大家使用,我已经将这个项目打包成了可执行文件,你可以直接下载运行,无需安装Python环境。

📦 下载链接

📋 下载信息

  • 📦 文件大小:约7MB
  • 🖥️ 运行环境:Windows 7及以上版本
  • 🚀 无需安装:下载后直接使用,绿色便捷

使用说明

  1. 下载对应操作系统的可执行文件
  2. 双击运行
  3. 享受跳动的爱心效果
  4. 按窗口关闭按钮退出程序

🚀 扩展和改进

如果你觉得这个爱心还不够酷,或者想要更个性化的效果,你可以尝试以下改进:

1. 颜色自定义

你可以修改INNER_HEART_COLOROUTER_HEART_COLOR变量,使用你喜欢的颜色组合:

1
2
3
4
5
6
7
# 示例:使用紫色和粉色
INNER_HEART_COLOR = "#ff69b4" # 亮粉色
OUTER_HEART_COLOR = "#9370db" # 紫色

# 示例:使用蓝色和青色
INNER_HEART_COLOR = "#00bfff" # 深 sky blue
OUTER_HEART_COLOR = "#00ffff" # 青色

2. 添加文本

你可以在爱心的中心添加一些文字,比如”我爱你”、”Happy Valentine’s Day”,或者你喜欢的人的名字:

1
2
3
# 在draw函数中添加文本
canvas.create_text(CANVAS_CENTER_X, CANVAS_CENTER_Y, text="我爱你",
font=("Arial", 20, "bold"), fill="white")

3. 交互效果

你可以添加鼠标交互,当鼠标点击爱心时,爱心会有特殊的反应:

1
2
3
4
5
6
7
# 添加鼠标点击事件
def on_click(event):
# 点击时改变颜色或大小
global INNER_HEART_COLOR
INNER_HEART_COLOR = random.choice(["pink", "red", "purple", "blue", "green"])

canvas.bind("<Button-1>", on_click)

4. 背景效果

你可以给画布添加一个渐变背景,或者一些星星、雪花等装饰元素:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 示例:添加渐变背景
from tkinter import ttk

# 创建渐变背景
style = ttk.Style()
style.configure("Gradient.TFrame", background="black")

# 或者添加星星效果
def draw_stars(canvas, count=50):
for _ in range(count):
x = random.randint(0, CANVAS_WIDTH)
y = random.randint(0, CANVAS_HEIGHT)
size = random.randint(1, 2)
canvas.create_oval(x, y, x+size, y+size, fill="white")

# 在主函数中调用
draw_stars(canvas)

5. 性能优化

如果你的电脑运行起来有点卡,你可以减少NUM_POINTSNUM_HALO_POINTS的值:

1
2
3
# 降低点的数量以提高性能
NUM_POINTS = 1000 # 从2000减少到1000
NUM_HALO_POINTS = 1500 # 从3000减少到1500

❓ 常见问题及解决方案

问题1:运行时出现模块导入错误

解决方案

  • 确保安装了Python环境(推荐Python 3.6+)
  • tkinter是Python标准库,通常不需要单独安装

问题2:窗口打开后无响应

解决方案

  • 检查电脑性能,较低配置的电脑可能需要更多时间初始化
  • 尝试减少NUM_POINTSNUM_HALO_POINTS的值
  • 确保代码完整复制,没有语法错误

问题3:可执行文件无法运行

解决方案

  • 确保下载了对应操作系统的版本
  • Windows用户可能需要允许来自未知发布者的应用

问题4:爱心大小不合适

解决方案

  • 修改IMAGE_ENLARGE变量的值,增大或减小爱心的整体大小
  • 修改CANVAS_WIDTHCANVAS_HEIGHT变量,调整窗口大小

🎯 总结与资源

项目总结

通过这个项目,我们学习了:

  • 数学应用:如何使用参数方程生成心形曲线
  • Python编程:如何使用tkinter创建图形界面和动画
  • 算法设计:如何使用随机扩散算法生成视觉效果
  • 性能优化:如何调整参数平衡视觉效果和性能
  • 创意表达:如何通过代码创造艺术效果

推荐资源

下一步学习建议

  1. 尝试将这个项目打包成可执行文件,方便分享给朋友
  2. 学习更多关于计算机图形学的知识,创建更复杂的视觉效果
  3. 探索其他数学曲线的生成和可视化
  4. 尝试添加更多交互元素,如声音效果或键盘控制

🎉 学习完成!
通过本文的学习,你已经掌握了如何使用Python和数学知识创建一颗跳动的爱心。希望这个项目能为你带来灵感,展示程序员的创意和浪漫一面!

💖 祝你编码愉快,生活充满爱!