【问题标题】:Drawing a line between points in pygame在pygame中的点之间画一条线
【发布时间】:2020-12-14 13:53:43
【问题描述】:

所以我试图制作类似于烟花的东西。我做了一个粒子类,它会组成烟花。

  class Particle:
        def __init__(self, pos, angle):
            self.pos = pos
            self.angle = angle
            self.color = choice([(217, 103, 51), (238, 95, 30)])
            self.radius = uniform(2, 7)
            self.pull = 0
            self.start = time.time()
    
        def adjust(self):
            self.radius -= 0.03
    
        def draw(self):
            if self.radius > 0:
                pygame.draw.circle(D, self.color, (int(self.pos[0])
                                               , int(self.pos[1])), int(self.radius))
    
        def move(self):
            now  = time.time()
            self.pos[0] += cos(radians(self.angle)) * 2
            self.pos[1] += (sin(radians(self.angle)) + self.pull) * 2
            if now - self.start > 0.1:
                self.pull += 0.25
                self.start = now

然后我制作了一个 Fireworks 类,它可以从 0 度到 360 度发射粒子。

class FireWorks:
    def __init__(self):
        self.particles = []
        for i in range(360):
            self.particles.append(Particle([600, 300], i))

    def explode(self):
        for i in range(len(self.particles)):
            self.particles[i].draw()
            self.particles[i].move()
            self.particles[i].adjust()
        for p in self.particles:
            if p.radius < 0:
                self.particles.remove(p)

现在我想从它们产生的位置 (600, 300) 沿着粒子所走的路径画一条线。但问题是粒子不会直线移动。为了让它看起来更自然一点,我对 y 值做了这个:self.pos[1] += (sin(radians(self.angle)) + self.pull) * 2self.pull 的值每 0.1 秒增加 0.25。我尝试的一件事是每次 y 增加时存储位置值并在这些位置之间画线,以便形成曲线,但根本没有绘制任何内容,这会导致滞后。下面的代码只显示了生成点和在点之间绘制线所涉及的位。

class Particle:
    def __init__(self, pos, angle):
        self.points = [] #added list to init to hold the points between which lines need  to be drawn

    def move(self):
       # In move method, every time a value is added to y, we record position at that point
       if now - self.start > 0.1:
          self.points.append(self.pos)
          self.pull += 0.25
    
    def draw(self):
        # Iterate through the points in the list and draw a line between them
        for i in range(len(self.points)):
            for j in range(1, len(self.points)):
                pygame.draw.line(D, self.color, (int(self.points[i][0]), int(self.points[i][1]))
                                 , (int(self.points[j][0]), int(self.points[j][1])), int(self.radius))

这是完整的代码供参考。

import pygame
from math import radians, sin, cos
from random import choice, uniform, randint
import time

pygame.init()

WIN = pygame.display
D = WIN.set_mode((1200, 600))

class Particle:
    def __init__(self, pos, angle):
        self.pos = pos
        self.angle = angle
        self.color = choice([(217, 103, 51), (238, 95, 30)])
        self.radius = uniform(2, 7)
        self.pull = 0
        self.start = time.time()
        self.points = []

    def adjust(self):
        self.radius -= 0.03

    def draw(self):
        if self.radius > 0:
            pygame.draw.circle(D, self.color, (int(self.pos[0])
                                           , int(self.pos[1])), int(self.radius))
            for i in range(len(self.points)):
                for j in range(1, len(self.points)):
                    pygame.draw.line(D, self.color, (int(self.points[i][0]), int(self.points[i][1]))
                                     , (int(self.points[j][0]), int(self.points[j][1])), int(self.radius))

    def move(self):
        now  = time.time()
        self.pos[0] += cos(radians(self.angle)) * 2
        self.pos[1] += (sin(radians(self.angle)) + self.pull) * 2
        if now - self.start > 0.1:
            self.points.append(self.pos)
            self.pull += 0.25
            self.start = now


class FireWorks:
    def __init__(self):
        self.particles = []
        for i in range(360):
            self.particles.append(Particle([600, 300], i))

    def explode(self):
        for i in range(len(self.particles)):
            self.particles[i].draw()
            self.particles[i].move()
            self.particles[i].adjust()
        for p in self.particles:
            if p.radius < 0:
                self.particles.remove(p)
            

f = FireWorks()
D.fill((0, 0, 0))
while True:
    pygame.event.get()
    D.fill((0, 0, 0))
    f.explode()
    WIN.flip()
    

 

【问题讨论】:

    标签: python pygame render


    【解决方案1】:

    您必须将位置元组的副本附加到位置列表,而不是对位置的引用:

    self.points.append(self.pos)

    self.points.append(self.pos[:])
    

    注意,self.pos 指的是一个包含 2 个组件的元组。因此self.points.append(self.pos) 将对该位置的新引用附加到列表中,但不会生成新位置。


    为了提高性能,我建议将整数位置添加到列表中,并通过pygame.draw.lines()沿着粒子路径画线:

    class Particle:
        # [...]
    
        def draw(self):
            if self.radius > 0:
                pygame.draw.circle(D, self.color, (int(self.pos[0])
                                               , int(self.pos[1])), int(self.radius))
                if len(self.points) > 1:
                    pygame.draw.lines(D, self.color, False, self.points)
    
        def move(self):
            now  = time.time()
            self.pos[0] += cos(radians(self.angle)) * 2
            self.pos[1] += (sin(radians(self.angle)) + self.pull) * 2
            if now - self.start > 0.1:
                x, y = round(self.pos[0]), round(self.pos[1])
                self.points.append((x, y))
                self.pull += 0.25
                self.start = now
    

    【讨论】:

    • 谢谢你成功了。但它仍然会导致滞后,并不是我所期望的那样。关于如何改进的想法?再次感谢
    • @hippozhipos 我不明白你为什么在嵌套循环中沿着粒子的路径画线。无论如何,我已经扩展了答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-23
    • 1970-01-01
    • 2020-02-16
    • 2020-10-24
    • 2016-08-25
    • 1970-01-01
    相关资源
    最近更新 更多