Python製作煙花秀

主要用了tkinter和PIL(pillow)庫

 

效果:

 

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.5
#listof colors,can choose randomly or use as queue(FIFO
colors=['red','blue','yellow','white','green','orange','purple','seagreen','indigo','cornflowerblue']
'''
create a class for particles粒子
particles are emitted almost randomly on the sky,
forming around(組成一個圈) of circle(a star)before falling and getting removed from canvas

Attributes(屬性):
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=idx#每個煙花的特定標識符
        self.x=x#煙花的綻放x軸
        self.y=y#煙花的綻放x軸
        self.initial_speed=explosion_speed#初速度
        self.vx=vx#外放x軸速度
        self.vy=vy#外放y軸速度
        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)#create_oval()創建一個橢圓,參數爲左上x,左上y,右下x,右下y,填滿的顏色,該函數返回一個id
        self.lifespan=lifespan#應該停留時間
    def update(self,dt):#更新數據,已停留時間增加
        self.age+=dt
        #粒子膨脹
        if self.alive() and self.expand():#如果停留時間(2s)足夠&&膨脹時間(1.2s)足夠
            move_x=cos(radians(self.id*360/self.total))*self.initial_speed#粒子的x軸繼續膨脹
            move_y=sin(radians(self.id*360/self.total))*self.initial_speed#粒子的y軸繼續膨脹
            self.cv.move(self.cid, move_x, move_y)#根據id把畫布上的粒子移動x和y個距離
            self.vx=move_x/(float(dt)*1000)
        #以自由落體墜落
        elif self.alive():#如果只是停留時間足夠,說明膨脹到最大了,應該準備下墜
            move_x=cos(radians(self.id*360/self.total))#x軸繼續膨脹
            self.cv.move(self.cid,self.vx+move_x,self.vy+GRAVITY*dt)#而y軸按照重力因素做落體運動,但實際上這個重力是v而不是a
            self.vy+=GRAVITY*dt#更新一下y軸

        elif self.cid is not None:#如果粒子的生命週期已過,就將其移除
            cv.delete(self.cid)#刪除該粒子對象
            self.cid=None
    #定義膨脹效果的時間幀
    def expand(self):
        return self.age<=1.2#膨脹時間小於1.2s
    #檢查粒子是否仍在生命週期內
    def alive(self):#已停留時間是不是比應該停留時間短
        return self.age<=self.lifespan
'''
煙花模擬迴路:
遞歸調用來在畫布上重複發出新的煙火
通過每個“部件”對象內部的更新協議,每次調用時都要在畫布上創建並繪製列表(星列表,每個星列表成員都是粒子列表)來重複地在畫布上發出新的焰火
'''
#生成新的一輪爆炸
def simulate(cv):
    t=time()#time()函數返回自1970年後經過的浮點秒數,精確到小數點後6位
    explode_points=[]#爆炸點列表--煙花列表
    wait_time=randint(10,100)#隨機生成一個int n,10<=n<=100
    numb_explode=randint(6,10)#爆炸的個數是6~10
    #爲所有模擬煙花綻放的全部例子創建一列列表
    for point in range(numb_explode):#遍歷爆炸的個數
        objects=[]#這是每個點的爆炸粒子列表
        x_cordi=randint(50,550)#每個點的爆炸x軸
        y_cordi=randint(50,150)#爆炸y軸
        speed=uniform(0.5,1.5)#隨機生成一個float speed,0.5<=speed<1.5
        size=uniform(0.5,3)#隨機生成一個float size,0.5<=size<3
        color=choice(colors)#choice()是python內置函數,隨機返回元組,列表,或字符串的一個成員
        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,
                vx=speed, vy=speed, color=color, size=size, lifespan=uniform(0.6, 1.75))#把上述參數帶入,但他們每個粒子的生存時間是自己獨立的
            objects.append(r)#添加進粒子列表裏
        explode_points.append(objects)#把該粒子列表添加進煙花列表裏

    total_time=.0#先把時間置0
    #在1.8秒時間幀內保持更新
    while total_time<1.8:
        sleep(0.01)#讓畫面暫停0.01s
        tnew=time()#刷新時間
        t,dt=tnew,tnew-t#時間等於新時間,與上次時間間隔爲tnew-t
        for point in explode_points:#遍歷煙花列表
            for item in point:#遍歷煙花裏的粒子列表
                item.update(dt)#更新時間
        cv.update()#刷新頁面
        total_time+=dt#爲上面的while循環增加時間
    root.after(wait_time,simulate,cv)#將組件置於其他組件之後,就是放在最頂層,覆蓋下面的,這裏遞歸第哦啊用了自己,形成新的一輪爆炸
def close(*ignore):
    #打開模擬循環並關閉窗口
    global root
    root.quit()

if __name__=="__main__":
    root=tk.Tk()
    cv=tk.Canvas(root,height=500,width=500)#繪製一個畫布
    #繪製一個黑色背景
    #cv.create_rectangle(0,0,600,600,fill="black")
    #use a nice background image
    image=Image.open("image.jpg")
    photo=ImageTk.PhotoImage(image)
    cv.create_image(0,0,image=photo,anchor='nw')#在畫板上繪製一張圖片
    cv.pack()#把cv添加進去
    root.protocol("WM_DELETE_WINDOW",close)
    #在0.1s後纔開始調用stimulate()
    root.after(100,simulate,cv)#調用stimulate生成一輪煙花綻放效果
    root.mainloop()#執行root,生成窗口
#讓我更加明白了python的一切皆對象

 

 

參考:

https://blog.csdn.net/Mou_Yang/article/details/85091181

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章