Python:生成表白爱心动画(程序的优化与打包)

目录

效果预览

功能的实现

优化内容

完整代码

性能分析


效果预览

程序参考于:python 爱心代码-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/weixin_74994771/article/details/137294470?spm=1000.2115.3001.6382&utm_medium=distribute.pc_feed_v2.none-task-blog-hot-11-137294470-null-null.329%5Ev9%5E%E4%B8%AA%E6%8E%A8pc%E9%A6%96%E9%A1%B5%E6%8E%A8%E8%8D%90%E2%80%94%E6%A1%B67&depth_1-utm_source=distribute.pc_feed_v2.none-task-blog-hot-11-137294470-null-null.329%5Ev9%5E%E4%B8%AA%E6%8E%A8pc%E9%A6%96%E9%A1%B5%E6%8E%A8%E8%8D%90%E2%80%94%E6%A1%B67

打包的exe文件:pyhton实现的爱心动画exe文件资源-CSDN文库icon-default.png?t=N7T8https://download.csdn.net/download/YYKand/89117257

功能的实现

优化内容

        1.使用线程

                引入线程,创建线程池。

                将生成光环点、点的偏移放入线程中,提高运行速度

        2.优化计算逻辑

                提前生成随机数,减少在循环中不断生成。

# 计算每一帧的点的方法
    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 = []
        points_to_add = []

        # 预生成随机偏移量和点的大小
        random_offsets = [(random.randint(-14, 14), random.randint(-14, 14)) for _ in range(halo_number)]
        random_sizes = [random.randint(0, 2) for _ in range(halo_number)]

        # 使用线程池并行生成光环点
        def generate_halo_points(halo_number, random_offsets, ratio, halo_radius, all_points):
            heart_halo_point = set()    # 生成光环点的集合
            for i 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_offset, y_offset = random_offsets[i]
                    x += x_offset
                    y += y_offset
                    size = random_sizes[i]
                    all_points.append((x, y, size))

            # 生成轮廓、边缘扩散点和中心扩散点
            for x, y in self._points:
                x, y = self.calc_position(x, y, ratio)
                size = random.randint(0, 2)
                points_to_add.append((x, y, size))

            for x, y in self._edge_diffusion_points:
                x, y = self.calc_position(x, y, ratio)
                size = random.randint(0, 2)
                points_to_add.append((x, y, size))

            for x, y in self._center_diffusion_points:
                x, y = self.calc_position(x, y, ratio)
                size = random.randint(0, 2)
                points_to_add.append((x, y, size))

            # 将生成的点添加到 all_points
            all_points.extend(points_to_add)
            self.all_points[generate_frame] = all_points

        # 创建线程池
        with ThreadPoolExecutor(max_workers=1) as executor:
            # 提交光环点生成任务
            executor.submit(generate_halo_points, halo_number, random_offsets, ratio, halo_radius, all_points)
        3.提取变量

                将用户可能需要改动的视觉效果提取出来:字体颜色,文本,刷新帧数(结果测试这个帧数变化效果不大)

HEART_COLOR = "#FF99CC"     # 设置爱心的颜色
TXT_DATE = "I Love You"     # 设置文本内容
TXT_COLOR = "#FF99CC"       # 设置字体颜色
Frames_Number = 20          # 动画刷新的帧数
        4.注释

                更详细的代码注释,方便更多的朋友学习研究使用

完整代码

import random
from math import sin, cos, pi, log
from tkinter import *
from concurrent.futures import ThreadPoolExecutor

CANVAS_WIDTH = 640      # 画布宽度
CANVAS_HEIGHT = 480     # 画布高度
CANVAS_CENTER_X = CANVAS_WIDTH / 2      # 画布中心的x坐标
CANVAS_CENTER_Y = CANVAS_HEIGHT / 2     # 画布中心的y坐标
IMAGE_ENLARGE = 11      # 图像放大的比例

HEART_COLOR = "#FF99CC"     # 设置爱心的颜色
TXT_DATE = "I Love You"     # 设置文本内容
TXT_COLOR = "#FF99CC"       # 设置字体颜色
Frames_Number = 60          # 动画刷新的帧数

# 窗口居中显示的辅助函数
def center_window(root, width, height):
    screenwidth = root.winfo_screenwidth()      # 获取显示屏宽度
    screenheight = root.winfo_screenheight()    # 获取显示屏高度
    size = '%dx%d+%d+%d' % (width, height, 
                            (screenwidth - width) /2, 
                            (screenheight - height) / 2)  # 设置窗口居中参数
    root.geometry(size)                         # 让窗口居中显示

# 定义计算爱心形状的函数
def heart_function(t, shrink_ratio: float = IMAGE_ENLARGE):
    # 使用参数t计算爱心形状的x和y坐标,并根据缩放比例进行缩放
    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)

# 在爱心内部根据beta值生成随机点
def scatter_inside(x, y, beta=0.15):
    # 根据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

# 定义缩小点的函数
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

# 定义曲线函数
def curve(p):
    return 2 * (2 * sin(4 * p)) / (2 * pi)  # 根据参数p计算并返回曲线值

