2.11 Drawing Introduction
Here is a list of things that you can draw:
http://www.pygame.org/docs/ref/draw.html
A program can draw things like rectangles, polygons, circles, ellipses, arcs, and lines. We will also cover how to display text with graphics. Bitmapped graphics such as images are covered in later unit. If you decide to look at that pygame reference, you might see a function definition like this:
pygame.draw.rect(Surface, color, Rect, width=0)
A frequent cause of confusion is the part of the line that says width=0. What this means is that if you do not supply a width, it will default to zero. Thus this function call: pygame.draw.rect(screen, RED, [55, 50, 20, 25])
Is the same as this function call:
pygame.draw.rect(screen, RED, [55, 50, 20, 25], 0)
What will not work, is attempting to copy the line and put width = 0 in the parentheses.
# This fails and the error the computer gives you is really hard # to understand.
pygame.draw.rect(screen, RED, [55, 50, 20, 25], width=0)
2.12 Drawing Lines
The code example below shows how to draw a line on the screen. It will draw on the screen a green line from (0, 0) to (100, 100) that is 5 pixels wide. Remember that GREEN is a variable that was defined earlier as a list of three RGB values.
Drawing a single line
# Draw on the screen a green line from (0, 0) to
# (100, 100) that is 5 pixels wide.
pygame.draw.line(screen, GREEN, [0, 0], [100, 100], 5)
Use the base template from the prior example and add the code to draw lines. Read the comments to figure out exactly where to put the code. Try drawing lines with different thicknesses, colors, and locations. Draw several lines.
2.13 Drawing Lines With Loops and Offsets
Programs can repeat things over and over. The next code example draws a line over and over using a loop. Programs can use this technique to do multiple lines, and even draw an entire car.
Putting a line drawing command inside a loop will cause multiple lines being drawn to the screen. But here's the catch. If each line has the same starting and ending coordinates, then each line will draw on top of the other line. It will look like only one line was drawn.
To get around this, it is necessary to offset the coordinates each time through the loop. So the first time through the loop the variable y_offset is zero. The line in the code below is drawn from (0,10) to (100, 110). The next time through the loop y_offset increased by 10. This causes the next line to be drawn to have new coordinates of (0, 20) and (100, 120). This continues each time through the loop shifting the coordinates of each line down by 10 pixels.
Drawing a series of lines
# Draw on the screen several lines from (0, 10) to
# (100, 110) 5 pixels wide using a while loop
y_offset = 0
while y_offset < 100:
pygame.draw.line(screen,RED,[0,10+y_offset],
[100,110+y_offset],5)
y_offset = y_offset + 10
This same code could be done even more easily with a for loop:
Drawing a series of lines
# Draw on the screen several lines from (0,10) to
#(100,110)5 pixels wide using a for loop
for y_offset in range(0, 100, 10):
pygame.draw.line(screen,RED,[0,10+y_offset],
[100,110+y_offset],5)
Run this code and try using different changes to the offset. Try creating an offset with different values. Experiment with different values until exactly how this works is obvious.
For example, here is a loop that uses sine and cosine to create a more complex set of offsets and produces the image shown.
Complex offsets
# For this code, make sure to have a line that says
# "import math" at the top of your program. Otherwise
# it won't know what math.sin is.
for i in range(200):
radians_x = i / 20
radians_y = i / 6
x = int(75 * math.sin(radians_x)) + 200
y = int(75 * math.cos(radians_y)) + 200
pygame.draw.line(screen, BLACK, [x,y], [x+5,y], 5)
Multiple elements can be drawn in one for loop, such as this code which draws the multiple X's.
Drawing a series of x's
for x_offset in range(30, 300, 30):
pygame.draw.line(screen,BLACK,[x_offset,100],
[x_offset-10,90],2)
pygame.draw.line(screen,BLACK,[x_offset,90],
[x_offset-10,100],2)
2.14 Drawing a Rectangle
When drawing a rectangle, the computer needs coordinates for the upper left rectangle corner (the origin), and a height and width.
The figure shows a rectangle (and an ellipse, which will be explained later) with the origin at (20, 20), a width of 250 and a height of 100. When specifying a rectangle the computer needs a list of these four numbers in the order of (x, y, width, height).
The next code example draws this rectangle. The first two numbers in the list define the upper left corner at (20, 20). The next two numbers specify first the width of 250 pixels, and then the height of 100 pixels.
The 2 at the end specifies a line width of 2 pixels. The larger the number, the thicker the line around the rectangle. If this number is 0, then there will not be a border around the rectangle. Instead it will be filled in with the color specified.
Drawing a rectangle
# Draw a rectangle
pygame.draw.rect(screen,BLACK,[20,20,250,100],2)
2.15 Drawing an ellipse
An ellipse is drawn just like a rectangle. The boundaries of a rectangle are specified, and the computer draws an ellipses inside those boundaries.
The most common mistake in working with an ellipse is to think that the starting point specifies the center of the ellipse. In reality, nothing is drawn at the starting point. It is the upper left of a rectangle that contains the ellipse.
Looking back at the previous figure one can see an ellipse 250 pixels wide and 100 pixels tall. The upper left corner of the 250x100 rectangle that contains it is at (20, 20). Note that nothing is actually drawn at (20, 20). With both drawn on top of each other it is easier to see how the ellipse is specified.
Drawing an ellipse
# Draw an ellipse, using a rectangle as the outside
# boundaries
pygame.draw.ellipse(screen, BLACK, [20,20,250,100], 2)
2.16 Drawing an Arc
What if a program only needs to draw part of an ellipse? That can be done with the arc command. This command is similar to the ellipse command, but it includes start and end angles for the arc to be drawn. The angles are in radians.
The code example below draws four arcs showing four difference quadrants of the circle. Each quadrant is drawn in a different color to make the arcs sections easier to see. The result of this code is shown in figure above.
Drawing arcs
# Draw an arc as part of an ellipse. Use
# radians to determine what angle to draw.
import math
PI = math.pi
pygame.draw.arc(screen, GREEN, [100,100,250,200],
PI/2, PI, 2)
pygame.draw.arc(screen, BLACK, [100,100,250,200],
0, PI/2, 2)
pygame.draw.arc(screen, RED, [100,100,250,200],
3*PI/2, 2*PI, 2)
pygame.draw.arc(screen, BLUE, [100,100,250,200],
PI, 3*PI/2, 2)
2.17 Drawing a Polygon
The next line of code draws a polygon. The triangle shape is defined with three points at (100, 100) (0, 200) and (200, 200). It is possible to list as many points as desired. Note how the points are listed. Each point is a list of two numbers, and the points themselves are nested in another list that holds all the points. This code draws what can be seen in the figure below.
Drawing a polygon
# This draws a triangle using the polygon command
pygame.draw.polygon(screen, BLACK, [[100,100],
[0,200], [200,200]], 5)
2.18 Drawing Text
Text is slightly more complex. There are three things that need to be done. First, the program creates a variable that holds information about the font to be used, such as what typeface and how big.
Second, the program creates an image of the text. One way to think of it is that the program carves out a “stamp” with the required letters that is ready to be dipped in ink and stamped on the paper.
The third thing that is done is the program tells where this image of the text should be stamped (or “blit'ed”) to the screen.
Here's an example:
Drawing text on the screen
# Select the font to use, size, bold, italics
font = pygame.font.SysFont('Calibri', 25, True, False)
# Render the text. "True" means anti-aliased text.
# Black is the color. The variable BLACK was defined
# above as a list of [0, 0, 0]
# Note: This line creates an image of the letters,
# but does not put it on the screen yet.
text = font.render("My text",True,BLACK)
# Put the image of the text on the screen at 250x250
screen.blit(text, [250, 250])
Want to print the score to the screen? That is a bit more complex. This does not work:
text = font.render("Score: ", score, True, BLACK)
Why? A program can't just add extra items to font.render like the print statement. Only one string can be sent to the command, therefore the actual value of score needs to be appended to the “Score: ” string. But this does not work either:
text = font.render("Score: " + score, True, BLACK)
If score is an integer variable, the computer doesn't know how to add it to a string. You, the programmer, must convert the score to a string. Then add the strings together like this:
text = font.render("Score: " + str(score), True, BLACK)
Now you know how to print the score. If you want to print a timer, that requires print formatting, discussed in a chapter later on.
"""
Simple graphics demo
"""
# Import a library of functions called 'pygame'
import pygame
# Initialize the game engine
pygame.init()
# Define some constants
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
BLUE = (0, 0, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
PI = 3.141592653
# Set the height and width of the screen
size = (400, 500)
screen = pygame.display.set_mode(size)
pygame.display.set_caption("Drawing Example")
# Loop until the user clicks the close button.
done = False
clock = pygame.time.Clock()
# Loop as long as done == False
while not done:
for event in pygame.event.get(): # User did something
if event.type == pygame.QUIT: # If user clicked close
done = True # Flag that we are done so we exit this loop
# All drawing code happens after the for loop and but inside the main while not
# done loop.
# Clear the screen and set the screen background
screen.fill(WHITE)
# Draw on the screen a line from (0,0) to (100,100) 5 pixels wide.
pygame.draw.line(screen, GREEN, [0, 0], [100, 100], 5)
# Draw on the screen several lines from (0,10) to (100,110)
# 5 pixels wide using a loop
for y_offset in range(0, 100, 10):
pygame.draw.line(screen, RED, [0, 10 + y_offset],
[100, 110 + y_offset], 5)
# Draw a rectangle
pygame.draw.rect(screen, BLACK, [20, 20, 250, 100], 2)
# Draw an ellipse, using a rectangle as the outside boundaries
pygame.draw.ellipse(screen, BLACK, [20, 20, 250, 100], 2)
# Draw an arc as part of an ellipse.
# Use radians to determine what angle to draw.
pygame.draw.arc(screen, BLACK, [20, 220, 250, 200],
0, PI / 2, 2)
pygame.draw.arc(screen, GREEN, [20, 220, 250, 200],
PI / 2, PI, 2)
pygame.draw.arc(screen, BLUE, [20, 220, 250, 200],
PI, 3 * PI / 2, 2)
pygame.draw.arc(screen, RED, [20, 220, 250, 200],
3 * PI / 2, 2 * PI, 2)
# This draws a triangle using the polygon command
pygame.draw.polygon(screen, BLACK, [[100, 100], [0, 200],
[200, 200]], 5)
# Select the font to use, size, bold, italics
font = pygame.font.SysFont('Calibri', 25, True, False)
# Render the text. "True" means anti-aliased text.
# Black is the color. This creates an image of the
# letters, but does not put it on the screen
text = font.render("My text", True, BLACK)
# Put the image of the text on the screen at 250x250
screen.blit(text, [250, 250])
# Go ahead and update the screen with what we've drawn.
# This MUST happen after all the other drawing commands.
pygame.display.flip()
# This limits the while loop to a max of 60 times per second.
# Leave this out and we will use all CPU we can.
clock.tick(60)
# Be IDLE friendly
pygame.quit()