使用python实现跨年烟花代码

news2024/9/24 3:29:09

朋友们,有多久没放烟花了?今年你所在的地方允许放烟花么?既然我们不能线下放,那么我们就在线上放个够吧(还是那句话:你~有~对~象~了~嘛~)

一下是动态图(图片我使用的我上几次的背景图,大家也可以换成别的哦~但是呢阿玥还是建议用暗色的背景图,会更好看的哟~~~)

目录

基本知识:用Python和Tkinter设计烟花

将烟花绽放转译成代码

使用Tkinter模拟

现在我们将粒子的移动概念化,不过很明显,一个烟花不能只有一个粒子,一场烟花秀也不能只有一个烟花。我们下一步就是让Python和Tkinter以我们可控的方式向天上连续“发射”粒子。



1.Pygame 绘制烟花的基本原理

1、发射阶段:在这一阶段烟花的形状是线性向上,通过设定一组大小不同、颜色不同的点来模拟“向上发射” 的运动运动,运动过程中 5个点被赋予不同大小的加速度,随着时间推移,后面的点会赶上前面的点,最终所有点会汇聚在一起,处于绽放准备阶段。

2、烟花绽放:烟花绽放这个阶段,是由一个点分散多个点向不同方向发散,并且每个点的移动轨迹可需要被记录,目的是为了追踪整个绽放轨迹。

3、烟花凋零,此阶段负责描绘绽放后烟花的效果,绽放后的烟花,而在每一时刻点的下降速度和亮度(代码中也叫透明度)是不一样的,因此在代码里,将烟花绽放后将每个点赋予两个属性:分别为重力向量和生命周期,来模拟烟花在不同时期时不同的展现效果。

首先设置全局变量,例如重力向量,窗口大小,Trail 的颜色列表(多为灰色或白色)以及不同状态下 Trail 之间间隔,gravity设置重力变量,DISPLAY_width和heigh控制窗口的长和宽

基本知识:用Python和Tkinter设计烟花

这里不再一股脑把数学知识全丢出来,我们边写代码边说理论。首先,确保你安装和导入了Tkinter,它是Python的标准 GUI 库,广泛应用于各种各样的项目和程序开发,在Python中使用 Tkinter 可以快速的创建 GUI 应用程序。

import tkinter as tk
from PIL import Image, ImageTk
from time import time, sleep
from random import choice, uniform, randint
from math import sin, cos, radians

除了Tkinter之外,为了能让界面有漂亮的背景,

w = tk.Label(root, text="Hello Tkinter!")

我们也导入PIL用于图像处理,以及导入其它一些包,比如time,random和math。它们能让我们更容易的控制烟花粒子的运动轨迹。

Tkinter应用的基本设置如下:

root = tk.Tk()

为了能初始化Tkinter,我们必须创建一个Tk()根部件(root widget),它是一个窗口,带有标题栏和由窗口管理器提供的其它装饰物。该根部件必须在我们创建其它小部件之前就创建完毕,而且只能有一个根部件。

w = tk.Label(root, text="Hello Tkinter!")

这一行代码包含了Label部件。该Label调用中的第一个参数就是父窗口的名字,即我们这里用的“根”。关键字参数“text”指明显示的文字内容。你也可以调用其它小部件:Button,Canvas等等。

w.pack()
root.mainloop()

接下来的这两行代码很重要。这里的打包方法是告诉Tkinter调整窗口大小以适应所用的小部件。窗口直到我们进入Tkinter事件循环,被root.mainloop()调用时才会出现。在我们关闭窗口前,脚本会一直在停留在事件循环。

将烟花绽放转译成代码

现在我们设计一个对象,表示烟花事件中的每个粒子。每个粒子都会有一些重要的属性,支配了它的外观和移动状况:大小,颜色,位置,速度等等。

'''
创作不易,点个赞再走呗

'''
particles 类
粒子在空中随机生成随机,变成一个圈、下坠、消失
属性:
    - id: 粒子的id
    - x, y: 粒子的坐标
    - vx, vy: 在坐标的变化速度
    - total: 总数
    - age: 粒子存在的时长
    - color: 颜色
    - cv: 画布
    - lifespan: 最高存在时长
