ホームページ  >  記事  >  バックエンド開発  >  Pythonのクールな花火の告白ソースコード

Pythonのクールな花火の告白ソースコード

angryTom
angryTomオリジナル
2020-02-25 14:10:1150408ブラウズ

毎日コードを入力している友人の皆さん、コードはクールでロマンチックにもなり得ると考えたことはありますか?今日は、Python を使用して開花する花火をシミュレートする方法を説明します。また、仕事の後いつでもプログラムで花火ショーを打ち上げることもできます。

Pythonのクールな花火の告白ソースコード

Python のクールな花火表現のソース コード

この興味深い小さなプロジェクトは複雑ではなく、ほんの少しの視覚化スキルだけで 100 個必要です。数行の Python コードとプログラム ライブラリ Tkinter を使用すると、最終的に次の効果を実現できます。

Pythonのクールな花火の告白ソースコード

このチュートリアルを完了すると、このような花火ショーを作成することもできます。

全体的なコンセプトのレビュー

私たちのコンセプト全体は比較的シンプルです。

Pythonのクールな花火の告白ソースコード

上の図に示すように、画面上のパーティクルを X 個のパーティクルに分割することで爆発エフェクトをシミュレートします。粒子は「膨張」します。これは、粒子が一定の速度で互いに等しい角度で移動することを意味します。これにより、円が広がる形で花火大会をシミュレートできるようになります。一定の時間が経過すると、パーティクルは「自由落下」フェーズに入り、花火が咲いて消えていくように、重力によって地面に落下し始めます。

(推奨学習: プログラミング学習コース)

基礎知識: Python と Tkinter による花火の設計

これ以上はここではありません数学的な知識をすべて一度に捨てて、コードを書きながら理論について話します。まず、Python の標準 GUI ライブラリであり、さまざまなプロジェクトやプログラム開発で広く使用されている Tkinter をインストールしてインポートします。Python で Tkinter を使用すると、GUI アプリケーションをすばやく作成できます。

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

Tkinter に加えて、インターフェイスの背景を美しくするために、画像処理用の PIL や、time、random、math などの他のパッケージもインポートします。これにより、花火の粒子の軌道をより簡単に制御できるようになります。

Tkinter アプリケーションの基本設定は次のとおりです。

root = tk.Tk()

Tkinter を初期化するには、Tk() ルート ウィジェットを作成する必要があります。これは、タイトル バーとその他の装飾はウィンドウ マネージャーによって提供されます。このルート ウィジェットは、他のウィジェットを作成する前に作成する必要があります。ルート ウィジェットは 1 つだけです。

w = tk.Label(root, text="Hello Tkinter!")

このコード行には、Label コンポーネントが含まれています。 Label 呼び出しの最初のパラメータは親ウィンドウの名前で、ここで使用する「ルート」です。キーワード引数「text」は、表示するテキストの内容を指定します。他のウィジェット (ボタン、キャンバスなど) を呼び出すこともできます。

w.pack()
root.mainloop()

コードの次の 2 行は重要です。ここでのパッケージ化方法は、使用されるウィジェットに合わせてウィンドウのサイズを変更するように Tkinter に指示することです。このウィンドウは、Tkinter イベント ループに入り、root.mainloop() によって呼び出されるまで表示されません。スクリプトはウィンドウを閉じるまでイベント ループ内に留まります。

開花する花火をコードに変換する

次に、花火イベントの各パーティクルを表すオブジェクトを設計します。各パーティクルには、サイズ、色、位置、速度など、その外観と動きを決定する重要なプロパティがいくつかあります。

