来源:集智小编        链接:

https://jizhi.im/blog/post/py_make_fireworks

天天敲代码的朋友,有没有想过代码也可以变得很酷炫又浪漫?今天就教大家用Python模拟出绽放的烟花,工作之余也可以随时让程序为自己放一场烟花秀。

这个有趣的小项目并不复杂,只需一点可视化技巧,100余行Python代码和程序库Tkinter,最后我们就能达到下面这个效果:

学完本教程后,你也能做出这样的烟花秀。

整体概念梳理

我们的整个理念比较简单。

如上图示,我们这里通过让画面上一个粒子分裂为X数量的粒子来模拟爆炸效果。粒子会发生“膨胀”,意思是它们会以恒速移动且相互之间的角度相等。这样就能让我们以一个向外膨胀的圆圈形式模拟出烟花绽放的画面。经过一定时间后,粒子会进入“自由落体”阶段,也就是由于重力因素它们开始坠落到地面,仿若绽放后熄灭的烟花。

基本知识:用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之外,为了能让界面有漂亮的背景,我们也导入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 = idxself.x = xself.y = yself.initial_speed = explosion_speedself.vx = vxself.vy = vyself.total = totalself.age = 0self.color = colorself.cv = cvself.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_speedmove_y = sin(radians(self.id*360/self.total))*self.initial_speedself.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 jobself.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 - tfor 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代码放了一场烟花秀:

本文只一个简单版本,等进一步熟悉Tkinter后,还可以添加更多颜色更漂亮的背景照片,让代码为你绽放更美的烟花!

以下是全部代码:

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 = idxself.x = xself.y = yself.initial_speed = explosion_speedself.vx = vxself.vy = vyself.total = totalself.age = 0self.color = colorself.cv = cvself.cid = self.cv.create_oval(x - size, y - size, x + size,y + size, fill=self.color)self.lifespan = lifespandef update(self, dt):self.age += dt# 粒子范围扩大if self.alive() and self.expand():move_x = cos(radians(self.id * 360 / self.total)) * self.initial_speedmove_y = sin(radians(self.id * 360 / self.total)) * self.initial_speedself.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 jobself.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 - tfor 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 rootroot.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()

     精 彩 文 章 

  • 霸榜 GitHub:去你丫的算法!

  • 25个常用Matplotlib图的Python代码,收藏收藏!

  • 超级棒的170+款web前端开发工具汇总,千万要收藏好!

END
来和小伙伴们一起向上生长呀~~~
扫描下方二维码,添加小詹微信,可领取千元大礼包并申请加入 Python学习交流群,群内仅供学术交流,日常互动,如果是想发推文、广告、砍价小程序的敬请绕道!一定记得备注「交流学习」,我会尽快通过好友申请哦!(添加人数较多,请耐心等待)(扫码回复 1024  即可领取IT资料包)

