2. hello, pygame

In this chapter, we will create a simple example program to give you an idea of what pygame is all about. After that, we’ll extend the program in chapters 3 and 4, going over the basics of Python. The result will be something like the GIF animation below.

No knowledge of Python is assumed, but it is assumed that you have done some simple programming in some language.

This is an interactive application that responds to mouse input and accepts the following operations.

  • Move the mouse pointer: Move the player
  • Left button press: Display text
  • ESC key: Exit

2.1. Preparing a Folder

Let’s prepare a folder for this project.

Open the folder selection dialog from VSCode’s File ‣ Open Folder menu, right-click in the projects folder (where you created the hello folder), and create the hello_pygame folder. Select the created folder and click Select Folder.

Open the Explorer sidebar from the activity bar, and you should see the hello_pygame folder open. Create a new file named hello_pygame.py and open it by double click. You should see hello_pygame.py - hello_pygame - VSCodium (Computer Seminar I) in the title bar of VSCode.

_images/titlebar_hello_pygame_py.png

2.2. Drawing a Figure

To begin with, we will write a program that simply opens a window and displays a certain figure.

hello_pygame.py (ver 1.0)
1import pygame
2
3pygame.init()
4screen = pygame.display.set_mode((600, 400))
5pygame.draw.circle(screen, pygame.Color("red"), (300, 200), 30)
6pygame.display.update()
7pygame.time.wait(5000)
8pygame.quit()
Line 1
The import statement is used to import additional functionality into Python. In this case, we want to use pygame’s functionality.
Line 2
You can leave blank lines as needed. It is easier to read if you leave a space for each chunk of processing.
Line 3

This line initializes pygame.

In Python, we use . (dot operator) in many places. aaa.bbb generally means “bbb belonging to aaa”, and in this line it refers to the function init belonging to the pygame package. As with the print function, it is called by putting round parentheses after it.

The pygame.init function can be called with no arguments and initializes pygame; it should always be called at the beginning of a program that uses pygame.

Line 4

A screen for pygame to draw on is created.

This statement is structured as follows: screen = ... This is the same structure as a statement such as x = 1 + 2. The result of the processing on the right side is assigned to, or substituted into, the variable on the left side.

The right hand side calls a function called set_mode that belongs to the display module that belongs to the pygame package, which you can safely assume is the pygame.display.set_mode function. But sometimes you need to remember the original meaning.

pygame.display.set_mode is a function that specifies the size of the screen. The size is specified by passing a tuple of two integers as an argument. In this example, the size is 600 pixels (width) and 400 pixels (height).

The double pairs of round parentheses may look strange, but they are necessary. If there were only a single pair of parentheses, it would mean passing 600 as the first argument and 400 as the second argument, which is not what pygame.display.set_mode expects. 600 and 400 must be in a tuple, enclosed in parentheses, and passed as a single argument.

The function pygame.display.set_mode returns the configured drawing “window screen” as a result of its operation. The returned screen is assigned to the variable screen on the left side, so that various operations can be performed on screen such as drawing and displaying on the monitor.

It may be astonishing to hear that a screen is assigned to a variable. However, the structure here is exactly the same as in the substitution y = cos(x), where y is the real value returned by the right-hand side function cos. pygame.display.set_mode returns a value of type Surface, which represents the “window screen” in pygame, and is assigned to the variable screen.

screen is just a variable name, so you can rename it to anything you like. For example, you can call it “window” or “canvas” or whatever you like. Of course, in that case, replace screen in the following lines with your own variable name.

Line 5

A circle is drawn on the screen created in line 4, using the function pygame.draw.circle.

It has four arguments. The four arguments are, in order, the surface to draw on, the color, the center coordinate, and the radius.

A color in pygame can be specified with a value returned by pygame.Color function with a string-type argument that represents the name of the color, which is red in this example.

