4
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Pythonでクリスマスの灯りを再現する

Posted at

初心者のためのtkinterお題

クリスマスが近づくと、部屋に暖かい灯りがほしくなる
Pythonの標準GUIライブラリである tkinter を使えば、シンプルなコードで「蝋燭の火が揺れ続け、スペースキーで消え、数秒後に勝手に点灯する」という小さなアニメーションを作ることができる

tkinter は軽量でインストール不要のため、Pygame を使うよりも環境構築のハードルが低い クリスマス向けのデスクトップ装飾や、ちょっとした学習用ミニアプリとして最適な題材になる

完成イメージ


コード全文

import tkinter as tk
import random

class EndlessCandle:
    def __init__(self, root):
        self.root = root
        self.root.title("Endless Candle - tkinter")

        self.canvas = tk.Canvas(root, width=300, height=500, bg="black")
        self.canvas.pack()

        # ロウソク本体
        self.canvas.create_rectangle(130, 300, 170, 450, fill="#f5e5c4", outline="")

        # 炎の座標を固定して保持(揺れのズレ防止)
        self.flame_x1, self.flame_y1 = 130, 220
        self.flame_x2, self.flame_y2 = 170, 300

        self.flame = self.canvas.create_oval(
            self.flame_x1, self.flame_y1,
            self.flame_x2, self.flame_y2,
            fill="orange",
            outline=""
        )

        self.flame_alive = True
        self.animate_flame()
        self.root.bind("<space>", self.blow_out)

    def animate_flame(self):
        if self.flame_alive:
            # 自然な炎の揺れ
            dx = random.uniform(-1.5, 1.5)
            dy = random.uniform(-0.5, 0.5)

            # 元の位置に対して揺らす(描画ズレ防止)
            self.canvas.coords(
                self.flame,
                self.flame_x1 + dx,
                self.flame_y1 + dy,
                self.flame_x2 + dx,
                self.flame_y2 + dy
            )

            # 炎の色をランダムに変化
            color = random.choice(["orange", "gold", "yellow", "#ffb84d"])
            self.canvas.itemconfig(self.flame, fill=color)

        self.root.after(60, self.animate_flame)

    def blow_out(self, event=None):
        if not self.flame_alive:
            return

        self.flame_alive = False
        # 黒く塗らず完全に透明化
        self.canvas.itemconfig(self.flame, fill="")

        # 二秒後に再点灯
        self.root.after(2000, self.reignite)

    def reignite(self):
        self.flame_alive = True
        self.canvas.itemconfig(self.flame, fill="orange")


root = tk.Tk()
app = EndlessCandle(root)
root.mainloop()

実装ポイント

位置の固定化と揺らぎ

tkinter の .move() は位置が積み上がるため、長時間動作で炎が画面外に飛んでいく
そのため、今回は .coords() を使って「元の位置+揺れ幅」を毎回再計算して描画している

これにより以下の問題が解決される

  • 炎が上に飛んでいく
  • 長時間動作で位置が破綻する
  • 揺れ方が不自然になる

自然さを出すための揺れ幅調整

炎の揺れは小さくするほどリアルになる
特に dx > dy となる振れ方は火の「縦長で横揺れしがち」な性質に合っている

dx = random.uniform(-1.5, 1.5)
dy = random.uniform(-0.5, 0.5)

消灯処理を透明化で実現

炎を黒に変えても「黒い楕円が見える」だけで消えたことにならない
そこで fill="" を使い、完全に非表示にする

self.canvas.itemconfig(self.flame, fill="")

これにより、消灯後は背景と同化して自然に見える


再点火を自然にする

炎の位置を常に固定値で保持しているため、再点火時にも炎の位置がズレない

まとめ

tkinter を使うことで、外部ライブラリを使わずに自然なアニメーションを作ることができる
今回の「エンドレス蝋燭」は非常にシンプルながら、位置補正、揺らぎ、透明化、状態管理など、アニメーションの基礎技術が凝縮されている

クリスマス向けの小さなデスクトップアプリ、学習用の教材、学校向けワークショップの題材などとしても扱いやすい

4
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?