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下的twisted框架入门指引
Apr 15 Python
在ironpython中利用装饰器执行SQL操作的例子
May 02 Python
详解python发送各类邮件的主要方法
Dec 22 Python
python3.6.3+opencv3.3.0实现动态人脸捕获
May 25 Python
关于python之字典的嵌套,递归调用方法
Jan 21 Python
python批量识别图片指定区域文字内容
Apr 30 Python
详解Python对JSON中的特殊类型进行Encoder
Jul 15 Python
python线程安全及多进程多线程实现方法详解
Sep 27 Python
在Python中使用filter去除列表中值为假及空字符串的例子
Nov 18 Python
Python阶乘求和的代码详解
Feb 14 Python
解决pyinstaller 打包exe文件太大,用pipenv 缩小exe的问题
Jul 13 Python
Selenium webdriver添加cookie实现过程详解
Aug 12 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 无限级数据JSON格式及JS解析
2010/07/17 PHP
php dirname(__FILE__) 获取当前文件的绝对路径
2011/06/28 PHP
easyui的tabs update正确用法分享
2014/03/21 PHP
PHP函数in_array()使用详解
2014/08/20 PHP
PHP提示Warning:phpinfo() has been disabled函数禁用的解决方法
2014/12/17 PHP
js innerHTML 的一些问题的解决方法
2008/06/22 Javascript
JavaScript Event学习第五章 高级事件注册模型
2010/02/07 Javascript
jQuery学习总结之元素的相对定位和选择器(持续更新)
2011/04/26 Javascript
js使用DOM设置单选按钮、复选框及下拉菜单的方法
2015/01/20 Javascript
JavaScript在网页中画圆的函数arc使用方法
2015/11/13 Javascript
JavaScript模拟鼠标右键菜单效果
2020/12/08 Javascript
微信小程序 textarea 详解及简单使用方法
2016/12/05 Javascript
微信小程序 配置文件详细介绍
2016/12/14 Javascript
jquery Ajax实现Select动态添加数据
2017/06/08 jQuery
在vue项目中使用Nprogress.js进度条的方法
2018/01/31 Javascript
基于IView中on-change属性的使用详解
2018/03/15 Javascript
详解如何创建并发布一个 vue 组件
2018/11/08 Javascript
小程序实现左滑删除效果
2019/07/25 Javascript
vue自定义正在加载动画的例子
2019/11/14 Javascript
详解Vue的ref特性的使用
2020/01/24 Javascript
[44:37]完美世界DOTA2联赛PWL S3 Forest vs access 第一场 12.11
2020/12/13 DOTA
python实现音乐下载的统计
2018/06/20 Python
python实现连续图文识别
2018/12/18 Python
python计算二维矩形IOU实例
2020/01/18 Python
基于Python-Pycharm实现的猴子摘桃小游戏(源代码)
2021/02/20 Python
美国购买隐形眼镜网站:Lenses For Less
2020/07/05 全球购物
李维斯牛仔裤荷兰官方网站:Levi’s NL
2020/08/23 全球购物
当我正在为表建立索引的时候,SQL Server 会禁止对表的访问吗
2014/04/28 面试题
后勤人员自我评价怎么写
2013/09/19 职场文书
读书心得体会
2013/12/28 职场文书
写演讲稿所需要注意的4个条件
2014/01/09 职场文书
人力资源专员岗位职责
2014/01/30 职场文书
中学生期中自我鉴定
2014/04/20 职场文书
全运会口号
2014/06/20 职场文书
2019年图书室自查报告范本
2019/10/12 职场文书
Golang 链表的学习和使用
2022/04/19 Golang