Как мне нарисовать линию без обновления всего экрана в pygame?

#python #python-3.x #pygame

#python #python-3.x #pygame

Вопрос:

Я пытаюсь создать визуальное представление, включающее движущуюся линию и статический фон. Есть ли способ визуализировать движущуюся линию без необходимости обновлять весь экран? Я знаю pygame.display.flip() , но для этого потребуется, чтобы программа «размывала» фон в каждом кадре, чего я хочу избежать.

Я пытался создать объект rect для фона и один для строки, а затем сделать pygame.display.update(line_rect) , но я не мог найти способ включить строку в rect.

Все идеи приветствуются!

Ответ №1:

Если у вас есть линия, которая определяется точками ( x1 , y1 ) и ( x2 , y2 ), ограничивающий прямоугольник можно вычислить с min помощью и max :

 min_x, min_y = min(x1, x2), min(y1, y2)
max_x, max_y = max(x1, x2), max(y1, y2)
line_rect = pygame.Rect(min_x, min_y, max_x-min_x, max_y-min_y)
  

В качестве альтернативы вы можете соединить два прямоугольника размером 1×1 с union одним, который полностью покрывает площадь двух предоставленных прямоугольников:

 line_rect = pygame.Rect(x1, y1, 1, 1).union((x2, y2, 1, 1))
  

Минимальный пример:

 import pygame
pygame.init()
window = pygame.display.set_mode((300, 300))
clock = pygame.time.Clock()

center_x, center_y = window.get_rect().center
radius = 100
line_vector = pygame.math.Vector2(1, 0)
angle = 0
prev_line_rect = None

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

    window_center = window.get_rect().center

    rot_vector = line_vector.rotate(angle) * radius
    x1, y1 = round(center_x   rot_vector.x), round(center_y   rot_vector.y)
    x2, y2 = round(center_x - rot_vector.x), round(center_y - rot_vector.y)
    angle  = 1

    line_rect = pygame.Rect(x1, y1, 1, 1).union((x2, y2, 1, 1))
    
    copy_rect = line_rect.copy()
    if prev_line_rect:
        line_rect.union_ip(prev_line_rect)
        line_rect.inflate_ip(2, 2)
    prev_line_rect = copy_rect

    window.fill(0, line_rect)
    pygame.draw.line(window, (255, 255, 255), (x1, y1), (x2, y2), 3)

    pygame.display.update(line_rect)

pygame.quit()
exit()
  

Комментарии:

1. Прежде всего, спасибо вам за ваше время и усилия. Поправьте меня, если я ошибаюсь, надеюсь, я правильно понял. Допустим, я хочу добавить другой цвет (или изображение) для фона, поскольку по умолчанию используется черный. Я должен был бы сделать window.fill(COLOR, line_rect) или удалить изображение. Ни один из них не работает: первый заполняет цветом только область, в которой вращается линия, а второй требует pygame.display.flip() отображения изображения. Могу ли я сделать что-либо из вышеперечисленного, изменив ваш код другим способом?

2. @BillTheKid Я понятия не имею, что ты имеешь в виду. Мне трудно угадать ваше намерение, потому что вы не предоставили никакого кода. Я не могу угадать ваши ошибки. Вам нужно перерисовать всю область, которая покрыта областью обновления. В любом случае, в наши дни принято перерисовывать всю сцену в каждом кадре. «Дешевле» перерисовать всю сцену, чем управлять подкатегориями обновлений

3. Возможно, я неправильно понял, как работает Rect . Возможно, будет невозможно сделать то, что я собираюсь сделать. Если вы хотите воссоздать мою последнюю «ошибку», замените window.fill(0, line_rect) на window.fill(100, line_rect . Я ожидал бы, что это изменение заполнит весь экран синим цветом, но оно просто рисует круг. В любом случае, еще раз спасибо за ваше время и усилия, вы уже научили меня некоторым вещам. Я попытаюсь найти другой способ обойти мою проблему.

4. @BillTheKid Это невозможно. Перерисовывается вся область. Конечно, вы можете полностью window.fill(0, line_rect) полностью пропустить, но тогда линии из всех предыдущих кадров останутся там, и вы просто рисуете по линии друг над другом. Вы не можете волшебным образом позволить исчезнуть строке предыдущего кадра. Все, что рисуется, — это просто куча пикселей на поверхности . Пиксель имеет только цвет. Когда что-то рисуется сверху, предыдущий цвет теряется навсегда.

5. Если вы используете сплошной фон, один из подходов заключается в том, чтобы перерисовать предыдущую строку в цвет фона, а затем нарисовать новую линию в цвете переднего плана. (Эффективно «стирая» пиксели, на которые была записана предыдущая строка.)