'''
class part:
 
    def __init__(self, cv, idx, total, explosion_speed, x=0., y=0., vx = 0., vy = 0., size=2., color = 'red', lifespan = 2, **kwargs):
        self.id = idx
        self.x = x
        self.y = y
        self.initial_speed = explosion_speed
        self.vx = vx
        self.vy = vy
        self.total = total
        self.age = 0self.color = color
        self.cv = cv
        self.cid = self.cv.create_oval(
            x - size, y - size, x + size,
            y + size, fill=self.color)
        self.lifespan = lifespan

如果我们回过头想想最开始的想法,就会意识到必须确保每个烟花绽放的所有粒子必须经过3个不同的阶段,即“膨胀”“坠落”和“消失”。 所以我们向粒子类中再添加一些运动函数,如下所示:

def update(self, dt):
    # 粒子膨胀if self.alive() and self.expand():
        move_x = cos(radians(self.id*360/self.total))*self.initial_speed
        move_y = sin(radians(self.id*360/self.total))*self.initial_speed
        self.vx = move_x/(float(dt)*1000)
        self.vy = move_y/(float(dt)*1000)
        self.cv.move(self.cid, move_x, move_y)
 
    # 以自由落体坠落
    elif self.alive():
        move_x = cos(radians(self.id*360/self.total))
        # we technically don't need to update x, y because move will do the job
        self.cv.move(self.cid, self.vx + move_x, self.vy+GRAVITY*dt)
        self.vy += GRAVITY*dt
    # 如果粒子的生命周期已过,就将其移除
    elif self.cid is not None:
        cv.delete(self.cid)
        self.cid = None

当然,这也意味着我们必须定义每个粒子绽放多久、坠落多久。这部分需要我们多尝试一些参数,才能达到最佳视觉效果。

# 定义膨胀效果的时间帧
def expand (self):
    return self.age <= 1.2
 
# 检查粒子是否仍在生命周期内
def alive(self):
    return self.age <= self.lifespan

使用Tkinter模拟

现在我们将粒子的移动概念化,不过很明显,一个烟花不能只有一个粒子,一场烟花秀也不能只有一个烟花。我们下一步就是让Python和Tkinter以我们可控的方式向天上连续“发射”粒子。

到了这里,我们需要从操作一个粒子升级为在屏幕上展现多个烟花及每个烟花中的多个粒子。

我们的解决思路如下:创建一列列表,每个子列表是一个烟花,其包含一列粒子。每个列表中的例子有相同的x,y坐标、大小、颜色、初始速度。

numb_explode = randint(6,10)
# 为所有模拟烟花绽放的全部粒子创建一列列表
for point in range(numb_explode):
    objects = []
    x_cordi = randint(50,550)
    y_cordi = randint(50, 150)       
    size = uniform (0.5,3)
    color = choice(colors)
    explosion_speed = uniform(0.2, 1)
    total_particles = randint(10,50)
    for i in range(1,total_particles):
        r = part(cv, idx = i, total = total_particles, explosion_speed = explosion_speed, x = x_cordi, y = y_cordi, 
        color=color, size = size, lifespan = uniform(0.6,1.75))
        objects.append(r)
explode_points.append(objects)

我们下一步就是确保定期更新粒子的属性。这里我们设置让粒子每0.01秒更新它们的状态,在1.8秒之后停止更新(这意味着每个粒子的存在时间为1.6秒,其中1.2秒为“绽放”状态,0.4秒为“坠落”状态,0.2秒处于Tkinter将其完全移除前的边缘状态)。

total_time = .0
# 在1.8秒时间帧内保持更新
while total_time < 1.8:
    sleep(0.01)
    tnew = time()
    t, dt = tnew, tnew - t
    for point in explode_points:
        for part in point:
            part.update(dt)
    cv.update()
    total_time += dt

现在,我们只需将最后两个gist合并为一个能被Tkinter调用的函数,就叫它simulate()吧。该函数会展示所有的数据项,并根据我们设置的时间更新每个数据项的属性。在我们的主代码中,我们会用一个alarm处理模块after()调用此函数,after()会等待一定的时间,然后再调用函数。

我们这里设置让Tkinter等待100个单位(大约1秒钟左右)再调取simulate。

if __name__ == '__main__':
    root = tk.Tk()
    cv = tk.Canvas(root, height=600, width=600)
    # 绘制一个黑色背景
    cv.create_rectangle(0, 0, 600, 600, fill="black")
    cv.pack()
 
    root.protocol("WM_DELETE_WINDOW", close)
    # 在1秒后才开始调用stimulate()
    root.after(100, simulate, cv)
    root.mainloop()

好了,这样我们就用Python代码放了一场烟花秀:

 可以换个背景哦

以下是全部代码:

import tkinter as tk
from PIL import Image, ImageTk
from time import time, sleep
from random import choice, uniform, randint
from math import sin, cos, radians
 
# 模拟重力
GRAVITY = 0.05
# 颜色选项(随机或者按顺序)
colors = ['red', 'blue', 'yellow', 'white', 'green', 'orange', 'purple', 'seagreen', 'indigo', 'cornflowerblue']
 
'''
particles 类
粒子在空中随机生成随机,变成一个圈、下坠、消失
属性:
    - id: 粒子的id
    - x, y: 粒子的坐标
    - vx, vy: 在坐标的变化速度
    - total: 总数
    - age: 粒子存在的时长
    - color: 颜色
    - cv: 画布
    - lifespan: 最高存在时长
