【问题标题】:How to draw bubbles and turn them animated into circles如何绘制气泡并将它们动画成圆圈
【发布时间】:2022-08-14 15:58:53
【问题描述】:

我正在尝试制作一个 python 程序来绘制一条线并使用 pygame 将它变成一个带有动画的圆圈,但我什至还没有完成绘图线代码。我注意到python正在更改列表中的错误或两个项目,该列表包含用户按下左键时的起点,存储为第一项,用户鼠标的当前点作为第二项。

这通常是我想要它做的:https://youtu.be/vlqZ0LubXCA

以下是有和没有更新第二项的行的结果:

和:

没有:

如您所见,或在描述中阅读,该行是覆盖前一帧所必需的。

我用箭头标记了改变结果的行:

import pygame, PIL, random
print(\'\\n\')

#data
bubbles = []
color_options = [[87, 184, 222]]

pressed = False
released = False
bubline_start = []

background = [50, 25, 25]
size = [500, 500]

#pygame
display = pygame.display.set_mode(size)
pygame.init()

#functions
def new_bub_color():
    color_index = random.randint(0, len(color_options)-1)
    lvl = random.randrange(85, 115)

    bub_color = []
    for val in color_options[color_index]:
        bub_color.append(val*(lvl/100))
    return bub_color


def bubble_line():
    global display, pressed, bubline_start, released, bubbles, color_options
    
    if len(bubbles) > 0:
        if not bubbles[-1][0] == 0:
            #first frame of click
            bub_color = new_bub_color()

            bubbles.append([0, bub_color, [bubline_start, list(pygame.mouse.get_pos())]])
            pygame.draw.line(display, bub_color, bubline_start, pygame.mouse.get_pos())
        else:
            #draw after drags
            pygame.draw.line(display, bubbles[-1][1], bubbles[-1][2][0], list(pygame.mouse.get_pos()))            
            bubbles[-1][2][1] = list(pygame.mouse.get_pos())# <-- HERE
    else:
        #first bubble
        bub_color = new_bub_color()
        
        bubbles.append([0, bub_color, [bubline_start, list(pygame.mouse.get_pos())]])
        pygame.draw.line(display, bub_color, bubline_start, pygame.mouse.get_pos())

    if released:
        bubbles[-1][0] = 1
        bubbles[-1][2][1] = list(pygame.mouse.get_pos())# <-- HERE
        released = False


def cover_prev_frame():
    global bubbles, background, size
    min_pos = []
    max_pos = []

    for bubble in bubbles:
        min_pos = bubble[2][0]
        max_pos = bubble[2][0]

        for point in bubble[2]:
            #x min and max
            if point[0] < min_pos[0]:
                min_pos[0] = point[0]
            elif point[0] > max_pos[0]:
                max_pos[0] = point[0]

            #y min and max
            if point[1] < min_pos[1]:
                min_pos[1] = point[1]
            elif point[1] > max_pos[1]:
                max_pos[1] = point[1]
        max_pos = [max_pos[0]-min_pos[0]+1, max_pos[1]-min_pos[1]+1]

        if type(background) == str:
            #image background
            later = True

        elif type(background) == list:
            #solid color background
            pygame.draw.rect(display, background, pygame.Rect(min_pos, max_pos))


while True:
    pygame.event.pump()
    events = pygame.event.get()

    for event in events:
        if event.type == pygame.QUIT:
            pygame.quit()

        elif event.type == pygame.MOUSEBUTTONDOWN and not pressed:
            bubline_start = list(pygame.mouse.get_pos())
            pressed = True
            
        elif event.type == pygame.MOUSEBUTTONUP and pressed:
            pressed = False
            released = True

    cover_prev_frame()
    if pressed or released:
        bubble_line()

    try:
        pygame.display.update()
    except:
        break

  • 您的代码中只有一个 bubline_start 列表。 bubbles 数组中的每个条目都有一个对该列表的引用。如果您更改bubline_start,则会更改列表中的每个条目。我怀疑你想让bubline_start[:] 制作一个新副本。
  • 我不知道 python 做到了,我假设是 3.x 的一部分。但是问题仍然存在,我标记的行仍在更改列表中第一项的值,当我写它来更改第二项时,只有第二项。
  • FWIW,这就是 Python 从一开始就工作的方式。这是最常见的 Python 程序员错误之一。您可能会考虑创建一个class Bubble 来保存所有气泡状态信息,这样您就不必执行[-1][2][1]
  • 你要这个画什么?

标签: python list pygame nested-lists


【解决方案1】:

if not bubbles[-1][0] == 0: 就是False,只要鼠标没有松开。因此添加许多线段,每个线段都从bubline_start 开始,到当前鼠标位置结束。
您必须在每一帧中重新绘制场景。 bubbles 是一个气泡列表,每个气泡都有一个点列表。按住鼠标时,将新点添加到列表中的最后一个气泡。按下鼠标时开始一个新气泡,松开鼠标时结束一个气泡。这大大简化了您的代码。

最小的例子

import pygame, random

size = [500, 500]
pygame.init()
display = pygame.display.set_mode(size)
clock = pygame.time.Clock()

pressed = False
bubbles = []
background = [50, 25, 25]

run = True
while run:
    clock.tick(100)
    events = pygame.event.get()
    for event in events:
        if event.type == pygame.QUIT:
            run = False

        elif event.type == pygame.MOUSEBUTTONDOWN:
            start_pos = list(event.pos)
            bubble_color = pygame.Color(0)
            bubble_color.hsla = (random.randrange(0, 360), 100, 50, 100)
            bubbles.append((bubble_color, [start_pos]))
            pressed = True

        elif event.type == pygame.MOUSEMOTION and pressed:
            new_pos = list(event.pos)
            if len(bubbles[-1][1]) > 0 and bubbles[-1][1] != new_pos:  
                bubbles[-1][1].append(new_pos)
            
        elif event.type == pygame.MOUSEBUTTONUP:
            pressed = False
            end_pos = list(event.pos)
            if len(bubbles[-1][1]) > 0 and bubbles[-1][1] != end_pos:  
                bubbles[-1][1].append(list(event.pos))

    display.fill(background)
    for i, bubble in enumerate(bubbles):
        if len(bubble[1]) > 1:
            closed = not pressed or i < len(bubbles) - 1
            pygame.draw.lines(display, bubble[0], closed, bubble[1], 3)
    pygame.display.update()

pygame.quit()

对于动画,我建议创建一个代表气泡的类和一个方法animate,它可以慢慢地将多边形变成一个圆。

最小的例子

import pygame, random

size = [500, 500]
pygame.init()
display = pygame.display.set_mode(size)
clock = pygame.time.Clock()

class Bubble:
    def __init__(self, start):
        self.color = pygame.Color(0)
        self.color.hsla = (random.randrange(0, 360), 100, 50, 100)
        self.points = [list(start)]
        self.closed = False
        self.finished = False
    def add_point(self, point, close):
        self.points.append(list(point))
        self.closed = close
        if self.closed:
            x_, y_ = list(zip(*self.points))
            x0, y0, x1, y1 = min(x_), min(y_), max(x_), max(y_)
            rect = pygame.Rect(x0, y0, x1-x0, y1-y0)
            self.center = rect.center
            self.radius = max(*rect.size) // 2
    def animate(self):
        if self.closed and not self.finished:
            cpt = pygame.math.Vector2(self.center) + (0.5, 0.5)
            self.finished = True
            for i, p in enumerate(self.points):
                pt = pygame.math.Vector2(p)
                v = pt - cpt
                l = v.magnitude()
                if l + 0.5 < self.radius:
                    self.finished = False
                v.scale_to_length(min(self.radius, l+0.5))
                pt = cpt + v
                self.points[i] = [pt.x, pt.y]
                
    def draw(self, surf):
        if self.finished:
            pygame.draw.circle(surf, self.color, self.center, self.radius, 3)
        elif len(self.points) > 1:
            pygame.draw.lines(surf, self.color, self.closed, self.points, 3)

bubbles = []
pressed = False
background = [50, 25, 25]

run = True
while run:
    clock.tick(100)
    events = pygame.event.get()
    for event in events:
        if event.type == pygame.QUIT:
            run = False

        elif event.type == pygame.MOUSEBUTTONDOWN:
            bubbles.append(Bubble(event.pos))
            pressed = True

        elif event.type == pygame.MOUSEMOTION and pressed:
            bubbles[-1].add_point(event.pos, False)
            
        elif event.type == pygame.MOUSEBUTTONUP:
            bubbles[-1].add_point(event.pos, True)
            pressed = False

    for bubble in bubbles:
        bubble.animate()

    display.fill(background)
    for bubble in bubbles:
        bubble.draw(display)
    pygame.display.update()

pygame.quit()

【讨论】:

  • 我已经更新了帖子以包含我正在尝试做的一般想法。虽然,答案和代码的速度做得很好,但这不是我想要的。
  • 您是否正在寻找类似的东西Looping mousebutton down to draw lines
  • . .哇。您的编辑改进并完成了我的整个项目。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-19
相关资源
最近更新 更多