The coordinates can be specified as a tuple of integers or real numbers. The origin is the top-left corner of the surface specified by the first argument, rightward is the positive direction of x, and downward is the positive direction of y. Note that the direction of y is different from that of ordinary mathematics. This is a convention when working with images on a computer.

Line 6
We “drew” the circle in line 5, but it is not yet reflected on the display, so we call pygame.display.update to update it.
Line 7
We have achieved our goal of drawing a shape on the display, but if we exit the program immediately, the window will close in an instant and we will see almost nothing. So, we wait for 5000 ms by calling the function pygame.time.wait.
Line 8
The pygame.quit function terminates pygame. Since this is the last line of the program, it also terminates the execution of the program itself.

Once you have successfully typed, don’t forget to save the file if you haven’t already done so. Once saved, run Run ‣ Run Without Debugging with hello_pygame.py displayed. A black window with a red circle will open and close on its own after 5 seconds, indicating success.

I’m getting an error and can’t run it.
It’s a short piece of code, so if you compare it with the sample carefully you can probably find the error, but looking at the error message carefully can often give you a clue.

Especially if you know the line number where the error occurred. When you run a Python program in VSCode, a tab labeled “Terminal” opens in the panel area, which acts like a Windows command prompt. For example, lets’s assume the following message is displayed.

pygame 2.0.1 (SDL 2.0.14, Python 3.9.5)
Hello from the pygame community. https://www.pygame.org/contribute.html
Traceback (most recent call last):
  File "c:\cs1\projects\hello_pygame\hello_pygame.py", line 5, in <module>
    pygame.draw.circle(screen, pygame.color("red"), (300, 200), 30)
TypeError: 'module' object is not callable

The first two lines are simply the credit information that pygame is displaying (which it does every time, regardless of whether there is an error or not).

The next lines after that shows where the error occurred. You may see many lines here, but as it says “most recent call last”, so if you want to know “what happened last”, you should look at the last line. In Python, the basic rule is to read the error messages backwards from the bottom like this.

As it turns out, the error “TypeError: ‘module’ object is not callable” occurred in line 5. If you compare line 5 carefully, you will see that the word “Color” which should be capitalized is lower case “color”. This should be fixed.

It is often difficult for beginners to decipher the meaning of error messages. Still, it is useful to pick up words that you can understand and think about them. In this case, the keyword is “is not callable”, which means that the function you are trying to call could not be called. The line 5 tries to call pygame.draw.circle and pygame.Color, suggesting either of them may be suspicious.

What is a type?
A type represents the kind of data used in a program, and defines what kind of values they can take and what kind of operations and manipulations they can apply.

For example, data of type integer can take any of the integers as a value, and operations such as addition, subtraction, multiplication, and so on can be applied to them. Boolean-valued data can take either True or False as a value, and logical operations such as AND and OR can be applied to them.

Similarly, data of type Surface can take as its value a two-dimensional image that can be displayed on a display, and operations such as drawing a shape, extracting a part of the image, and displaying it on the display can be applied.

So, you mean there is a type called Surface in Python, apart from the integer and real number types?
Surface (pygame.Surface, to be precise) is a type defined by pygame.

Many programming languages, including Python, allow you to define your own types. This allows you to increase the level of abstraction in your programs, making them more readable and easier to write. We will discuss this in detail in Chapter 5.

2.2.1. Commit the Changes

Before moving on, let’s commit the contents of this folder to the Git repository.

Since this folder has not been git init’d yet, open Source Control from the activity bar and you should see a button that says Initialize Repository. Click on it. This is the equivalent of git init.

Then, as before, stage changes using the + button on the right side of hello.py, enter a commit message, and click the checkmarked button (Commit). The message can be anything like “Show a red circle for 5 seconds”.

Open the Git Graph and verify that the history has indeed been recorded.

In the following sections, I won’t say every time, but make sure you commit your changes to Git once you modify the program and confirm that it works.

2.3. Loop and Key Input

An application that closes itself after 5 seconds is not interesting, so let’s change it so that it continues to display until the user tells it to close.

