---
# System prepended metadata

title: Chapter 21 - Introduction to Pygame
tags: [GUI Programming]

---

---
slideOptions:
  theme: white
---

# Chapter 21 - Introduction to Pygame

###### tags: `GUI Programming`

---

## Set up Pygame in Pycharm

You need to follow the following steps to set up Pygame in Pycharm.

1. Press File > Setting, or press `Ctrl + Alt + s` keys.
![](https://hackmd.io/_uploads/HJwsf66_3.png)

2. Click Project: (project name) > Python Interpreter
![](https://hackmd.io/_uploads/SJsJ7ppu3.png)

3. Click the "+" symbol.
![](https://hackmd.io/_uploads/S1Zmmp6_3.png)

4. Search `pygame` and click on it. After that, click the "Install package" button at the bottom.
![](https://hackmd.io/_uploads/H1MHQaau3.png)  
![](https://hackmd.io/_uploads/Hk4tXTTO2.png)

After the `pygame` is installed, input and run the following program.

```python=
import pygame
import sys

WHITE = (255, 255, 255)
BLACK = (  0,   0,   0)

def main():
    pygame.init()
    pygame.display.set_caption("The first Pygame")
    screen = pygame.display.set_mode((800, 600))
    clock = pygame.time.Clock()
    font = pygame.font.Font(None, 80)
    tmr = 0

    while True:
        tmr = tmr + 1
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()

        txt = font.render(str(tmr), True, WHITE)
        screen.fill(BLACK)
        screen.blit(txt, [300, 200])
        pygame.display.update()
        clock.tick(10)

if __name__ == "__main__":
    main()
```

A screen with numbers should be shown afterwards.

![](https://hackmd.io/_uploads/ryl7V6a_3.png)

The meaning of different part of the program are listed below.

1. Initialise Pygame
   Before using Pygame, the program will load the Pygame module by line 1, and then initialise them by `pygame.init()` using line 8.
   
2. Assign colours in Pygame
   Colors in Pygame can be assigned by using decimal RGB value. You may refer the value to the [RGB colour picker](https://www.rapidtables.com/web/color/RGB_Color.html).

3. Prepare the window
   The canvas in Pygame is called ==Surface==. In line 10, `screen = pygame.display.set_mode((width, height))` can initialise the screen. ==Surface== is used to draw string or picture on the screen in the program. The title of the window can be set by `pygame.display.set_caption()` in line 9.
   
4. Frame rate
   In Pygame, the frame rate can be set by creating `clock` object in line 11, and then use `tick()` command in line 26 to assign the frame rate. The value 10 in line 26 means the frame rate is 10.

5. Main loop
   Line 7 declare the `main()` function. Inside the function, there is a infinity loop in line 15-26. 

6. Draw string
   For showing text in Pygame, it is required to set the font family and size -> draw on Surface -> paste Surface on the window. They are processed in line 12, 22 adn 24 respectively.
   
7. Method to end Pygame program
   Please refer to line 17-20. The event in Pygame will be triggered by `for` loop.


###  About `if __name__ == "__main__":`
Lin line 28, the line `if __name__ == "__main__":` means ==the content being run when the program is run==. `__name__` is a variable crated when the Python program is run. Then assign then module name to the variable, i.e. assign `__main__` into `__name__`. 

When using Python to import other python program, we can write this condition to avoid running other programs.

## Receive Keyboard Events
If we need to move the character and arrow keys and make the character jump by space key, it is required to write a program to receive the key events. Pygame can determine the input keys. Please input and run the following program.

```python=
import pygame
import sys

WHITE = (255, 255, 255)
BLACK = (  0,   0,   0)
RED   = (  0, 255, 255)
GREEN = (  0, 255,   0)
BLUE  = (  0,   0, 255)

def main():
    pygame.init()
    pygame.display.set_caption("The first Pygame")
    screen = pygame.display.set_mode((800, 600))
    clock = pygame.time.Clock()
    font = pygame.font.Font(None, 60)

    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()

        key = pygame.key.get_pressed()
        txt1 = font.render("UP" + str(key[pygame.K_UP]) + " DOWN" + str(key[pygame.K_DOWN]),
                           True, WHITE, GREEN)
        txt2 = font.render("LEFT" + str(key[pygame.K_LEFT]) + " RIGHT" + str(key[pygame.K_RIGHT]),
                           True, WHITE, BLUE)
        txt3 = font.render("SPACE" + str(key[pygame.K_SPACE]) + " ENTER" + str(key[pygame.K_RETURN]),
                           True, WHITE, RED)

        screen.fill(BLACK)
        screen.blit(txt1, [100, 100])
        screen.blit(txt2, [100, 200])
        screen.blit(txt3, [100, 300])
        pygame.display.update()
        clock.tick(10)
if __name__ == "__main__":
    main()
```

After the program is run, the follwoing screen should be shown. It can determine specific keys.

![](https://hackmd.io/_uploads/SJpQ9HlK2.png)

The common keys are shown as below.

|Key | Constant|
|----|---------|
|Array keys|`K_UP`, `K_DOWN`, `K_LEFT`, `K_RIGHT`|
|Space key|`K_SPACE`|
|Enter/Return key|`K_RETURN`|
|Escape key|`K_ESCAPE`|
|Letter keys|`K_a` to `K_z`|
|Number keys|`K_0` to `K_9`|
|Shift keys|`K_RSHIFT`, `K_LSHIFT`|
|Function keys|`K_F*` where `*` is a number|


## Receive Mouse Events

Please input and run the follwoing program.

```python=
import pygame
import sys

WHITE = (255, 255, 255)
BLACK = (  0,   0,   0)
LBLUE = (  0, 192, 255)
PINK  = (255,   0, 224)

def main():
    pygame.init()
    pygame.display.set_caption("The first Pygame")
    screen = pygame.display.set_mode((800, 600))
    clock = pygame.time.Clock()
    font = pygame.font.Font(None, 60)

    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()

        mouseX, mouseY = pygame.mouse.get_pos()
        txt1 = font.render("{},{}".format(mouseX, mouseY), True, LBLUE)

        mBtn1, mBtn2, mBtn3 = pygame.mouse.get_pressed()
        txt2 = font.render("{}:{}:{}".format(mBtn1, mBtn2, mBtn3), True, PINK)

        screen.fill(BLACK)
        screen.blit(txt1, [100, 100])
        screen.blit(txt2, [100, 200])
        pygame.display.update()
        clock.tick(10)
if __name__ == "__main__":
    main()
```

After the program is run, it will show position of the cursor and the status of the buttons (left, middle, right).

![](https://hackmd.io/_uploads/ry-vnHgK2.png)

## Insert Sounds

In Pygame, there have built-in commands to output BGM and SE (Sound Effects). 

We can use `try` to handle the exceptions in the program.

Please put `pygame_bgm.ogg` and `pygame_se.ogg` into the same folder as the program, input and run the following program.

```python=
import pygame
import sys

WHITE = (255, 225, 255)
BLACK = (  0,   0,   0)
CYAN  = (  0, 255, 255)

def main():
    pygame.init()
    pygame.display.set_caption("The first Pygame")
    screen = pygame.display.set_mode((800, 600))
    clock = pygame.time.Clock()
    font = pygame.font.Font(None, 40)

    try:
        pygame.mixer.music.load("pygame_bgm.ogg")
        se = pygame.mixer.Sound("pygame_se.ogg")
    except:
        print("No ogg files found or no audio output device")

    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()

        key = pygame.key.get_pressed()
        if key[pygame.K_p] == 1:
            if pygame.mixer.music.get_busy() == False:
                pygame.mixer.music.play(-1)
        if key[pygame.K_s] == 1:
            if pygame.mixer.music.get_busy() == True:
                pygame.mixer.music.stop()
        if key[pygame.K_SPACE] == 1:
            se.play()

        pos = pygame.mixer.music.get_pos()
        txt1 = font.render("BGM pos" + str(pos), True, WHITE)
        txt2 = font.render("[P]lay bgm : [S]top bgm : [SPACE] se", True, CYAN)
        screen.fill(BLACK)
        screen.blit(txt1, [100, 100])
        screen.blit(txt2, [100, 200])
        pygame.display.update()
        clock.tick(10)

if __name__ == "__main__":
    main()
```

Pygame can only load mp3 and ogg audio file.

We can use the following commands to control the BGM.

| Command         | Syntax                               | Remarks                                                                                             |
| --------------- | ------------------------------------ | --------------------------------------------------------------------------------------------------- |
| Load file       | `pygame.mixer.music.load(file_name)` |                                                                                                     |
| Play            | `pygame.mixer.music.play(para)`      | If `para` is -1, then play continuously; if it is 0, then play once; if it is 5, then play 6 times. |
| Stop            | `pygame.miser.music.stop()`          |                                                                                                     |
| Get play time   | `pygame.mixer.music.get_pos()`       | Value is in milliseconds                                                                            |
| Get play status | `pygame.mixer.music.get_busy()`      | If it is playing, then return `True`, otherwise return `False`                                      |
`

The SE can be load and play by the following commands.

```python!
variable = pygame.mixer.Sound(file_name)
variable.play()
```


## Drawing Pictures

First, put the following pictures into same folder of the program.

![pg_gb.png](https://hackmd.io/_uploads/rJoVPSgF3.png) 
![pg_chara0.png](https://hackmd.io/_uploads/r1iVvBeK3.png) 
![pg_chara1.png](https://hackmd.io/_uploads/SJiEPrlt3.png)

Please input and run the follwoing program.

```python=
import pygame
import sys

def main():
    pygame.init()
    pygame.display.set_caption("The first Pygame")
    screen = pygame.display.set_mode((640, 360))
    clock = pygame.time.Clock()
    img_bg = pygame.image.load("pg_bg.png")
    img_chara = [
        pygame.image.load("pg_chara0.png"),
        pygame.image.load("pg_chara1.png")
    ]
    tmr = 0

    while True:
        tmr += 1
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_F1:
                    screen = pygame.display.set_mode((640, 360), pygame.FULLSCREEN)
                if event.key == pygame.K_F2:
                    screen = pygame.display.set_mode((640, 360))
        x = tmr % 160    # 160 is the width of pg_bg
        for i in range(5):
            screen.blit(img_bg, [i*160-x, 0])
        screen.blit(img_chara[tmr%2], [224, 160])
        pygame.display.update()
        clock.tick(5)

if __name__ == "__main__":
    main()
```

After the program is run, the characters should be shown as walking. When pressing `F1` key, it will become full screen; when pressing `F2`, it will change to normal screen mode.

![](https://hackmd.io/_uploads/r1BVlLxK2.png)

In line 9, `pygame.image.load()` assigns the picture that requires to load by its file name. And then in Line 10-13 defines the graphics by file name.

When we need to draw pictures, we can use the following command.

```python!
screen.blit(graphic_variable, [x-coor, y-coor])
```

Notice that the coordination system of Pygame is different from tkinter. It uses the top left-hand corner as the original point. 

![](https://hackmd.io/_uploads/ryswPvgt3.png)

## Reference

[Pygame documentation](https://www.pygame.org/docs/)
[RGB colour picker](https://www.rapidtables.com/web/color/RGB_Color.html)
[pg_gb.png](https://hackmd.io/_uploads/rJoVPSgF3.png)
[pg_chara0.png](https://hackmd.io/_uploads/r1iVvBeK3.png)
[pg_chara1.png](https://hackmd.io/_uploads/SJiEPrlt3.png)