'''
 
 
class Particle:
 
    def __init__(self, cv, idx, total, explosion_speed, x=0., y=0., vx=0., vy=0., size=2., color='red', lifespan=2,
                 **kwargs):
        self.id = idx
        self.x = x
        self.y = y
        self.initial_speed = explosion_speed
        self.vx = vx
        self.vy = vy
        self.total = total
        self.age = 0self.color = color
        self.cv = cv
        self.cid = self.cv.create_oval(
            x - size, y - size, x + size,
            y + size, fill=self.color)
        self.lifespan = lifespan
 
    def update(self, dt):
        self.age += dt
 
        # 粒子范围扩大
        if self.alive() and self.expand():
            move_x = cos(radians(self.id * 360 / self.total)) * self.initial_speed
            move_y = sin(radians(self.id * 360 / self.total)) * self.initial_speed
            self.cv.move(self.cid, move_x, move_y)
            self.vx = move_x / (float(dt) * 1000)
 
        # 以自由落体坠落
        elif self.alive():
            move_x = cos(radians(self.id * 360 / self.total))
            # we technically don't need to update x, y because move will do the job
            self.cv.move(self.cid, self.vx + move_x, self.vy + GRAVITY * dt)
            self.vy += GRAVITY * dt
        # 移除超过最高时长的粒子
        elif self.cid is not None:
            cv.delete(self.cid)
            self.cid = None
    # 扩大的时间
    def expand (self):
        return self.age <= 1.2
    # 粒子是否在最高存在时长内
    def alive(self):
        return self.age <= self.lifespan
'''
循环调用保持不停
'''
def simulate(cv):
    t = time()
    explode_points = []
    wait_time = randint(10, 100)
    numb_explode = randint(6, 10)
    # 创建一个所有粒子同时扩大的二维列表
    for point in range(numb_explode):
        objects = []
        x_cordi = randint(50, 550)
        y_cordi = randint(50, 150)
        speed = uniform(0.5, 1.5)
        size = uniform(0.5, 3)
        color = choice(colors)
        explosion_speed = uniform(0.2, 1)
        total_particles = randint(10, 50)
        for i in range(1, total_particles):
            r = Particle(cv, idx=i, total=total_particles, explosion_speed=explosion_speed, x=x_cordi, y=y_cordi,
                         vx=speed, vy=speed, color=color, size=size, lifespan=uniform(0.6, 1.75))
            objects.append(r)
        explode_points.append(objects)
    total_time = .0
    # 1.8s内一直扩大
    while total_time < 1.8:
        sleep(0.01)
        tnew = time()
        t, dt = tnew, tnew - t
        for point in explode_points:
            for item in point:
                item.update(dt)
        cv.update()
        total_time += dt
    # 循环调用
    root.after(wait_time, simulate, cv)
def close(*ignore):
    """退出程序、关闭窗口"""
    global root
    root.quit()
if __name__ == '__main__':
    root = tk.Tk()
    cv = tk.Canvas(root, height=400, width=600)
    # 选一个好看的背景会让效果更惊艳!
    image = Image.open("./image.jpg")
    photo = ImageTk.PhotoImage(image)
    cv.create_image(0, 0, image=photo, anchor='nw')
    cv.pack()
    root.protocol("WM_DELETE_WINDOW", close)
    root.after(100, simulate, cv)
    root.mainloop()

创作不易哦~

求大家给个三连,点个关注~感谢大家哦

 今天就是以上这些内容,下面有个投票,大家可以来看看哦

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/132015.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

算法设计与分析复习02:分而治之算法

算法设计与分析复习02&#xff1a;分而治之算法 文章目录算法设计与分析复习02&#xff1a;分而治之算法复习重点分而治之算法全排列递归算法矩阵乘法的Strassen算法棋盘覆盖线性时间选择复习重点 分而治之算法 全排列递归算法 #include<vector> #include<iostream&g…

await如何优雅的捕获异常?

传统方式 try { const res await getUser(id) }catch(err){console.log(err) } await让我们使用异步方式开发的代码简便不少&#xff0c;但是每次使用如果都用try..catch来捕获异常反而埋没了它的优势。 [ err, user ] await to(UserModel.findById(1)); 如果我们使用await…

CSS var() 自定义的属性值和使用

声明全局 CSS 变量 :root{<自定义属性名>: <自定义属性值>; }自定义属性名必需以 -- 开头。 :root :root 这个 CSS 伪类匹配文档树的根元素。对于 HTML 来说&#xff0c;:root 表示 <html> 元素&#xff0c;除了优先级更高之外&#xff0c;与 html 选择器…

【Docker】构建自定义镜像

文章目录1. 镜像制作的两种方法2. Commit构建自定义镜像3. Dockerfile构建镜像4. 镜像的分层结构5. Dockerfile基础指令6. Java服务器镜像构建7. Nginx镜像构建8. Redis镜像构建9. 快速部署MySQL并初始化1. 镜像制作的两种方法 基于Docker Commit制作镜像基于Dockerfile制作镜…

WIKO+鸿蒙生态:海外品牌中国化的新范式

想要理解快速变化的科技行业&#xff0c;往往要锚定一些标杆型企业&#xff0c;它们的风吹草动&#xff0c;可能就是行业接下来的地动山摇。就像互联网绕不过BAT&#xff0c;手机行业的趋势也少不了鸿蒙的消息。最近&#xff0c;有一件鸿蒙生态的新闻是比较特别的。我们报道过很…

java反射基础

Java反射机制提供的功能 在运行时判断任意一个对象所属的类 在运行时构造任意一个类的对象 在运行时判断任意一个类所具有的成员变量和方法 在运行时获取泛型信息 在运行时调用任意一个对象的成员变量和方法 在运行时处理注解 生成动态代理 Java反射优点和缺点 优点: …

Linux free命令详解,Linux查看内存使用情况

「作者主页」&#xff1a;士别三日wyx 「作者简介」&#xff1a;CSDN top100、阿里云博客专家、华为云享专家、网络安全领域优质创作者 free一、常用操作二、字段解释1、free和available的区别&#xff1f;2、交换分区的作用&#xff1f;三、内存使用情况分析技巧四、原理&…

人脸识别检测项目实战

文章目录 一、项目介绍 二、环境配置 三、项目知识储备 导入图片灰度转换 修改图片尺寸的大小矩形检测框图绘制 人脸检测识别 多个人脸检测效果对人脸视频进行检测数据集录入训练数据人脸识别过程 项目介绍 人脸识别在现代化中应用较为广泛&#xff0c;比如人脸考勤系统等&…

Python爬虫——Scrapy 的基本使用

Scrapy 框架中创建项目、查看配置信息&#xff0c;以及运行爬虫程序都是通过指令完成。 常用指令如下所示&#xff1a; 指令格式说明startprojectscrapy startproject <项目名>创建新项目genspiderscrapy genspider <爬虫文件名> <访问的域名>新建爬虫文件…

torchnet package (1)

torchnet torchnet用于torch的代码复用和模块化编程框架,主要包含四个类 Dataset: 以不同的方式对数据进行预处理.Engine: 训练/测试机器学习方法Meter评估方法性能Log日志. Documentation torchnet的调用 local tnt require ‘torchnet’ tnt.Dataset() torchnet提供了多…

VueJs中的reactive函数

前言一个基本类型的数据,想要变成响应式数据,那么需要通过ref函数包裹,而如果是一个对象的话,那么需要使用reactive函数reactive可将对象变成响应式将一个对象类型的数据变为响应式,如果是基本数据类型,那用refconst 代理对象 reactive(被代理对象)接收一个对象(或数组),返回一…

一个DevOps/SRE/运维的2022年碎碎语

人们常说&#xff1a;情商高的人会说话。实际上他们的意思是对人说人话&#xff0c;对鬼说鬼话&#xff0c;这样的人才有前途。很长时间里&#xff0c;我一直以为我无法理解他们为什么要推崇心口不一。后来&#xff0c;我知道了。我不是不理解。我只是不服气。这样的”不服气“…

box-shadow 高阶玩法:纯 CSS 画蒙娜丽莎和粒子星空

想必写过 CSS 的同学都用过 box-shadow&#xff0c;它可以给元素设置阴影&#xff0c;增加立体效果。 比如说这样&#xff1a; 但它能做的可不只是阴影&#xff0c;还可以用来做出很多有趣的效果&#xff1a; 比如画蒙娜丽莎&#xff1a; 画星空&#xff1a; 这些效果都是 bo…

尚医通-医院查询接口-上传科室接口(十九)

目录 &#xff08;1&#xff09;医院查询接口-功能实现 &#xff08;2&#xff09;上传科室接口-功能实现 &#xff08;1&#xff09;医院查询接口-功能实现 接口文档&#xff1a; 4.4.查询医院 医院信息 4.4.1.提交地址 http://localhost/api/hosp/hospital/show 在ApiC…

《东晋门阀政治》

《东晋门阀政治》 关于作者 田余庆&#xff0c;北京大学历史系教授&#xff0c;国务院古 籍整理出版规划小组成员&#xff0c;是魏晋南北朝 政治史专家。他在学术界拥有重要的地位&#xff0c;参加编著的《中国史纲要》曾获国家 教委特等奖。著有《秦汉魏晋史探微》 《拓跋史…

ubuntu 22.04上vim-plug插件管理器,相关插件与ROS2的安装

前言 最近&#xff0c;新配置了一版虚拟机&#xff0c;因为学校已经配置好环境的虚拟机忘了带回来&#xff0c;我还想系统的学习一下ROS&#xff0c;并将其用于机械臂的控制&#xff0c;因此用了新的方式配置了vim&#xff0c;并将树莓派raspberry buster系统配置上了ROS1的环…

Flink系列Table API和SQL之:滚动窗口、滑动窗口、累计窗口、分组聚合

Flink系列Table API和SQL之&#xff1a;窗口一、窗口(Window)二、分组窗口(Group Window)三、窗口表值函数(Windowing TVFs)1.滚动窗口(TUMBLE)2.滑动窗口(HOP)3.累计窗口(CUMULATE)四、分组聚合五、分组聚合实现代码六、分组窗口聚合代码实现七、窗口聚合&#xff1a;滚动窗口…

【SCL】博图SCL应用之音乐喷泉

使用Scl语言编写博图应用&#xff1a;音乐喷泉 文章目录 目录 一、音乐喷泉 1.控制要求 2.I/O分配 3.编写程序 4.效果和完整代码 二、装配流水线模拟控制&#xff08;练习&#xff09; 1.控制要求 2.场景 前言 承接上文&#xff0c;这里写一下上一篇的练习题 音乐喷泉应用案…

使用Typora+PicGo+SM.MS实现本地博客图片自动上传

使用TyporaPicGoSM.MS实现本地博客图片自动上传 Typora&#xff1a;一款Markdown 编辑器 PicGo: 一个用于快速上传图片并获取图片 URL 链接的工具. SM.MS: 一个图床网站&#xff0c;注册后有5G免费空间 为什么要让本地图片自动上传 对于一个随时随刻都有可能在文章中贴代码的计…

快来领取你的JavaScript正则表达式速查表

如果我们想对字符串进行相关&#xff08;增、删、改、查、检索&#xff09;操作&#xff0c;就可以用接下来的正则表达式实现 什么是正则表达式 正则表达式是用于匹配字符串中字符组合的模式正则表达式通常被用来检索、替换那些符合某个模式&#xff08;规则&#xff09;的文本…