'''
particles 类
粒子在空中随机生成随机,变成一个圈、下坠、消失
属性:
    - id: 粒子的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
        self.y = y
        self.initial_speed = explosion_speed
        self.vx = vx
        self.vy = vy
        self.total = total
        self.age = 0self.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

元のアイデアに戻って考えると、花火のすべての粒子が「膨張」、「落下」、「消滅」という 3 つの異なる段階を確実に通過する必要があることがわかります。 。そこで、以下に示すように、モーション関数をパーティクル クラスに追加します。

def update(self, 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.vx = move_x/(float(dt)*1000)
        self.vy = move_y/(float(dt)*1000)
        self.cv.move(self.cid, move_x, move_y)
    # 以自由落体坠落
    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

Tkinter シミュレーションの使用

ここで粒子の動きを概念化しますが、花火に粒子が 1 つしか存在できないことは明らかであり、花火ショーに粒子が 1 つしか存在できないことは明らかです。花火が一発です。次のステップは、Python と Tkinter が制御可能な方法でパーティクルを空に継続的に「発射」できるようにすることです。

この時点で、1 つのパーティクルの操作から、複数の花火と各花火内の複数のパーティクルを画面上に表示するようにアップグレードする必要があります。

私たちの解決策は次のとおりです。リストを作成します。各サブリストは粒子のリストを含む花火です。各リストの例は、X、Y 座標、サイズ、色、初速度が同じです。

numb_explode = randint(6,10)
# 为所有模拟烟花绽放的全部粒子创建一列列表
for point in range(numb_explode):
    objects = []
    x_cordi = randint(50,550)
    y_cordi = randint(50, 150)       
    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 = part(cv, idx = i, total = total_particles, explosion_speed = explosion_speed, x = x_cordi, y = y_cordi, 
        color=color, size = size, lifespan = uniform(0.6,1.75))
        objects.append(r)
explode_points.append(objects)

次のステップは、パーティクルのプロパティが定期的に更新されるようにすることです。ここでは、ステータスを 0.01 秒ごとに更新し、1.8 秒後に更新を停止するようにパーティクルを設定します (これは、各パーティクルが 1.6 秒間存在し、そのうち 1.2 秒が「ブルーミング」状態、0.4 秒が「落下」状態であることを意味します。 Tkinter が完全に削除するまでに数秒かかります)。

total_time = .0
# 在1.8秒时间帧内保持更新
while total_time < 1.8:
    sleep(0.01)
    tnew = time()
    t, dt = tnew, tnew - t
    for point in explode_points:
        for part in point:
            part.update(dt)
    cv.update()
    total_time += dt

现在,我们只需将最后两个gist合并为一个能被Tkinter调用的函数,就叫它simulate()吧。该函数会展示所有的数据项,并根据我们设置的时间更新每个数据项的属性。在我们的主代码中,我们会用一个alarm处理模块after()调用此函数,after()会等待一定的时间,然后再调用函数。

我们这里设置让Tkinter等待100个单位(1秒钟)再调取simulate。

if __name__ == &#39;__main__&#39;:
    root = tk.Tk()
    cv = tk.Canvas(root, height=600, width=600)
    # 绘制一个黑色背景
    cv.create_rectangle(0, 0, 600, 600, fill="black")
    cv.pack()
    root.protocol("WM_DELETE_WINDOW", close)
    # 在1秒后才开始调用stimulate()
    root.after(100, simulate, cv)
    root.mainloop()

好了,这样我们就用Python代码放了一场烟花秀:

Pythonのクールな花火の告白ソースコード

本文只一个简单版本,等进一步熟悉Tkinter后,还可以添加更多颜色更漂亮的背景照片,让代码为你绽放更美的烟花!

以下是全部代码:

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 = [&#39;red&#39;, &#39;blue&#39;, &#39;yellow&#39;, &#39;white&#39;, &#39;green&#39;, &#39;orange&#39;, &#39;purple&#39;, &#39;seagreen&#39;, &#39;indigo&#39;, &#39;cornflowerblue&#39;]
&#39;&#39;&#39;
particles 类
粒子在空中随机生成随机,变成一个圈、下坠、消失
属性:
    - id: 粒子的id
    - x, y: 粒子的坐标
    - vx, vy: 在坐标的变化速度
    - total: 总数
    - age: 粒子存在的时长
    - color: 颜色
    - cv: 画布
    - lifespan: 最高存在时长
&#39;&#39;&#39;
class Particle:
    def __init__(self, cv, idx, total, explosion_speed, x=0., y=0., vx=0., vy=0., size=2., color=&#39;red&#39;, 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 = 0self.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&#39;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
&#39;&#39;&#39;
循环调用保持不停
&#39;&#39;&#39;
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__ == &#39;__main__&#39;:
    root = tk.Tk()
    cv = tk.Canvas(root, height=400, width=600)
    # 选一个好看的背景会让效果更惊艳!
    image = Image.open("./image.jpg")
    photo = ImageTk.PhotoImage(image)
    cv.create_image(0, 0, image=photo, anchor=&#39;nw&#39;)
    cv.pack()
    root.protocol("WM_DELETE_WINDOW", close)
    root.after(100, simulate, cv)
    root.mainloop()

众多python培训视频,尽在python学习网,欢迎在线学习!

以上がPythonのクールな花火の告白ソースコードの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。