The basic structure of this kind of interactive program is as follows:

Initialize

while Forever:
    Process Input
    Calculate Things (if any)
    Draw on Screen

Finish

while Forever: ... means that the part of ... is repeated forever. However, we don’t want the program to repeat really forever and never stop, so we make it possible to escape from the repetition in the middle. Let’s assume that the program will exit when the Esc key is pressed.

hello_pygame.py (ver 2.0)
 1import pygame
 2
 3pygame.init()
 4screen = pygame.display.set_mode((600, 400))
 5
 6while True:
 7    pygame.event.clear()
 8    key_pressed = pygame.key.get_pressed()
 9    if key_pressed[pygame.K_ESCAPE]:
10        break
11
12    pygame.draw.circle(screen, pygame.Color("red"), (300, 200), 30)
13    pygame.display.update()
14
15pygame.quit()

The lines highlighted in color are the changes.

Line 6

This to line 13 is called a while statement, which instructs the execution of a loop. If you write something like while condition: in the first line, it will repeat as long as the condition is satisfied.

If you are familiar with the C language, note that conditions do not need to be enclosed in round parentheses, and that a colon : needs to be written after the condition.

Conditions are specified as Boolean values (truth values, logical values), and Python provides constants True and False to represent true and false Boolean values. Since we specify True here, this is an infinite loop.

Line 7

This is the start of the main body of the process (called a suite in Python) that will be repeated by the while statement.

Note the indentation at the beginning of the line. The indentation indicates that we are in a while statement. From this line, the content up to just before line 15, which returns to the same indentation depth as the while keyword, is repeated.

Conversely, whitespace at the beginning of a line is meaningful in Python, so do not add or remove whitespace at will.

In line 7, we clear the input event by calling pygame.event.clear function. An event is a generic term for something that occurs externally during the execution of pygame, such as a keystroke, a mouse movement, or a mouse button press.

Normally, we would check each of these events in turn and reflect them in the behavior of the program, but in this case we will do nothing and let pygame do all the work. However, if we just leave them alone, they will be infinitely accumulated. To avoid this, we will clear all the events that have accumulated.

Line 8
The pygame.event.clear in line 7 also has the effect of allowing some events to be processed inside pygame. As a result, the function pygame.key.get_pressed can be called to get the current list of pressed keys. The list of keys being pressed is assigned to a variable called key_pressed.
Line 9

Line 9 is the starting line of the if statement. The syntax is similar to that of the while statement, and if the specified condition is true, the codes from the next line to just before the 12th line, which has the same indentation depth as the if keyword, will be executed.

The value key_pressed returned by pygame.key.get_pressed, followed by [key name], will evaluate to True if that key is pressed, or False if it is not.

We specify pygame.K_ESCAPE as the key name here, so the body of the if statement will be executed when the Esc key is pressed.

Line 10.
The break statement interrupts the current loop process. Since the currently executing loop is the while statement in this case, when this line is executed, the loop is exited and the program proceeds to line 15, where it ends.
Lines 12-13
This is where the drawing process is executed. The contents are the same as in the previous example (the only difference is the indentation at the beginning of the line). Since this is the end of the while statement, we go back to line 6.

Since there is a while statement, if you make a mistake, the program may not stop. So please check carefully before executing the program. If it is written correctly, the program will wait until the Esc key is pressed before exiting. If it works well, commit it in Git. The commit message should be something like “Enable Esc key to quit the program”.

The program won’t stop. Nothing happens when I press the X button in the upper right corner of the window. What should I do?
Try to stop the program from VSCode, or if that doesn’t work, quit it from Windows Task Manager.

As explained for line 7, this program ignores event processing, so the X button on the title bar does not work (Are you surprised? The fact that the X button is pressed is also a kind of event).

Depending on how you wrote it wrong, you may be able to exit by hitting the X button repeatedly.

Another way is to exit from VSCode. You will see the debugger control buttons at the top of the VSCode window. Try pressing the red square button (Stop).

