首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用Tkinter创建Fireworks

使用Tkinter创建Fireworks
EN

Stack Overflow用户
提问于 2017-01-10 18:06:32
回答 1查看 1.5K关注 0票数 2

我正试着用Tkinter (python)创建一个非常漂亮的五颜六色的Firework,尽管它对我不起作用。问题是在爆炸(火箭类)部分的烟火粒子没有停止,我不知道为什么。我已经尝试了很多方法,但是没有变得更好。

**注意:我正在讨论的类叫Rocket,粒子在其中移动,爆炸,不会停止“爆炸”**-我使用了粒子类和Firework类,所以你不需要阅读所有的代码,只需要阅读这些部分。

我的代码:

代码语言:javascript
复制
import tkinter as tk
from time import time, sleep
from random import choice, uniform, randint
from math import sin, cos, radians
from sys import modules

GRAVITY = 30  # you can play around with this if you want

class Particle:
    """Generic class for particles.

    Particles can be emitted by Fireworks objects. They are displayed for a
    specified lifespan and then removed from the canvas.

    Attributes:
        cv (Tk.canvas): the canvas in which the particle is drawn.
        cid (Tk.canvas): the tkinter canvas id for the particle.
        x (float): x-coordinate of the particle.
        y (float): y-coordinate of the particle.
        vx (float): x-velocity of the particle (in pixels per second).
        vy (float): y-velocity of the particle (in pixels per second).
        color (str): color of the particle.
        age (float): age of the particle.
        lifespan (float): lifespan of the particle (in seconds).

    """

    def __init__(self, cv=None, color='white', x=0., y=0.,
                 vx=0., vy=0., lifespan=5.):
        """Init Particle objects.

        Args:
            cv (Tk.canvas): the canvas in which the particle is drawn.
            x (float): x-coordinate of the particle.
                Defaults to 0.0.
            y (float): y-coordinate of the particle.
                Defaults to 0.0.
            vx (float): x-velocity of the particle (in pixels per second).
                Defaults to 0.0.
            vy (float): y-velocity of the particle (in pixels per second).
                Defaults to 0.0.
            color (str): color of the particle.
                Defaults to 'white'.
            lifespan (float): lifespan of the particle (in seconds).
                Defaults to 5.0.

        """
        self.cv = cv
        self.cid = None
        self.x, self.y = x, y
        self.vx, self.vy = vx, vy
        self.color = color
        self.age, self.lifespan = 0, lifespan

    def update(self, dt):
        """Update position and velocity after dt seconds have passed.

        Args:
            dt (float): the time that has passed after the last update (in s).

        """
        self.age += dt
        if self.alive():
            self.vy += GRAVITY * dt
            self.x += self.vx * dt
            self.y += self.vy * dt
            self.cv.move(self.cid, self.vx * dt, self.vy * dt)
        elif self.cid is not None:
            cv.delete(self.cid)
            self.cid = None

    def alive(self):
        """Check if particle is still within its lifespan."""
        return self.age <= self.lifespan


class SquareParticle(Particle):
    """A Particle with a quadratic shape"""
    def __init__(self, x=0., y=0., size=2., **kwargs):
        super().__init__(x=x, y=y, **kwargs)
        self.cid = self.cv.create_polygon(
            x - size, y - size, x + size, y - size,
            x + size, y + size, x - size, y + size,
            fill=self.color)


class TriangleParticle(Particle):
    """A Particle with a triangular shape"""
    def __init__(self, x=0., y=0., size=2., **kwargs):
        super().__init__(x=x, y=y, **kwargs)
        self.cid = self.cv.create_polygon(
            x - size, y - size, x + size,
            y - size, x, y + size,
            fill=self.color)


class CircularParticle(Particle):
    """A Particle with a circular shape."""
    def __init__(self, x=0., y=0., size=2., **kwargs):
        super().__init__(x=x, y=y, **kwargs)
        self.cid = self.cv.create_oval(
            x - size, y - size, x + size,
            y + size, fill=self.color)


class Fireworks:
    """Generic class for fireworks.

    The main "behavior" of a fireworks is specified via its update method.
    E.g., new particles can be emitted and added to the particle list. The
    Fireworks base class automatically updates all particles from the particle
    list in its update method.

    Attributes:
        cv (Tk.canvas): the canvas in which the fireworks is drawn.
        age (float): age of the fireworks.
        particles (list of Particle): list of generated particles.

    """

    def __init__(self, cv=None):
        """Init Fireworks objects.

        Args:
            cv (Tk.canvas): the canvas in which the particle is drawn.

        """
        self.cv = cv
        self.age = 0
        self.particles = []

    def update(self, dt):
        """Update the fireworks' particles and remove dead ones.

        Args:
            dt (float): the time that has passed after the last update (in s).

        """
        self.age += dt
        for p in self.particles:
                 p.update(dt)
        for i in range(len(self.particles) - 1, -1, -1):
            if not self.particles[i].alive():
                del self.particles[i]


