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实现进程间通信简单实例
Jul 23 Python
在Django的模型中添加自定义方法的示例
Jul 21 Python
详解supervisor使用教程
Nov 21 Python
Python numpy 点数组去重的实例
Apr 18 Python
使用Python实现一个栈判断括号是否平衡
Aug 23 Python
用Python中的turtle模块画图两只小羊方法
Apr 09 Python
python自动保存百度盘资源到百度盘中的实例代码
Aug 26 Python
pytorch+lstm实现的pos示例
Jan 14 Python
在pytorch中实现只让指定变量向后传播梯度
Feb 29 Python
django实现后台显示媒体文件
Apr 07 Python
python Socket网络编程实现C/S模式和P2P
Jun 22 Python
Python3利用scapy局域网实现自动多线程arp扫描功能
Jan 21 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 eval函数用法总结
2012/10/31 PHP
php面向对象之反射功能与用法分析
2017/03/29 PHP
laravel中数据显示方法(默认值和下拉option默认选中)
2019/10/11 PHP
Laravel使用swoole实现websocket主动消息推送的方法介绍
2019/10/20 PHP
javascript 面向对象全新理练之原型继承
2009/12/03 Javascript
ASP.NET jQuery 实例15 通过控件CustomValidator验证CheckBoxList
2012/02/03 Javascript
jQuery focus和blur事件的应用详解
2014/01/26 Javascript
toggle()隐藏问题的解决方法
2014/02/17 Javascript
js控制div弹出层实现方法
2015/05/11 Javascript
JS实现可直接显示网页代码运行效果的HTML代码预览功能实例
2015/08/06 Javascript
javascript图片预加载完整实例
2015/12/10 Javascript
Javascript操作表单实例讲解(下)
2016/06/20 Javascript
JavaScript 判断一个对象{}是否为空对象的简单方法
2016/10/09 Javascript
nodejs 图片预览和上传的示例代码
2017/09/30 NodeJs
javaScript动态添加Li元素的实例
2018/02/24 Javascript
详解Webpack多环境代码打包的方法
2018/08/03 Javascript
vue基于element-ui的三级CheckBox复选框功能的实现代码
2018/10/15 Javascript
webpack项目使用eslint建立代码规范实现
2019/05/16 Javascript
Typescript 中的 interface 和 type 到底有什么区别详解
2019/06/18 Javascript
layui的面包屑或者表单不显示的解决方法
2019/09/05 Javascript
浅探express路由和中间件的实现
2019/09/30 Javascript
解决vue admin element noCache设置无效的问题
2019/11/12 Javascript
[01:47]2018年度DOTA2最具人气解说-完美盛典
2018/12/16 DOTA
在Windows系统上搭建Nginx+Python+MySQL环境的教程
2015/12/25 Python
python输入错误密码用户锁定实现方法
2017/11/27 Python
Python中实现变量赋值传递时的引用和拷贝方法
2018/04/29 Python
python pandas写入excel文件的方法示例
2019/06/25 Python
关于tensorflow softmax函数用法解析
2020/06/30 Python
致短跑运动员广播稿
2014/01/09 职场文书
C++程序员求职信
2014/05/07 职场文书
2014年六一儿童节演讲稿
2014/05/23 职场文书
五水共治一句话承诺
2014/05/30 职场文书
2015年入党决心书
2015/02/05 职场文书
土木工程毕业答辩开场白
2015/05/29 职场文书
2019年怎样写好导游词?
2019/07/02 职场文书
gateway网关接口请求的校验方式
2021/07/15 Java/Android