If that doesn’t work, try to kill the debugger from the task manager. Right-click on the Windows taskbar to open the Task Manager. In the “Processes” tab, you will see the name “Python” in the “Apps” section. Right-click on it and select “End Task”.

key_pressed[key_name] is something like an array in C language, isn’t it?
Yes, you can think of them as similar.

Python has a data structure called a sequence, which can be used similarly as an array in C. key_pressed mentioned here is actually a kind of sequence. We’ll look at it in more detail in the next chapter.

2.4. Mouse Input Handling

Having a user interaction merely to exit the program is not so interesting. Let’s make the red circle move with the mouse.

hello_pygame.py (ver 3.0)
 1import pygame
 2
 3pygame.init()
 4screen = pygame.display.set_mode((600, 400))
 5
 6while True:
 7    pygame.event.clear()
 8    key_pressed = pygame.key.get_pressed()
 9    if key_pressed[pygame.K_ESCAPE]:
10        break
11
12    pygame.draw.circle(screen, pygame.Color("red"), pygame.mouse.get_pos(), 30)
13    pygame.display.update()
14
15pygame.quit()

The change is only in 12th line.

When the pygame.mouse.get_pos function is called, it retrieves the current mouse pointer position and returns it as a tuple of x and y coordinates. We simply use this as the center of the circle to draw.

…Have you tried moving it? You may think “It’s not what I expected!” Rather than moving the circle, the application is more like drawing a line with a paintbrush. But this is the way we programmed it to work.

Anyway, let’s commit this to Git for now. You may want to refer to it later, even if it’s an unplanned result. The commit message can be anything you want, say, “Make the circle follow the mouse pointer, without clearing screen”

Is it wrong to commit something on Git that doesn’t work?
No, it’s fine as long as you’re developing on your own. However, you should make sure that you mention in the commit message that it doesn’t work.

2.5. Handling Mouse Input (retried)

To make the program such that the circle moves, you need to clear the screen before each drawing. To do so, just add one line as follows.

hello_pygame.py (ver 4.0)
 1import pygame
 2
 3pygame.init()
 4screen = pygame.display.set_mode((600, 400))
 5
 6while True:
 7    pygame.event.clear()
 8    key_pressed = pygame.key.get_pressed()
 9    if key_pressed[pygame.K_ESCAPE]:
10        break
11
12    screen.fill(pygame.Color("black"))
13    pygame.draw.circle(screen, pygame.Color("red"), pygame.mouse.get_pos(), 30)
14    pygame.display.update()
15
16pygame.quit()

By calling screen.fill with a color as an argument, you can fill the entire screen with that color. black means that the screen is cleared.

This is the only change, but it actually involves a concept in Python that has not been introduced before. The functions we’ve used so far either come from Python itself, such as print, or they belong to the pygame package, such as pygame.init and pygame.display.update.

So what is screen.fill? screen is a variable that we created in this program. The data assigned to it is of type Surface. It seems that here we are calling the function fill that belongs to the Surface type data.

In this way, Python allows you to define function-like things (referred to as methods) that belong to specific types of data. A method abc that belongs to data xyz can be referred to as xyz.abc. The method used here, fill, is defined by pygame as an operation that fills the data of type Surface to which it belongs (i.e. the screen in our case) with the color specified by the argument.

In many programming languages, data having a method are called objects; in Python, the term is used more broadly, but the basic idea is the same. The variable screen is assigned an object of type Surface.

I don’t understand how calling the method “screen.fill” fills the screen. How does it change the state of screen? Does it mean that the result of calling fill is assigned to screen?
You will learn the detailed mechanism in Chapter 5, but for the sake of intuition, think of it as “telling the screen object to fill”. It has nothing to do with assignment.

For example, the print function of Python can be understood as telling Python to “print”. The pygame.display.update function can be understood as telling the pygame.display module to “update”. Similarly, it tells the screen object to “fill”.