class Volcano(Fireworks):
    """A volcano that continuously emits colored particles.

    Attributes:
        x (float): x-coordinate of the volcano.
        pps (float): the number of particles to spawn per second.
        colors (list of string): the colors of the particles to spawn."""

    def __init__(self, cv, x, pps, colors):
        """Init Volcano objects.

        Args:
            cv (Tk.canvas): the canvas in which the particle is drawn.
            x (float): x-coordinate of the volcano.
            pps (float): the number of particles to spawn per second.
            colors (list of string): the colors of the particles to spawn.

        """
        super().__init__(cv)
        self.cid = cv.create_polygon(x - 12, 530,  # size and color are fixed
                                     x + 12, 530,  # (can be parametrized)
                                     x, 500,
                                     fill="orange")
        self.x = x
        self.pps = pps
        self.colors = colors
        self._tospawn = 0

    def update(self, dt):
        """Continuously emits new random particles and updates them.

        Args:
            dt (float): the time that has passed after the last update (in s).

        """
        super().update(dt)
        self._tospawn += self.pps * dt
        color = self.colors[int(self.age / 3) % len(self.colors)]
        for i in range(int(self._tospawn)):
            ptype = choice(
                [SquareParticle, TriangleParticle, CircularParticle])
            angle = uniform(-0.25, 0.25)
            speed = -uniform(80.0, 120.0)
            vx = sin(angle) * speed
            vy = cos(angle) * speed
            self.particles.append(
                ptype(cv=self.cv, x=self.x, y=500, color=color, vx=vx, vy=vy))
        self._tospawn -= int(self._tospawn)


class Rocket(Particle, Fireworks):

    def __init__(self, cv, x=0., y=0., size=2., **kwargs):
        super().__init__(cv, x=x, y=y, **kwargs)
        self.cid = self.cv.create_oval(
            x - size, y - size, x + size,
            y + size, fill=self.color)
        self.x = x
        self.pps = 100
        self.colors = ['red']
        self._tospawn = 0
        self.particles = []

    def update(self, dt):
        self.age += dt
        if self.alive():
            self.vy += -GRAVITY * dt
            self.x += self.vx * dt
            self.y += self.vy * dt
            self.cv.move(self.cid, self.vx * dt, self.vy * dt)
        elif self.cid is not None:
            cv.delete(self.cid)
            self.cid = None
        if self.cid is None:
             Fireworks.update(self, dt)
             color = self.colors[int(self.age / 3) % len(self.colors)]
             self._tospawn += self.pps * dt
             for i in range(int(self._tospawn)):
              ptype = choice(
                [CircularParticle])
              angle = uniform(-100, 100)
              speed = -uniform(80, 120.0)
              vx = sin(angle) * speed
              vy = cos(angle) * speed
              self.particles.append(
                 ptype(cv=self.cv, x=self.x, y=self.y, color=color, vx=vx, vy=vy))
              self._tospawn -= self.pps * dt


def simulate(cv, objects):
    """Fireworks simulation loop.

        Args:
            cv (float): the canvas in which the firework objects are drawn.
            objects (float): the firework objects.

    """
    t = time()
    while running:
        sleep(0.01)
        tnew = time()
        t, dt = tnew, tnew - t
        for o in objects:
            o.update(dt)
        cv.update()


def close(*ignore):
    """Stops simulation loop and closes the window."""
    global running
    running = False
    root.destroy()


if __name__ == '__main__':
    x = 10
    root = tk.Tk()
    cv = tk.Canvas(root, height=600, width=800)
    cv.create_rectangle(0, 0, 800, 600, fill="black")  # sky
    cv.create_rectangle(0, 450, 800, 600, fill="gray11")  # ground
    cv.pack()

    v1 = Volcano(cv, 400, 100, ["red", "green", "gold"])
    ro = Rocket(cv, 600, 500)
    objects = [v1, ro]

    # close with [ESC] or (x) button
    root.bind('<Escape>', close)
    root.protocol("WM_DELETE_WINDOW", close)

    running = True
    root.after(500, simulate, cv, objects)
    if "idlelib" not in modules:
        root.mainloop()

对我来说,更重要的是理解为什么会发生这种情况,所以如果我能从内部得到解释,那就太好了。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-01-10 20:47:07

Rocket我不得不搬家

代码语言:javascript
复制
self._tospawn += self.pps * dt

转到

代码语言:javascript
复制
elif self.cid is not None: 

停止fireworks的步骤

代码语言:javascript
复制
   elif self.cid is not None:
        cv.delete(self.cid)
        self.cid = None

        self._tospawn += 10 * self.pps * dt

   if self.cid is None:
        Fireworks.update(self, dt)
        color = self.colors[int(self.age / 3) % len(self.colors)]
        for i in range(int(self._tospawn)):
          ptype = choice(
            [CircularParticle])
          angle = uniform(-100, 100)
          speed = -uniform(80, 120.0)
          vx = sin(angle) * speed
          vy = cos(angle) * speed
          self.particles.append(
             ptype(cv=self.cv, x=self.x, y=self.y, color=color, vx=vx, vy=vy))
          self._tospawn -= self.pps * dt

您可以移动除Framework.update()之外的所有内容

代码语言:javascript
复制
   elif self.cid is not None:
        cv.delete(self.cid)
        self.cid = None

        self._tospawn += 10 * self.pps * dt

        color = self.colors[int(self.age / 3) % len(self.colors)]
        for i in range(int(self._tospawn)):
          ptype = choice(
            [CircularParticle])
          angle = uniform(-100, 100)
          speed = -uniform(80, 120.0)
          vx = sin(angle) * speed
          vy = cos(angle) * speed
          self.particles.append(
             ptype(cv=self.cv, x=self.x, y=self.y, color=color, vx=vx, vy=vy))
          self._tospawn -= self.pps * dt

   if self.cid is None:
        Fireworks.update(self, dt)
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/41566185

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档