一、项目简介
这是一个用Python语言绘制的动态爱心图案,你❤动了吗?
编译器:PyCharm Community Edition
二、运行截图
三、代码思路
1、引入库文件random、math、tkinter
import random
from math import sin, cos, pi, log
from tkinter import \*
2、设置画布
CANVAS\_WIDTH = 800 #画布宽800
CANVAS\_HEIGHT = 600 #画布长600
CANVAS\_CENTER\_X = CANVAS\_WIDTH / 2
CANVAS\_CENTER\_Y = CANVAS\_HEIGHT / 2
IMAGE\_ENLARGE = 11
HEART\_COLOR = "#dc143c" #ff2121 #引号内为爱心的颜色
3、生成爱心
def heart_function(t, shrink_ratio: float = 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)
4、随机扩散
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
5、抖动
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
6、定义曲线函数和跳动周期
def curve§:
return 5 \* (2 \* sin(4 \* p)) / (2 \* pi)
7、爱心的类
class Heart:
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)
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(4000):
x, y = random.choice(point\_list)
x, y = scatter\_inside(x, y, 0.17)
self.\_center\_diffusion\_points.add((x, y))
8、@classmethod 装饰类方法
@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 = 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, 2 \* pi)
x, y = heart\_function(t, shrink\_ratio=11.6)
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
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)
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(160, draw, main, render\_canvas, render\_heart, render\_frame + 1)
if \_\_name\_\_ == '\_\_main\_\_':
root = Tk() # 一个Tk
root.title("dotcpp.com")
canvas = Canvas(root, bg='black', height=CANVAS\_HEIGHT, width=CANVAS\_WIDTH)
canvas.pack()
heart = Heart()
draw(root, canvas, heart)
root.mainloop()