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显示进度条的方法
Sep 20 Python
零基础写python爬虫之urllib2使用指南
Nov 05 Python
Python多进程通信Queue、Pipe、Value、Array实例
Nov 21 Python
python实现获取客户机上指定文件并传输到服务器的方法
Mar 16 Python
使用Python的Twisted框架实现一个简单的服务器
Apr 16 Python
python同时给两个收件人发送邮件的方法
Apr 30 Python
python getopt详解及简单实例
Dec 30 Python
对python 合并 累加两个dict的实例详解
Jan 21 Python
Python中将两个或多个list合成一个list的方法小结
May 12 Python
Python pandas对excel的操作实现示例
Jul 21 Python
python爬虫利器之requests库的用法(超全面的爬取网页案例)
Dec 17 Python
Python读取文件夹下的所有文件实例代码
Apr 02 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中利用XML技术构造远程服务(下)
2006/10/09 PHP
PHP中防止SQL注入实现代码
2011/02/19 PHP
php模仿qq空间或朋友圈发布动态、评论动态、回复评论、删除动态或评论的功能(中)
2017/06/11 PHP
Thinkphp5 微信公众号token验证不成功的原因及解决方法
2017/11/12 PHP
php取出数组单个值的方法
2018/03/12 PHP
JS 日期验证正则附asp日期格式化函数
2009/09/11 Javascript
IE下js调试工具Companion.JS
2010/10/15 Javascript
JavaScript之自定义类型
2012/05/04 Javascript
javascript同页面多次调用弹出层具体实例代码
2013/08/16 Javascript
JQuery中使用Ajax赋值给全局变量异常的解决方法
2014/01/10 Javascript
js实现的后台左侧管理菜单代码
2015/09/11 Javascript
Node.js中JavaScript操作MySQL的常用方法整理
2016/03/01 Javascript
js传值后台中文出现乱码的解决方法
2016/06/30 Javascript
angularjs实现文字上下无缝滚动特效代码
2016/09/04 Javascript
微信小程序 设置启动页面的两种方法
2017/03/09 Javascript
JS使用贪心算法解决找零问题示例
2017/11/27 Javascript
Vue+Flask实现简单的登录验证跳转的示例代码
2018/01/13 Javascript
原生js实现可兼容PC和移动端的拖动滑块功能详解【测试可用】
2019/08/15 Javascript
使用Vue-scroller页面input框不能触发滑动的问题及解决方法
2020/08/08 Javascript
[02:17]2016完美“圣”典风云人物:Sccc专访
2016/12/03 DOTA
一张图带我们入门Python基础教程
2017/02/05 Python
Python查找第n个子串的技巧分享
2018/06/27 Python
Python格式化日期时间操作示例
2018/06/28 Python
33个Python爬虫项目实战(推荐)
2019/07/08 Python
python numpy库linspace相同间隔采样的实现
2020/02/25 Python
Python使用socket_TCP实现小文件下载功能
2020/10/09 Python
匡威荷兰官方网站:Converse荷兰
2018/10/24 全球购物
医校毕业生自我鉴定
2014/01/25 职场文书
汽车销售员如何做职业生涯规划
2014/02/16 职场文书
街道务虚会发言材料
2014/10/20 职场文书
2014年幼儿园老师工作总结
2014/12/05 职场文书
安全承诺书
2015/01/19 职场文书
辞职信格式模板
2015/02/27 职场文书
小学生勤俭节约倡议书
2015/04/29 职场文书
单位政审意见范文
2015/06/04 职场文书
PyCharm配置KBEngine快速处理代码提示冲突、配置命令问题
2021/04/03 Python