What you will learn
This chapter explores two fundamental concepts: the color system (RGB, HSV, transparency) and Pygame's coordinate system. You will learn to generate rainbow colors, understand where the point (0, 0) is located, and display a debug grid to better visualize element positioning.
The concept
The coordinate system
In Pygame, the point (0, 0) is at the top-left corner of the window. The X axis goes right, the Y axis goes down. This is the opposite of what you learned in math class, where Y goes up.
For an 800x600 window:
- Top-left corner is
(0, 0) - Top-right corner is
(799, 0) - Bottom-left corner is
(0, 599) - Bottom-right corner is
(799, 599)
Colors
Pygame supports several ways to define colors:
- RGB: tuple of 3 integers
(red, green, blue)from 0 to 255 - RGBA: tuple of 4 integers with an alpha channel (transparency) from 0 (invisible) to 255 (opaque)
- HSV: via
pygame.Color, you can define hue, saturation and value
The HSV model is particularly useful for generating gradients: by varying the hue from 0 to 360, you get a complete rainbow.
Step by step
1. Generating rainbow colors
Our rainbow_color function uses Pygame's HSV model. We vary the hue based on the row number to get a uniform color spectrum.
def rainbow_color(row, total_rows):
"""Generate a rainbow color based on row position."""
hue = int(360 * row / total_rows)
color = pygame.Color(0)
color.hsva = (hue, 100, 100, 100)
return (color.r, color.g, color.b)
pygame.Color is a powerful object. Its hsva property accepts a tuple (hue, saturation, value, alpha). Hue ranges from 0 to 360 (color wheel), saturation and value from 0 to 100. We then retrieve the r, g, b components to get a standard RGB tuple.
2. Checkerboard effect on bricks
To add visual depth, we alternate brick brightness based on the parity of (row + col). It is a simple but effective checkerboard effect.
for row in range(BRICK_ROWS):
for col in range(BRICK_COLS):
x = BRICK_OFFSET_X + col * (BRICK_WIDTH + BRICK_PADDING)
y = BRICK_OFFSET_Y + row * (BRICK_HEIGHT + BRICK_PADDING)
color = rainbow_color(row, BRICK_ROWS)
# Alternate brightness for checkerboard effect
if (row + col) % 2 == 0:
color = tuple(min(255, c + 30) for c in color)
pygame.draw.rect(screen, color, (x, y, BRICK_WIDTH, BRICK_HEIGHT))
pygame.draw.rect(screen, (255, 255, 255),
(x, y, BRICK_WIDTH, BRICK_HEIGHT), 1)
The second draw.rect call with width=1 draws a thin white outline around each brick, visually separating them.
3. Coordinate grid
To debug element placement, we add a grid that toggles with the G key. It draws lines every 50 pixels.
show_grid = False
# In the event loop:
if event.key == pygame.K_g:
show_grid = not show_grid
# In the draw section:
if show_grid:
for gx in range(0, SCREEN_WIDTH, 50):
pygame.draw.line(screen, (50, 50, 70), (gx, 0), (gx, SCREEN_HEIGHT))
for gy in range(0, SCREEN_HEIGHT, 50):
pygame.draw.line(screen, (50, 50, 70), (0, gy), (SCREEN_WIDTH, gy))
4. Displaying mouse coordinates
To better understand the coordinate system, we continuously display the mouse position. We use pygame.mouse.get_pos() and text rendering (which we will cover in detail in chapter 8).
mouse_x, mouse_y = pygame.mouse.get_pos()
font = pygame.font.SysFont("monospace", 14)
coord_text = font.render(f"({mouse_x}, {mouse_y})", True, (150, 150, 150))
screen.blit(coord_text, (10, SCREEN_HEIGHT - 25))
Key takeaways
Tip: pygame.Color also supports English color names: pygame.Color("red"), pygame.Color("dodgerblue"). Handy for quick prototyping.
Common pitfall: the alpha channel (RGBA) does not work directly with pygame.draw on the main surface. To use transparency, you must draw on an intermediate surface with SRCALPHA, then copy it to the screen with blit(). We will cover this in chapter 5.
Pygame functions used:
pygame.Color: color object with RGB, RGBA, HSV supportcolor.hsva: set/get color in Hue-Saturation-Valuepygame.mouse.get_pos(): current cursor positionpygame.font.SysFont(): load a system fontfont.render(): convert text to a Surface
Complete code
"""Brick Breaker - Chapter 3: Colors and Coordinates"""
import pygame
import sys
pygame.init()
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
FPS = 60
BG_COLOR = (20, 20, 40)
PADDLE_WIDTH = 100
PADDLE_HEIGHT = 15
PADDLE_COLOR = (200, 200, 200)
paddle_x = SCREEN_WIDTH // 2 - PADDLE_WIDTH // 2
paddle_y = SCREEN_HEIGHT - 40
BALL_RADIUS = 8
BALL_COLOR = (255, 255, 255)
ball_x = SCREEN_WIDTH // 2
ball_y = SCREEN_HEIGHT // 2
BRICK_ROWS = 6
BRICK_COLS = 10
BRICK_WIDTH = 70
BRICK_HEIGHT = 20
BRICK_PADDING = 5
BRICK_OFFSET_X = 30
BRICK_OFFSET_Y = 50
def rainbow_color(row, total_rows):
"""Generate a rainbow color based on row position."""
hue = int(360 * row / total_rows)
color = pygame.Color(0)
color.hsva = (hue, 100, 100, 100)
return (color.r, color.g, color.b)
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption("Brick Breaker - Chapter 3")
clock = pygame.time.Clock()
font = pygame.font.SysFont("monospace", 14)
show_grid = False
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
running = False
if event.key == pygame.K_g:
show_grid = not show_grid
mouse_x, mouse_y = pygame.mouse.get_pos()
screen.fill(BG_COLOR)
# Draw bricks with rainbow colors and slight alpha variation
for row in range(BRICK_ROWS):
for col in range(BRICK_COLS):
x = BRICK_OFFSET_X + col * (BRICK_WIDTH + BRICK_PADDING)
y = BRICK_OFFSET_Y + row * (BRICK_HEIGHT + BRICK_PADDING)
color = rainbow_color(row, BRICK_ROWS)
# Alternate brightness for checkerboard effect
if (row + col) % 2 == 0:
color = tuple(min(255, c + 30) for c in color)
pygame.draw.rect(screen, color, (x, y, BRICK_WIDTH, BRICK_HEIGHT))
pygame.draw.rect(screen, (255, 255, 255),
(x, y, BRICK_WIDTH, BRICK_HEIGHT), 1)
# Draw paddle
pygame.draw.rect(screen, PADDLE_COLOR,
(paddle_x, paddle_y, PADDLE_WIDTH, PADDLE_HEIGHT))
# Draw ball
pygame.draw.circle(screen, BALL_COLOR, (ball_x, ball_y), BALL_RADIUS)
# Show grid overlay
if show_grid:
for gx in range(0, SCREEN_WIDTH, 50):
pygame.draw.line(screen, (50, 50, 70),
(gx, 0), (gx, SCREEN_HEIGHT))
for gy in range(0, SCREEN_HEIGHT, 50):
pygame.draw.line(screen, (50, 50, 70),
(0, gy), (SCREEN_WIDTH, gy))
# Show coordinates
coord_text = font.render(f"({mouse_x}, {mouse_y})", True, (150, 150, 150))
screen.blit(coord_text, (10, SCREEN_HEIGHT - 25))
# Show instructions
grid_text = font.render("[G] Toggle grid [ESC] Quit", True, (100, 100, 100))
screen.blit(grid_text, (SCREEN_WIDTH - 280, SCREEN_HEIGHT - 25))
pygame.display.flip()
clock.tick(FPS)
pygame.quit()
sys.exit()
Download
Download the source code for this chapter: brick-breaker-ch03.zip