代码也浪漫:用Python放一场烟花秀!相关推荐

  1. python引用turtle画烟花_代码也浪漫:用Python放一场烟花秀!

    天天敲代码的朋友,有没有想过代码也可以变得很酷炫又浪漫?今天就教大家用Python模拟出绽放的烟花,工作之余也可以随时让程序为自己放一场烟花秀. 这个有趣的小项目并不复杂,只需一点可视化技巧,100余 ...

  2. 庆祝法国队夺冠:用Python放一场烟花秀

    2019独角兽企业重金招聘Python工程师标准>>> 天天敲代码的朋友,有没有想过代码也可以变得很酷炫又浪漫?今天就教大家用Python模拟出绽放的烟花庆祝昨晚法国队夺冠,工作之余 ...

  3. python画春节_快到春节了,用Python来一场烟花秀

    原标题:快到春节了,用Python来一场烟花秀 作者:野客 来源:Python 技术(pythonall) 大家好,欢迎来到 Crossin的编程教室 ! 春节的脚步越来越近了,每逢春节很多地方都会燃 ...

  4. 快到春节了,用 Python 实现一场烟花秀

    春节的脚步越来越近了,每逢春节很多地方都会燃放烟花来增添节日的气氛,然而因环境污染的加剧,近年来不少地方已经禁止燃放烟花了,为了弥补这个遗憾,本文我们来看一下如何使用 Python 来实现一场烟花秀. ...

  5. 用python画烟花-过年了,用Python放一场浪漫烟花秀!

    天天敲代码的朋友,有没有想过代码也可以变得很酷炫又浪漫?今天就教大家用Python模拟出绽放的烟花,工作之余也可以随时让程序为自己放一场烟花秀. 这个有趣的小项目并不复杂,只需一点可视化技巧,100余 ...

  6. 【新年快乐】禁止燃放烟花爆竹那就用Python画场烟花秀吧

    目录 前言 Python界面设计之Tkinter 简单创建一个界面 在界面上创建画布 导入图片到界面中 其他一些重要函数 用Python画一场烟花秀 烟花的粒子类 烟花秀的实现 完整程序 前言 新年即 ...

  7. JAVA中的多线程与运动仿真(1)——用JAVA来放一场烟花

    JAVA中的多线程与运动仿真(1)--用JAVA来放一场烟花 一.实现效果的简单展示: 初步实现的动态效果为在鼠标点击之后,点击之处出现一簇小球,然后向不同方向散开变大. 利用这一效果,再在后续增加颜 ...

  8. 【python教程入门学习】Python新年炫酷烟花秀代码

    先介绍下 Pygame 绘制烟花的基本原理,烟花从发射到绽放一共分为三个阶段: 1,发射阶段:在这一阶段烟花的形状是线性向上,通过设定一组大小不同.颜色不同的点来模拟"向上发射" ...

  9. 我用Python放了除夕烟花

    uu们,有多久没放烟花了?今年你所在的地方允许放烟花么?既然我们不能线下放,那么我们就在线上放个够吧,先上最后效果图,给大家留个小疑问,知道博主配的什么歌么? 老规矩,先导包,导入pygame,Pyt ...

最新文章

  1. 超详细配置教程,搭建 Windows 深度学习环境
  2. Java的this、super和final关键字
  3. 别问我SolarWinds Orion API怎么用,自己进来看看,看完还不会来骂我
  4. ios 跳转到某 app 的评价区域、由某应用跳转到其他应用
  5. php 安装测试程序,PHPUnit安装及使用示例
  6. 论坛中,无限分类的原理
  7. 【牛客NOIP模拟】牛半仙的魔塔(增强版)【贪心】【并查集】
  8. 统计MySQL中某数据库硬盘占用量大小
  9. [UWP]创建一个ProgressControl
  10. [Java]toString的用法
  11. 三层代码的bll dal 层优化
  12. 1688api 图片搜索item_search_img-按图搜索1688商品(拍立淘)
  13. of介词短语作定语_在英语句子中,介词短语都能做什么用?作定语?作表语?作状语?...
  14. 如何给PDF文件添加页码
  15. 【HGE引擎】源码解析——常用公共函数(二)
  16. “芯片”=“集成电路”=“半导体”吗?
  17. 支小蜜人脸识别消费系统实现校园、家长、学生三方共赢
  18. R语言用贝叶斯线性回归、贝叶斯模型平均 (BMA)来预测工人工资
  19. 小米8se刷android7系统,小米8SE Flyme8系统刷机包(系统刷机最新固件升级包)
  20. 【Docker】Segmentation Fault or Critical Error encountered. Dumping core and abor

热门文章

  1. MySQL查询时通过修改字段的排序规则来忽略大小写的操作讲解
  2. 网页静态化和网页伪静态化之间的区别与选择
  3. MySQL重要概念图解(重要)
  4. 反思开发新需求节省时间的方法
  5. Linux之查看ubuntu版本
  6. jQuery构建路由
  7. php mysql通用类_PHP连接MYSQL数据库通用类_PHP教程
  8. HTML与XHTML的区别
  9. 模型与logit_基础方法 | 如何用Logit回归模型写论文?
  10. mysql数据存储方式_数据存储在mysql的两种方式