Python跳动的爱心

跳动的爱心

系列专栏

系列文章

写在前面

Python语言实现李峋同款可写字版跳动的爱心的完整代码。

技术需求

  1. Tkinter 图形用户界面 (GUI) 开发

    • 使用 tkinter 库创建窗口、按钮、标签和绘图画布等 GUI 元素。
    • 通过 Canvas 实现动态绘图,展示爱心的跳动动画。
    • 使用窗口事件处理(如 protocol 绑定窗口关闭事件)增加交互性。
  2. 数学函数绘图

    • 通过参数方程 heart_function 描绘心形轮廓,利用正弦和余弦函数生成坐标点。
    • 应用数学缩放和偏移操作调整爱心的大小和位置。
  3. 随机生成与散点模拟

    • 使用 random 模块实现随机数生成,制造爱心边缘和中心的扩散效果,增加视觉表现力。
    • 利用随机分布和对数变换 (scatter_inside) 模拟爱心扩散区域的自然感。
  4. 动态动画渲染

    • 通过递归调用 after 方法实现帧刷新,生成连续动态效果。
    • 在每一帧中动态计算并绘制不同的点,模拟爱心跳动的视觉效果。
  5. 点的力场模拟

    • 使用力场模型 (calc_positionshrink) 模拟坐标点的运动轨迹,制造扩散和收缩的动态效果。
    • 根据点到心形中心的距离计算力的大小和方向,增加动画的物理感。
  6. 交互逻辑设计

    • 设置“同意”和“拒绝”按钮,配合弹窗提示,实现趣味性互动。
    • 通过点击事件触发心形动画,提升用户体验。
  7. 视觉样式和文字布局

    • 使用画布背景色、字体样式和颜色(如 heartcolor)增强界面美感。
    • 利用 Label 元素和 place 方法精确放置文字在窗口中心。
  8. 模块化与类设计

    • 封装了一个 Heart 类,专门负责爱心的点生成、动态计算和渲染,逻辑清晰、结构化强。
    • calc 方法和 render 方法分别负责帧计算与绘制,职责分离,便于维护。

完整代码

import tkinter as tk
import tkinter.messagebox
import random
from math import sin, cos, pi, log
from tkinter.constants import *

width = 888
height = 500
heartx = width / 2
hearty = height / 2
side = 11
heartcolor = "pink"  # 爱心颜色,可修改
word = "I Love You!"  # 想要写的字,可修改

# 爱心类
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))

    @staticmethod
    def calc_position(x, y, ratio):
        force = 1 / (((x - heartx) ** 2 + (y - hearty) ** 2) ** 0.520)  # 魔法参数
        dx = ratio * force * (x - heartx) + random.randint(-1, 1)
        dy = ratio * force * (y - hearty) + 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=heartcolor)


def heart_function(t, shrink_ratio: float = side):
    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 += heartx
    y += hearty
    return int(x), int(y)


……

代码分析

这段代码是一个基于Python的Tkinter模块实现的互动式程序,主题是通过跳动的爱心动画来表达浪漫情感。以下从代码结构、主要功能模块、核心算法以及实现技巧等方面进行详细分析。


一、代码结构概览

代码结构清晰且功能分明,大致可以分为以下几个模块:

  1. 界面初始化与互动逻辑
    • 负责创建主窗口、弹出消息框,并引导用户进入爱心动画。
  2. 核心类 Heart
    • 负责爱心形状的坐标计算、动态扩散效果以及动画帧的生成。
  3. 数学函数与工具方法
    • 通过数学公式绘制爱心,并为动态效果提供支持。
  4. 动画渲染与绘制
    • 实现爱心形状的动态跳动,并在窗口中绘制动画。
  5. 主函数
    • 程序入口,负责引导用户操作。

二、核心功能分析

1. 用户交互界面

代码开头定义了一个简单的交互界面,用于向用户表达“求婚”意图:

root = tk.Tk()
root.title('❤')
root.resizable(0, 0)
root.wm_attributes("-toolwindow", 1)
  • 界面标题:通过 root.title('❤'),设置窗口标题为心形符号,增添浪漫氛围。
  • 窗口属性root.resizable(0, 0) 禁止调整窗口大小,root.wm_attributes("-toolwindow", 1) 将窗口设置为工具窗口样式。
  • 交互按钮
    • 好哦 按钮绑定了 OK 方法,表示用户同意并进入动画界面。
    • 不要 按钮绑定了 NO 方法,通过消息框提示用户“再给你一次机会”,强调必须点击同意才可继续。
    • 窗口关闭事件绑定到 closeWindow 方法,提示“逃避是没有用的哦”,进一步增强互动趣味性。

这部分代码设计了一个趣味性较强的“无法拒绝”的场景,为后续爱心动画营造铺垫。


2. 爱心动画的数学原理

(1)爱心函数 heart_function
  • 该函数利用参数方程绘制爱心,t 是参数范围,shrink_ratio 用于控制缩放比例。
  • 数学方程细节:
    • 横坐标公式:16 * (sin(t) ** 3),通过三次方正弦曲线,确保爱心左右对称。
    • 纵坐标公式:复杂的余弦叠加公式控制上下轮廓,使其具有自然的心形曲线。
(2)散点效果 scatter_inside
  • 功能:在给定点 (x, y) 的基础上生成随机散点,模拟边缘和中心扩散效果。
  • 原理
    • 利用随机数 random.random() 和对数函数 log 实现随机偏移,beta 控制偏移范围。
    • 偏移量根据距离中心点 (heartx, hearty) 的距离计算,呈现一种逐渐扩散的视觉效果。
(3)缩放函数 shrink
  • 用于模拟爱心外边缘的扩散光环。
  • 核心思想是通过引力公式,计算点向中心偏移的量,从而生成光晕效果。

3. 动态效果实现

(1)动态点计算
  • 动态缩放比例 ratio 控制爱心的跳动,curve 函数生成平滑周期曲线,带来呼吸般的效果。
(2)光晕生成
  • 光晕点以随机角度 t 和缩放比生成。
  • halo_number 随动态曲线调整,控制光晕点数量的变化。

4. 渲染与动画

(1)渲染实现
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=heartcolor)
  • 将动态点按帧渲染到 Canvas 画布上,通过循环绘制心形、扩散光晕和动态点。
(2)动画绘制
def draw(main: tk.Tk, render_canvas: tk.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)
  • main.after() 定时调用,使每帧间隔160ms,带来平滑的跳动效果。
  • render_frame 累加控制帧动画。

5. 爱心动画界面

进入动画后,窗口被设置为全屏效果:

root.geometry("%dx%d+%d+%d" % (width, height, x, y))
canvas = tk.Canvas(root, bg='black', height=height, width=width)
tk.Label(root, text=word, bg="black", fg="#FF99CC", font="Helvetic 25 bold").place(relx=.5, rely=.5, anchor=CENTER)
  • 黑色背景衬托粉色爱心。
  • 文本通过 tk.Label 居中显示,突出视觉中心。

三、总结

这段代码巧妙结合了数学公式和Tkinter界面功能,通过动态光效和跳动爱心的动画,生动地表达浪漫情感。亮点包括:

  1. 爱心函数:复杂的数学方程带来完美的心形曲线。
  2. 动态扩散效果:散点生成与光晕模拟为动画增添层次感。
  3. 人性化交互:有趣的“无法拒绝”逻辑增添趣味性。

通过这些实现,代码展示了Python在动态动画和界面设计中的强大能力,同时通过精心设计的互动流程和细腻的动画效果,完美达成情感表达的目标。

写在后面

我是一只有趣的兔子,感谢你的喜欢!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Want595

感谢小伙伴的支持!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值