python实现浪漫的烟花秀


Posted in Python onJanuary 30, 2019

无意中看到一段用Tkinter库写的放烟花的程序,就跟着跑了一遍。

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

python实现浪漫的烟花秀

首先我们写一个粒子类,表示烟花事件中的每个粒子,包含大小,颜色,位置,速度等属性以及粒子经历的三个阶段的函数,即:膨胀、坠落、消失。

'''
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 = 0
  self.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

接下来我们需要创建一列列表,每个子列表是一个烟花,其包含一列粒子,每个列表中的粒子有相同的x,y坐标、大小、颜色、初始速度。

源码如下:

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 = 0
  self.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=360, width=480)
 # 选一个好看的背景会让效果更惊艳!
 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()

效果图(背景请忽略哈哈):

python实现浪漫的烟花秀

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python的装饰器用法学习笔记
Jun 24 Python
对numpy中数组转置的求解以及向量内积计算方法
Oct 31 Python
浅谈pandas用groupby后对层级索引levels的处理方法
Nov 06 Python
Python学习笔记之图片人脸检测识别实例教程
Mar 06 Python
python读csv文件时指定行为表头或无表头的方法
Jun 26 Python
用Python+OpenCV对比图像质量的几种方法
Jul 15 Python
Python TCP通信客户端服务端代码实例
Nov 21 Python
TensorFlow Saver:保存和读取模型参数.ckpt实例
Feb 10 Python
Python通过正则库爬取淘宝商品信息代码实例
Mar 02 Python
Python Django2 model 查询介绍(条件、范围、模糊查询)
Mar 16 Python
python3爬虫中异步协程的用法
Jul 10 Python
python数字类型和占位符详情
Mar 13 Python
新年快乐! python实现绚烂的烟花绽放效果
Jan 30 #Python
python+selenium 定位到元素,无法点击的解决方法
Jan 30 #Python
解决Python selenium get页面很慢时的问题
Jan 30 #Python
对python实现模板生成脚本的方法详解
Jan 30 #Python
ActiveMQ:使用Python访问ActiveMQ的方法
Jan 30 #Python
python 发送和接收ActiveMQ消息的实例
Jan 30 #Python
Python批量生成特定尺寸图片及图画任意文字的实例
Jan 30 #Python
You might like
php实现把url转换迅雷thunder资源下载地址的方法
2014/11/07 PHP
php版本CKEditor 4和CKFinder安装及配置方法图文教程
2019/06/05 PHP
Laravel 实现Eloquent模型分组查询并返回每个分组的数量 groupBy()
2019/10/23 PHP
discuz论坛更换域名,详细文件修改步骤
2020/12/09 PHP
jQuery 源代码显示控件 (Ajax加载方式).
2009/05/18 Javascript
JavaScript 面向对象编程(2) 定义类
2010/05/18 Javascript
jquery触发a标签跳转事件示例代码
2013/07/21 Javascript
jQuery中odd选择器的定义和用法
2014/12/23 Javascript
JavaScript删除数组元素的方法
2015/03/20 Javascript
javascript实现全局匹配并替换的方法
2015/04/27 Javascript
JS中产生标识符方式的演变
2015/06/12 Javascript
Ionic实现仿通讯录点击滑动及$ionicscrolldelegate使用分析
2016/01/18 Javascript
jQuery Easyui Tabs扩展根据自定义属性打开页签
2016/08/15 Javascript
webpack 插件html-webpack-plugin的具体使用
2018/04/09 Javascript
Angular父子组件通过服务传参的示例方法
2018/10/31 Javascript
Vue核心概念Action的总结
2019/01/18 Javascript
vue使用高德地图根据坐标定位点的实现代码
2019/08/22 Javascript
利用JS代码自动删除稿件的普通弹幕功能
2019/09/20 Javascript
layui: layer.open加载窗体时出现遮罩层的解决方法
2019/09/26 Javascript
Vue 中 template 有且只能一个 root的原因解析(源码分析)
2020/04/11 Javascript
解决vue自定义指令导致的内存泄漏问题
2020/08/04 Javascript
JavaScript this关键字指向常用情况解析
2020/09/02 Javascript
Python最小二乘法矩阵
2019/01/02 Python
Python中一般处理中文的几种方法
2019/03/06 Python
python 普通克里金(Kriging)法的实现
2019/12/19 Python
tensorflow 模型权重导出实例
2020/01/24 Python
Python系统公网私网流量监控实现流程
2020/11/23 Python
Python爬虫开发与项目实战
2020/12/16 Python
CK美国官网:Calvin Klein
2016/08/26 全球购物
Python里面如何实现tuple和list的转换
2012/06/13 面试题
解释一下ruby中的特殊方法与特殊类
2013/02/26 面试题
法院授权委托书范文
2014/08/02 职场文书
教师竞聘上岗演讲稿
2014/09/03 职场文书
pycharm 如何查看某一函数源码的快捷键
2021/05/12 Python
js基础语法与maven项目配置教程案例
2021/07/15 Javascript
Mybatis-Plus 使用 @TableField 自动填充日期
2022/04/26 Java/Android