6

Info: I am drawing a rectangle using pygame but would like to have a gradient added to the rectangle so that it looks like there is a shadow.

Right now here is my code:

light_green = (0, 255, 0)
dark_green = (0, 100, 0)

pygame.draw.rect(screen, light_green, rect_dims) # Draws a rectangle without a gradient


Question: I would like to create a linear transition between light green and dark green without drawing a bunch of lines stacked on top of each other (because that is very slow), so is there a way that I would be able to do this using pygame?

  • 1
    [Here's how to do it](https://stackoverflow.com/a/32532502/355230) using the PIL module (if nothing else, you could use it to generate an image file and use that), which you might be able to adapt to pygame. There's also a more generic method describing the math involved in this other [answer of mine](https://stackoverflow.com/questions/10901085/range-values-to-pseudocolor/10902473#10902473). – martineau Jun 12 '20 at 02:55
  • 1
    You could also define a small bitmap, then use `smoothscale` to stretch it to size. This would create a gradient. – Kingsley Jun 12 '20 at 02:58
  • Could you give me an example? –  Jun 12 '20 at 02:59
  • @Kingsley: That's an excellent suggestion! I've used a very similar technique in the past (in C++) with a library that had the ability to scale and transform image files (like I believe pygame can do). – martineau Jun 12 '20 at 03:01
  • 2
    Leon: `smoothscale` is [documented](https://www.pygame.org/docs/search.html?q=smoothscale) and there's examples of using it in the [pygame documentation](http://www.pygame.org/docs/). – martineau Jun 12 '20 at 03:10

1 Answers1

4

Here's a quick test of using smoothscale. It starts off with a 2x2 coloured bitmap, then scales it arbitrarily before drawing the result to the screen.

While PyGame will use hardware (if available) to do the stretch, I wouldn't expect this to be very fast.

import pygame

# Window size
WINDOW_WIDTH    = 400
WINDOW_HEIGHT   = 400

### initialisation
pygame.init()
window = pygame.display.set_mode( ( WINDOW_WIDTH, WINDOW_HEIGHT ) )
pygame.display.set_caption("Gradient Rect")

def gradientRect( window, left_colour, right_colour, target_rect ):
    """ Draw a horizontal-gradient filled rectangle covering <target_rect> """
    colour_rect = pygame.Surface( ( 2, 2 ) )                                   # tiny! 2x2 bitmap
    pygame.draw.line( colour_rect, left_colour,  ( 0,0 ), ( 0,1 ) )            # left colour line
    pygame.draw.line( colour_rect, right_colour, ( 1,0 ), ( 1,1 ) )            # right colour line
    colour_rect = pygame.transform.smoothscale( colour_rect, ( target_rect.width, target_rect.height ) )  # stretch!
    window.blit( colour_rect, target_rect )                                    # paint it


### Main Loop
clock = pygame.time.Clock()
finished = False
while not finished:

    # Handle user-input
    for event in pygame.event.get():
        if ( event.type == pygame.QUIT ):
            done = True

    # Update the window
    window.fill( ( 0,0,0 ) )
    gradientRect( window, (0, 255, 0), (0, 100, 0), pygame.Rect( 100,100, 100, 50 ) )
    gradientRect( window, (255, 255, 0), (0, 0, 255), pygame.Rect( 100,200, 128, 64 ) )
    pygame.display.flip()

    # Clamp FPS
    clock.tick_busy_loop(60)

pygame.quit()
Kingsley
  • 14,398
  • 5
  • 31
  • 53