如何绘制气泡并将其动画化为圆圈

kil*_*rp7 6 python pygame list nested-lists

我正在尝试制作一个 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

Run Code Online (Sandbox Code Playgroud)

Rab*_*d76 18

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()
Run Code Online (Sandbox Code Playgroud)

对于动画,我建议创建一个代表气泡的类和一个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()
Run Code Online (Sandbox Code Playgroud)

  • 。。哇。您的编辑改进并完成了我的整个项目。 (3认同)