# 定义Heart类,用于生成和渲染爱心形状
class Heart:
    def __init__(self, generate_frame=Frames_Number):       # 初始化方法,生成爱心形状的点集合
        self._points = set()                                # 原始爱心坐标集合
        self._edge_diffusion_points = set()                 # 边缘扩散效果点坐标集合
        self._center_diffusion_points = set()               # 中心扩散效果点坐标集合
        self.all_points = {}                                # 每帧动态点坐标
        self.build(2000)                                    # 构建爱心形状的点集合
        self.random_halo = 500                              # 初始化光环点的数量
        self.generate_frame = generate_frame                # 动画帧数

        for frame in range(generate_frame):                 # 循环计算每一帧的点
            self.calc(frame)

    def build(self, number):                                # 构建爱心形状的点集合的方法
        # 使用heart_function函数生成number个点,构成原始爱心形状
        self._points = {heart_function(random.uniform(0, 2 * pi)) for _ in range(number)}

        # 爱心内扩散,生成边缘扩散效果点坐标集合
        edge_diffusion_points = set()
        for _x, _y in self._points:
            for _ in range(3):
                x, y = scatter_inside(_x, _y, 0.05)
                edge_diffusion_points.add((x, y))
        self._edge_diffusion_points = edge_diffusion_points

        # 爱心内再次扩散,生成中心扩散效果点坐标集合
        center_diffusion_points = set()
        point_list = list(self._points)
        for _ in range(4000):
            x, y = random.choice(point_list)
            x, y = scatter_inside(x, y, 0.17)
            center_diffusion_points.add((x, y))
        self._center_diffusion_points = center_diffusion_points

    # 计算点位置的静态方法
    @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 = []
        points_to_add = []

        # 预生成随机偏移量和点的大小
        random_offsets = [(random.randint(-14, 14), random.randint(-14, 14)) for _ in range(halo_number)]
        random_sizes = [random.randint(0, 2) for _ in range(halo_number)]

        # 使用线程池并行生成光环点
        def generate_halo_points(halo_number, random_offsets, ratio, halo_radius, all_points):
            heart_halo_point = set()    # 生成光环点的集合
            for i 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_offset, y_offset = random_offsets[i]
                    x += x_offset
                    y += y_offset
                    size = random_sizes[i]
                    all_points.append((x, y, size))

            # 生成轮廓、边缘扩散点和中心扩散点
            for x, y in self._points:
                x, y = self.calc_position(x, y, ratio)
                size = random.randint(0, 2)
                points_to_add.append((x, y, size))

            for x, y in self._edge_diffusion_points:
                x, y = self.calc_position(x, y, ratio)
                size = random.randint(0, 2)
                points_to_add.append((x, y, size))

            for x, y in self._center_diffusion_points:
                x, y = self.calc_position(x, y, ratio)
                size = random.randint(0, 2)
                points_to_add.append((x, y, size))

            # 将生成的点添加到 all_points
            all_points.extend(points_to_add)
            self.all_points[generate_frame] = all_points

        # 创建线程池
        with ThreadPoolExecutor(max_workers=1) as executor:
            # 提交光环点生成任务
            executor.submit(generate_halo_points, halo_number, random_offsets, ratio, halo_radius, all_points)

    # 在指定的画布上渲染爱心形状
    def render(self, render_canvas, render_frame):
        frame_key = render_frame % self.generate_frame
        if frame_key in self.all_points:
            points = self.all_points[frame_key]
        else:
            points = []
        for x, y, size in points:
            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)  # 递归调用draw函数以实现动画效果

if __name__ == '__main__':
    root = Tk()
    root.title("爱心")
    root.resizable(0, 0)        # 锁定界面大小
    center_window(root, CANVAS_WIDTH, CANVAS_HEIGHT)  # 窗口居中显示

    canvas = Canvas(root, bg='black', height=CANVAS_HEIGHT, width=CANVAS_WIDTH)     # 创建画布并添加到窗口
    canvas.pack()

    heart = Heart()                 # 创建爱心对象并开始绘制
    draw(root, canvas, heart)       # 调用draw函数开始动画

    # 在画布中心显示文本
    Label(root, 
          text=TXT_DATE, 
          bg="black", 
          fg=TXT_COLOR, 
          font="Helvetic 20 bold").place(relx=.5, rely=.5, anchor=CENTER)
    
    root.mainloop()         # 启动Tkinter事件循环

性能分析

貌似刚刚启动的时候,运行内测会比较高,后面则稳定在40-60MB(可能会因为电脑性能不一致)

相关推荐

  1. 专属于程序员烂漫表白||Python动态爱心

    2024-04-13 06:14:02       44 阅读

最近更新

  1. 前端导出pdf

    2024-04-13 06:14:02       0 阅读
  2. Knife4j的原理及应用详解(五)

    2024-04-13 06:14:02       0 阅读
  3. Day2--每日一练

    2024-04-13 06:14:02       0 阅读
  4. 东方博宜1626 - 暑假的旅游计划

    2024-04-13 06:14:02       0 阅读
  5. react小白面试不得不会的20个问题——第二篇

    2024-04-13 06:14:02       0 阅读
  6. 简单滤波算法伪码

    2024-04-13 06:14:02       0 阅读
  7. Mongodb索引简介

    2024-04-13 06:14:02       0 阅读
  8. Linux 6种日志查看方法

    2024-04-13 06:14:02       0 阅读
  9. 案例研究(Case Study)是什么?怎么写?

    2024-04-13 06:14:02       0 阅读
  10. Linux虚拟化技术:从Xen到KVM

    2024-04-13 06:14:02       0 阅读

热门阅读

  1. HiveSQL基础Day03

    2024-04-13 06:14:02       16 阅读
  2. 通过 Vue 3 组合式 API 优化 Uni-app 基础页面功能

    2024-04-13 06:14:02       43 阅读
  3. YOLOv9:下一代目标检测的革新

    2024-04-13 06:14:02       56 阅读
  4. 傻瓜式远程P2P联机局域网游戏

    2024-04-13 06:14:02       17 阅读
  5. vue3 reactive

    2024-04-13 06:14:02       19 阅读
  6. 【我的代码生成器】React的FrmUser类源码

    2024-04-13 06:14:02       19 阅读