What the screen does as a result of this call is determined by how the pygame developer has defined it. In this case, it is defined to fill the entire surface of itself with the specified color.

In general, a method calling of xyz.abc does not necessarily change the state of the object xyz. If abc is defined to change it, it will change, that’s all.

I understand the concept of methods, but I don’t really understand its significance. How are they different from ordinary functions, and what are they for?
You will learn the details in Chapter 5, too, but for now, just understand that there are many ways to define something like a function.

For example, the operation of adding x and y can be written as x + y using the + operator, or you can also define a function add and write it as add(x, y). Python (and many other languages that adopt the concept of object-oriented programming) provides yet another way of definition that allows notations like x.add(y). Instead of telling Python to return the result of adding x and y, here we tell x to return the result of adding y to itself.

If you are familiar with struct in C language, you can think of its extension to have member functions as well as member variables, and method is a synonym for member function. Whether a piece of data should be represented as an independent variable or as a member variable of a struct is a case-by-case decision. The same is true for functions.

2.6. Displaying an Image

Instead of a circle, let’s display an image loaded from a file.

Next to the projects folder, there is a folder called assets, which contains some image files. I got them from a site that distributes free materials for games.

hello_pygame.py (ver 5.0)
 1import pygame
 2
 3pygame.init()
 4screen = pygame.display.set_mode((600, 400))
 5image = pygame.image.load("../../assets/player/p1_walk01.png").convert()
 6
 7while True:
 8    pygame.event.clear()
 9    key_pressed = pygame.key.get_pressed()
10    if key_pressed[pygame.K_ESCAPE]:
11        break
12
13    screen.fill(pygame.Color("black"))
14    screen.blit(image, pygame.mouse.get_pos())
15    pygame.display.update()
16
17pygame.quit()
Line 5

Here, the image file is loaded into the variable image.

The function to load the image file is pygame.image.load. The argument is a string that specifies the location of the file. The location of the file is specified as a file path name in which the folder separator is /, and the folder one level up is expressed by ... Since we are running the program in the projects/hello_pygame folder, the assets folder is located two folders up. We specify player/p1_walk01.png within that folder.

The pygame.image.load function returns the content of the loaded image as a Surface type object. This is the same type used to represent the entire window screen, but it is also used to represent the image data loaded from a file. If you can “paste” the image onto the screen, you have achieved your goal. To prepare for this, we call the convert method to convert the image to a format suitable for pasting. The result is assigned to the variable image.

The way of calling the convert method may be difficult to understand if you are not familiar with it. Here, the method is called by appending the dot operator directly to the value returned by pygame.image.load. In other words, it is the same as executing the following two lines together. Such a call is called a method chain:

image_original = pygame.image.load("../../assets/player/p1_walk01.png")
image = image_original.convert()
Line 14
We replace the line where pygame.draw.circle draws the circle with the process of pasting the image. We are using Surface’s method blit, which pastes the Surface object specified by the first argument (in this case, the Surface type object held by variable image) on top of itself (in this case, the Surface type object held by variable screen). The coordinates to be pasted are specified by the second argument.
What does blit mean?
Apparently, it stands for bit block transfer.

This is an old term that you don’t need to know anymore. But in pygame, it survives as a method name. I don’t think that bit block transfer can be abbreviated to blit, but that’s just history.

When I run the program from the command prompt instead of from VSCode, I get an error. What am I doing wrong?

C:\cs1\projects>python hello_pygame\hello_pygame.py
pygame 2.0.1 (SDL 2.0.14, Python 3.9.5)
Hello from the pygame community. https://www.pygame.org/contribute.html
Traceback (most recent call last):
  File "C:\cs1\projects\hello_pygame\hello_pygame.py", line 5, in <module>
    image = pygame.image.load("../../assets/player/p1_walk01.png").convert()
FileNotFoundError: No such file or directory.
Move to the folder where hello_pygame.py is located and run it. In particular, do the following:
C:\cs1\projects>cd hello_pygame
C:\cs1\projects\hello_pygame>python hello_pygame.py

