如何在Pygame中绘制带有颜色渐变的线条?

问题描述 投票:0回答:1

我希望绘制一系列具有颜色渐变的线条,以便颜色从亮白色渐变为黑色或完全透明:

enter image description here

理想情况下,

pygame.draw.lines()
会接受一个列表作为
color
参数,每个顶点使用一种颜色,或者端点使用两种颜色。 API中没有这样的东西,如何实现自己的渐变线绘制功能呢?

该线可以是一个像素宽,并且不必进行抗锯齿,但我希望有一种比使用

pygame.gfxdraw.pixel()
实现 Bresenham 算法更好的方法。

python pygame
1个回答
0
投票

这当然是可能的,但 PyGame 没有提供现成的解决方案。

在下面的示例中,我展示了一个

GradientLine
类。 这是通过计算从原始颜色到最终颜色的颜色步长来实现的。 对线条的每个部分使用阶梯颜色。

它假设颜色数量少于像素数量,并进行相应优化。这是一个合理的假设,因为大多数消费者都会表现出:

  • 每个颜色通道仅支持 256 个不同的步骤
  • 通常有很多超过256像素的屏幕分辨率

因此,该类首先生成组成屏幕上线条的像素列表。 当算法遍历像素时,它会寻找“显着”(即:可见)颜色变化。 如果发现颜色变化,则存储线段并开始新线段。 但如果颜色变化不显着,则该像素将被忽略,以创建更长的单色线。

screenshot import pygame # Window size WINDOW_WIDTH = 800 WINDOW_HEIGHT = 800 BLACK = ( 0, 0, 0) WHITE = (255, 255, 255) RED = (220, 0, 0) GREEN = ( 0, 220, 0) BLUE = ( 0, 0, 220) ORANGE = (255, 165, 0) def clamp( point ): """ Ensure the point is inside the window """ x, y = point x = max( 0, x ) x = min( WINDOW_WIDTH-1, x ) y = max( 0, y ) y = min( WINDOW_HEIGHT-1, y ) return x, y def getLinePath( start_pos, end_pos ): """ Using Bresenham's Line algorithm, get a list of all the points along a straight-line path from the start to the end (inclusive). Note that this includes diagonal movement """ # clamp range to window x0, y0 = clamp( start_pos ) x1, y1 = clamp( end_pos ) points = [] # ref: https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm#Algorithm_for_integer_arithmetic dx = abs(x1 - x0) if x0 < x1: sx = 1 else: sx = -1 dy = -abs(y1 - y0) if y0 < y1: sy = 1 else: sy = -1 error = dx + dy while True: points.append( ( x0,y0 ) ) if x0 == x1 and y0 == y1: break e2 = 2 * error if e2 >= dy: if x0 == x1: break error = error + dy x0 = x0 + sx if e2 <= dx: if y0 == y1: break error = error + dx y0 = y0 + sy return points class GradientLine: def __init__( self, start_point, end_point, start_colour, end_colour, thickness:int=1 ): self.lines = [] self.width = thickness line_pixels = getLinePath( start_point, end_point ) pixel_count = float( len( line_pixels ) ) red_step = float( end_colour[0] - start_colour[0] ) / pixel_count green_step = float( end_colour[1] - start_colour[1] ) / pixel_count blue_step = float( end_colour[2] - start_colour[2] ) / pixel_count red = float( start_colour[0] ) green = float( start_colour[1] ) blue = float( start_colour[2] ) # It is too inefficient to continually draw a huge whack of pixels # So Identify a bunch of line-segments that are the same colour start_point = None for pixel in line_pixels: if ( start_point == None ): start_point = pixel start_red, start_green, start_blue = ( red, green, blue ) else: # calculate the next colour # if that colour significantly different, output a line segment if ( abs( start_red - red ) > 1.0 or \ abs( start_green - green ) > 1.0 or \ abs( start_blue - blue ) > 1.0 ): colour = ( int( start_red ), int( start_green ), int( start_blue ) ) self.lines.append( ( start_point, pixel, colour ) ) start_point = None # crawl the gradient red += red_step green += green_step blue += blue_step def draw( self, surface:pygame.Surface ): """ Draw a line from start to end, changing colour along the way """ for segment in self.lines: point_a, point_b, colour = segment pygame.draw.line( surface, colour, point_a, point_b, self.width ) ### ### MAIN ### pygame.init() window = pygame.display.set_mode( ( WINDOW_WIDTH, WINDOW_HEIGHT ), pygame.HWSURFACE ) pygame.display.set_caption("Gradient Line") # Define some Gradient Lines grad_lines = [] grad_lines.append( GradientLine( ( 0,0 ), ( 799,799 ), BLUE, ORANGE, 5 ) ) grad_lines.append( GradientLine( ( 0,399 ), ( 799,399 ), RED, GREEN, 5 ) ) grad_lines.append( GradientLine( ( 50,150 ), ( 50, 300 ), WHITE, BLACK, 5 ) ) # Main loop clock = pygame.time.Clock() running = True while running: time_now = pygame.time.get_ticks() # Handle user-input for event in pygame.event.get(): if ( event.type == pygame.QUIT ): running = False # Paint the window window.fill( BLACK ) # Draw the walking path to the most recent mouse-click (if any) for line in grad_lines: line.draw( window ) pygame.display.flip() # Clamp FPS clock.tick(60) pygame.quit()

	
© www.soinside.com 2019 - 2024. All rights reserved.