This program assumes that the folder where hello_pygame.py is located and the folder where it is running are the same, and specifies the location of the image files on that assumption.

Although you may not pay much attention to it, a running program always keeps information about the current directory (the current folder). It is not directly related to the location of the program’s file. In the case of execution from the command prompt, it is determined by where the command was executed.

(In the case of execution from VSCode, if you look closely at the message displayed in Terminal, you will see that the program was executed after moving to the location of the program file.)

I tried removing .convert() in line 5, but it worked as usual. Is this necessary?
It works without .convert(), but the execution may become a bit slower.

If you don’t convert the data here, it will run through the conversion process every time you blit. It’s a waste of time to do it every time when it should be done only once.

I understand that there are both normal functions and methods, but I don’t understand how they are used. Wehn we draw a circle, we use pygame.draw.circle(screen, ...). Then, why isn’t it allowed to paste an image by writing like pygame.blit(screen, image, ...)?
This is a difficult question. To be honest, I’m not sure.

The only answer I can give is that the designers of pygame chose to do it that way. There may be a reason for this, or it may just be a whim.

In fact, such as situation often happens. When there is more than one way to achieve the same thing, the choice that the designer thinks is good may not be the same as the choice that the user finds natural.

In the end, the only option is to study the manual of the library or programming language carefully and follow it.

I tried setting the background color to navy. Then I see a black square surrounding the character and it’s not very nice. Can’t we do something about it?
Replace convert with convert_alpha, which preserves the transparent color of the PNG file.

2.7. Displaying Text

When you want to draw text, the concept is the same as for image display. First, create a small Surface with text on it. Then, paste it in the same way.

hello_pygame.py (ver 6.0)
4screen = pygame.display.set_mode((600, 400))
5font = pygame.font.Font(None, 50)    
6image = font.render("hello, pygame", True, pygame.Color("green"))
7
8while True:
Line 5

pygame.font.Font is a function that creates a character font (typeface), where the first argument is the font file and the second argument is the font size. The value returned is of type Font, and is assigned to the variable font.

The first argument, None, is used in Python to indicate that nothing is being pointed to or specified; if you are familiar with C, it is similar to NULL. If None is specified as the first argument, pygame’s default font will be used.

Line 6

The method render is applied to the font. render means “to make an image” in this case. The first argument is the string to be rendered, the second argument is a boolean indicating whether or not anti-aliasing should be applied, and the third argument is the font color.

Anti-aliasing is the process of applying blur to prevent the border between the background and the image from looking jagged.

It can’t show a string in my native language.
Try specifying a font name, instead of None, as the 1st argument to pygame.font.Font. For example, Japanese text will be correctly shown by using "hg正楷書体pro".

The available fonts depend on your environment. You can call pygame.font.get_fonts() to display a list of fonts:

>>> import pygame
>>> pygame.font.get_fonts()

2.8. Simultaneous Display of Text and Image

Let’s try to display an image and text at the same time. Since it would be unfortunate if the two images overlap, we will place the text a little to the right of the image.

hello_pygame.py (ver 7.0)
 1import pygame
 2
 3pygame.init()
 4screen = pygame.display.set_mode((600, 400))
 5font = pygame.font.Font(None, 50)    
 6text_image = font.render("hello, pygame", True, pygame.Color("green"))
 7player_image = pygame.image.load("../../assets/player/p1_walk01.png").convert()
 8
 9while True:
10    pygame.event.clear()
11    key_pressed = pygame.key.get_pressed()
12    if key_pressed[pygame.K_ESCAPE]:
13        break
14    mouse_pos = pygame.mouse.get_pos()
15
16    screen.fill(pygame.Color("black"))
17    screen.blit(player_image, mouse_pos)
18    mouse_x, mouse_y = mouse_pos
19    screen.blit(text_image, (mouse_x + 100, mouse_y))
20    pygame.display.update()
21
22pygame.quit()
Lines 6-7
Until now, the Surface to be pasted was placed in a variable called image, but since we are using both image and text, we need to distinguish between them. You can use any names you like, but we’ll use text_image and player_image.
Line 14
Previously, the pygame.mouse.get_pos function was called just when drawing a shape or pasting a Surface, but since it is used for both image and text, we call it in advance.
Lines 17-19

The pasting of the player image is the same as before. The text will be displayed 100 pixels to the right of the player image.

The x-coordinate and y-coordinate values are stored in the variables mouse_x and mouse_y, respectively. By separating the left hand side of the assignment statement with a comma, the elements of the tuple can be separated and assigned to them. This is a useful Python notation that does not exist in C and similar languages.

2.9. Reading the Reference Manual of pygame

We’ve just skimmed over a few of the features of pygame. After reading this far, you probably have a lot of questions. How do I draw a circle without filling the inside? How can I draw a shape other than a circle? What other colors can I use? … and so on.

I don’t want to explain them all here. Rather, you should be able to find out for yourself. First, open the official pygame documentation. There are many documents, including installation instructions and tutorials.

As an example, let’s look at the pygame.draw.circle function that we used to draw a circle. Open draw, which is listed as “Most useful stuff” at the top of the official documentation page.

There, you will find a list of functions, many of which are named pygame.draw.***. You will soon find pygame.draw.circle. You should see something like the following.

pygame.draw.circle()

draw a circle

circle(surface, color, center, radius) -> Rect
circle(surface, color, center, radius, width=0,
       draw_top_right=None, draw_top_left=None,
       draw_bottom_left=None, draw_bottom_right=None) -> Rect

Here is how to call pygame.draw.circle (or circle for short). In the first example, we pass four arguments: Surface, color, center, and radius, just as we did in this chapter.

After that, you will see -> Rect. This means that the call to pygame.draw.circle will return a value of type Rect. In the examples in this chapter, we did not use the return value, but it seems that some value is actually returned.

The meaning of each argument is described a little further down. If you don’t understand the details, don’t worry; if you know that int is an integer, float is a real number, and tuple is a tuple, then you should be able to read what you have seen in this chapter.

Parameters:
  • surface (Surface) – surface to draw on
  • color (Color or int or tuple(int, int, int, [int])) – color to draw with, the alpha value is optional if using a tuple (RGB[A])
  • center (tuple(int or float, int or float) or list(int or float, int or float) or Vector2(int or float, int or float)) – center point of the circle as a sequence of 2 ints/floats, e.g. (x, y)
  • radius (int or float) – radius of the circle, measured from the center parameter, nothing will be drawn if the radius is less than 1
  • width (int) – (optional) used for line thickness or to indicate that the circle is to be filled
  • (Snipped)

In addition, we can see that there are apparently a fifth and subsequent arguments. The fifth and subsequent arguments are marked as “(optional)”, meaning that they can be omitted; Python functions can be defined so that some arguments are optional.

The value to be used if omitted (the default value) can be found in the description of each argument, as well as in the second example call quoted above, as:

circle(surface, color, center, radius, width=0,
       draw_top_right=None, draw_top_left=None,
       draw_bottom_left=None, draw_bottom_right=None) -> Rect

The page describing pygame.draw.circle has other functions such as ellipse, line, and polygon. It looks like you can draw other shapes as well. At the end of the page, there is a sample code to draw some shapes.

Let’s take a look at colors. You can open Color in the “Most useful stuff” section, or you can open Color from the description of the second argument of pygame.draw.circle.

pygame.Color

pygame object for color representations

Color(r, g, b) -> Color
Color(r, g, b, a=255) -> Color
Color(color_value) -> Color

Color can take three, four, or one argument(s), and we used one argument in this chapter. So, we should find the description for the color_value argument.

If you read the description of color_value, you will see that there are many notations available as “Supported color_value formats”. The one used in this chapter is “color name str”, where str is a string, i.e. the type of string. If you want a list of names, check out the following page.

This is no longer a document, but it is part of the program that makes up pygame. You don’t need to read and understand it as a program. We see it just contains a list of strings that can be used as color names, which is enough for our purpose.

The more you can read the reference manual like this, the more you can do. It is not necessary to understand everything completely. Just focus on the information that you can read, and exercise trial and error.

I know how to use pygame.draw.circle, as this is literally written in the “draw” page of the reference manual, but I don’t understand what about screen.fill and screen.blit. In the “Surface” page of the manual, these are written as “pygame.Surface.fill” and “pygame.Surface.blit”. Then, why not just write pygame.Surface.fill in my program? How can I tell the difference between them?
Oh, yes, the pygame manual is confusing on this point.

The key is that the “draw” page starts with “pygame module for drawing shapes” while the “Surface” page starts with “pygame object for representing images”.

“draw” is a module, which contains ordinary functions that can be called using the same notation.

“Surface”, on the other hand, refers to an object, so it contains methods, which should be called using the method call notation.

The reference manual often omits pygame.something. before, for example, circle, Color, and so on. Perhaps is it possible to omit them in my source code?
Yes, you can by changing the way you use the import statement. It’ll be explained soon.
In the reference manual, Color is described as a “pygame object”; I thought Color is a function?
It is both an object and a function. To understand this, you need to understand the concepts that you will learn in Chapter 5.

Briefly explained, Color is the name of a type (class) of an object that represents a color in pygame. In Python, you can use a type name as the name of a function that generates an object of that type.

I’m having trouble with the official reference manual. Can’t I just google it and see what comes up?
Not bad, but be aware that there is no guarantee that the information is correct or up-to-date (especially for pygame, which differs considerably between versions 1.x and 2.x).

This is not specific to pygame, but always be aware that easy-to-understand pages that appear in a random web search may contain outdated or unreliable information. As a general rule, if you find something awkward, consult official information.

It is difficult to judge whether something is reliable or unreliable, but at the very least, you should be aware that just because the web search ranking is high does not mean it is reliable. In particular, be wary of the pages that seem to put a lot of effort into increasing search rankings and page views:

  • Content is bulked up with uninformative free image material
  • Content is bulked up with uninformative conversations between mysterious characters.
  • Page title has a lot of “?” or “!”

2.10. import statement

The import statement can be used to load external libraries such as pygame as well as the standard Python language libraries such as math, sys, etc. In Python, libraries are managed in units called modules:

import math          # Standard module in Python
import pygame        # Non-standard module can be imported in the same way

There are several variations in the use of the import statement:

1import pygame as pg            # Imports a module with a different name
2from pygame import Color       # Allows a module name to be omitted
3from pygame.draw import circle

The first line allows you to write, for example, pg.init() instead of pygame.init() (but not pygame.init()).

pygame.Color can be referred to as Color by using from, as in line 2. The third line allows you to use the function name circle instead of pygame.draw.circle, which is the grammatical reason why the pygame reference manual refers to Color and circle only.

You can also load your own modules. For example, you can create a file my_module.py, define functions, etc., and import it as my_module. Examples will be shown in later chapters.

2.11. Exercise

Before working on the following problems, don’t forget to commit them in Git. In the next chapter, we will continue developing the program from this state. Alternatively, you can copy hello_pygame.py to another file and modify it to work on the problems.

Problem 2-1

Change the text that displays “hello, pygame” to yellow.

Problem 2-2

Draw a blue crosshair around the mouse pointer position, and draw a red ellipse around “hello, pygame”. You can adjust the size and thickness of them as you like.

_images/ex2-2.png

Problem 2-3

When drawing a circle with pygame.draw.circle, the mouse pointer is at the center of the circle, but when pasting a player image with the blit method of Surface, the pointer is at the upper left.

Modify the program so that the center of the player image is at the mouse pointer position. The relative positions of the player image and the “hello, pygame” image should not change.

(Hint: You can check Surface’ methods get_width and get_height)