---
# System prepended metadata

title: Python Pygame 語法(1)
tags: [Python Pygame]

---

# Python Pygame 語法介紹(1)

## 簡介

**Pygame**是**Python**的一個遊戲開發函式庫，提供了簡單的介面來處理視窗管理、圖形渲染、事件處理及音效播放等功能

## 安裝 Pygame

在開始使用**Pygame**前，我們得先安裝他，在終端機輸入以下指令來安裝
```
pip install pygame
```
>若安裝失敗請確認`pip`是否有正常執行

## Pygame 語法

### 導入和初始化

在程式的一開始，我們需要導入並初始化`pygame`，否則系統可能會報錯
```python
#導入pygame
import pygame
#初始化pygame
pygame.init()
```

### 建立與管理視窗

在`pygame`中，主要由`pygame.display`負責管理視窗的顯示，提供了許多方法來處理畫面更新、視窗控制、全螢幕模式等。以下是相關指令的介紹

- `pygame.display.init()`：初始化`pygame.display`（通常`pygame.init()`會自動執行）
- `pygame.display.get_init`：檢查`pygame.display`是否已初始化，回傳`True`或`False`
- `pygame.display.set_mode(size, flags=0, depth=0, display=0, vsync=0)`：設定視窗的大小和類型
    - `size`：必填，設定視窗的大小
        - 格式： `(寬度, 高度)`（單位：像素）
        - 範例：`pygame.display.set_mode((800, 600))`
            >→ 創建一個 800×600 的視窗
    - `flags`：選填，控制視窗模式，且可同時存在多個`flags`
        - 預設值`0`：普通視窗
        - 可用的`flags`：
            |`flags`|功能|
            |-------------------|---------------------|
            |`pygame.FULLSCREEN`|全螢幕模式             |
            |`pygame.RESIZABLE` |允許使用者調整視窗大小   |
            |`pygame.NOFRAME`   |無邊框視窗             |
            |`pygame.SCALED`    |自動縮放畫面以適應視窗大小|
            |`pygame.HWSURFACE` |使用硬體加速（僅限 `pygame.FULLSCREEN`可用）|
            |`pygame.DOUBLEBUF` |啟用雙緩衝（建議與`pygame.HWSURFACE`或`pygame.OPENGL`一起使用）|
            |`pygame.OPENGL`    |使用 OpenGL 渲染       |
            >[!Note]名詞補充
            >雙緩衝 (Double Buffering) 是一種圖形渲染技術，目的是減少畫面閃爍並提升視覺流暢度
            >OpenGL（Open Graphics Library）渲染是指使用 OpenGL API 來將 3D 模型與場景轉換成影像並顯示在螢幕上的過程
    - `depth`：選填，設定色彩深度（單位：bit）
        - 預設值`0`： 讓系統自動選擇最佳的色彩深度
    - `display`：選填，指定使用哪一個顯示器（僅在**多螢幕系統**上適用）
        - 預設值`0`：使用主顯示器
    - `vsync`：選填，啟用或停用**垂直同步（VSync）**
        - 可用的值：
            - `0`：預設，不使用垂直同步
            - `1`：啟用垂直同步
            - `-1`：讓系統自動決定是否啟用（部分系統和驅動支援）
    >[!Important]注意
    >在設定參數時許注意格式統一，否則系統將會報錯
    >以下為錯誤示範
    >```
    >pygame.display.set_mode(size=(800,800), pygame.FULLSCREEN)
    >```
    >
    >另外，也要注意各個參數之間的搭配，否則可能會引起系統故障
- `pygame.display.quit()`：關閉視窗（不等於關閉`pygame`）
- `pygame.display.flip()`：更新整個視窗
- `pygame.display.update(rect_list)`：更新視窗內部份區域
    - `rect_list`：
        - `rect_list=None`：預設值，若**不提供`rect_list`參數**，則效果與`pygame.display.flip()`相同，會更新整個畫面
        - `rect_list`是一個`Rect`物件列表：當`rect_list`是一個 list（包含多個`pygame.Rect`物件）時，只會更新這些區域，提升效能
- `pygame.display.set_caption(title)`：設定視窗名稱
- `pygame.display.get_caption()`：取得視窗名稱，回傳`(title, icontitle)`
- `pygame.display.set_icon(icon_surface)`：設定視窗圖示，接受一個`pygame.Surface`物件或圖片作為圖示，步驟如下
    1. 準備圖示圖片：首先，你需要準備一張 小尺寸的圖示圖片（如 icon.png），建議尺寸為 32×32 或 64×64 像素，並且圖片格式為 PNG（建議使用透明背景） 
    2. 載入圖片並設定圖示：
        ```python
        import pygame
        pygame.init()
        screen = pygame.display.set_mode((800, 600))
        # 載入圖示，確保 icon.png 放在程式的相同目錄下
        # 也可以直接給予路徑
        icon = pygame.image.load("icon.png")
        # 設定視窗圖示
        pygame.display.set_icon(icon)
        ```
    >[!Note]補充
    >如果你的圖示太大（例如 256x256），Pygame不會自動縮小，可能會出現問題，這時可以使用`pygame.transform.scale()`來縮小圖示
    >```python
    >icon = pygame.image.load("icon.png")
    >#調整為 32×32
    >icon = pygame.transform.scale(icon, (32, 32))
    >pygame.display.set_icon(icon)
    >```
    >這樣可以確保你的圖示適合視窗
- `pygame.display.get_surface()`：取得目前視窗本身的`Surface`（用於直接繪製）
    >[!Note]視窗本身的`Surface`是什麼?
    >Pygame的**視窗本身就是一個`Surface`物件**，它來自`pygame.display.set_mode()`
    >當你執行：
    >```python
    >screen = pygame.display.set_mode((800, 600))
    >```
    >這行程式碼會：
    >1. 建立一個 800×600 的Pygame視窗
    >2. 回傳一個`Surface`物件，存入變數`screen`
    >3. `screen`就是這個**視窗的`Surface`**，你可以在上面畫東西
    >
    >這個`Surface`代表遊戲視窗上的所有像素。你可以把它想像成一張**可以繪製的畫布**，所有的圖案、圖片和文字都必須畫在這個`Surface`上，最後再透過`pygame.display.update()`或 `pygame.display.flip()`顯示到螢幕上
    >
    >當你使用`pygame.display.get_surface()`，你取得的是**視窗本身的`Surface`物件**，這表示：
    >1. 你可以直接在視窗上畫圖，無需建立新的`Surface`
    >2. 你畫的內容會直接影響視窗內容（但仍需更新視窗才能顯示）
- `pygame.display.iconify()`：最小化視窗
- `pygame.display.toggle_fullscreen()`：切換全螢幕模式，主要適用於 Linux（X11 視窗系統）
    >[!Caution]警告
    >在 Windows 和 macOS 上可能無法正常運作，甚至會導致視窗異常，建議改用`pygame.display.set_mode()`來切換全螢幕模式
:::success
- `.fill(color)`：將`Surface`物件填滿顏色，在前面我們有提到視窗本身就是一個`Surface`物件，所以我們可以用`.fill()`來改變視窗的顏色
    - 範例：
      ```python
      screen = pygame.display.set_mode((500, 300))
      screen.fill((0, 0, 0))# 黑色背景
      ```
:::

### 繪製圖形

在`pygame`中，主要由`pygame.draw`來負責繪製圖形，提供了一系列用於繪製基本圖形的函式

>[!Note]螢幕座標系統
>在開始介紹函式前我們要先來說明一下螢幕座標系統
>螢幕座標系統是一種 二維 (2D) 坐標系統，用來定位電腦螢幕上的像素 (pixel) 位置
>
>螢幕座標的基本特性：
>- 原點 (0,0) 在左上角
>  與數學坐標系統（原點通常在中心）不同，螢幕座標系統的原點通常定義在**螢幕的左上角**
>- X軸向右遞增
>  從左往右，X值增加
>- Y軸向下遞增
>  從上往下，Y值增加，這與數學座標系統相反，數學座標系統通常是Y軸向上遞增
>
>示意圖
>|0,0|1,0|2,0|
>|---|---|---|
>|0,1|1,1|2,1|
>|0,2|1,2|2,2|

>[!Tip]`pygame.draw`繪圖函式的特性
>這些函式的第一個參數通常是`surface`，表示要繪製的目標畫布，顏色則使用`(R, G, B)`或`(R, G, B, A)`格式，`A`為透明度，另外，**所有繪圖函式都會回傳`pygame.Rect`物件**，代表繪製區域的範圍，可配合`pygame.display.update()`使用

- `pygame.draw.line(surface, color, start_pos, end_pos, width=1)`：畫一條線
    - `start_pos`：線段的起點座標`(x, y)`
    - `end_pos`：線段的終點座標`(x, y)`
    - `width`：線條寬度，預設`1`
- `pygame.draw.lines(surface, color, closed, point_list, width=1)`：畫多條相連的線
    - `closed`：若為`True`，則最後一點會連回第一點形成封閉區域
    - `point_list`：點座標的列表`[(x1, y1), (x2, y2), ...]`
    - `width`：線條寬度
- `pygame.draw.aaline(surface, color, start_pos, end_pos, blend=1)`：畫一條抗鋸齒的線（較平滑）
    - `blend`：若為`1`，則啟用抗鋸齒效果 
- `pygame.draw.aalines(surface, color, closed, point_list, blend=1)`：畫多條相連的抗鋸齒線
>[!Note]什麼是抗鋸齒?
>抗鋸齒（Anti-Aliasing，AA）是一種圖形技術，主要用來減少電腦圖像中因解析度限制而產生的鋸齒狀（Jagged Edges）效果，使邊緣看起來更平滑。這種鋸齒現象通常出現在低解析度或當對角線、曲線無法完美對應像素點時，導致邊緣看起來不自然或鋸齒化
>
>以下是幾種常見的抗鋸齒技術：
>- 多重取樣抗鋸齒（MSAA, Multi-Sample Anti-Aliasing）
>    - 透過對場景的多個樣本進行計算，並根據像素的顏色加權平均，使邊緣平滑
>    - 只對幾何邊緣進行抗鋸齒，因此效能較好，但對透明紋理無效
>- 快速近似抗鋸齒（FXAA, Fast Approximate Anti-Aliasing）
>    - 透過後處理（Post-Processing）的方法模糊鋸齒邊緣，使畫面變得平滑
>    - 效能較好，適合低端硬體，但畫面可能會變模糊
>- 超級採樣抗鋸齒（SSAA, Super-Sampling Anti-Aliasing）
>    - 先以高解析度渲染畫面，然後縮小至目標解析度，以獲得更平滑的圖像
>    - 效果較佳，但效能消耗較高
>- 時間性抗鋸齒（TAA, Temporal Anti-Aliasing）
>    - 使用多幀資訊來平滑動態場景中的鋸齒，能減少閃爍問題
>    - 效果較佳，但可能會產生畫面模糊或鬼影（Ghosting）現象
>- 深度學習抗鋸齒（DLAA, Deep Learning Anti-Aliasing）
>    - 由 NVIDIA 開發，人工智慧加持的反鋸齒技術，讓影像品質更臻完美。DLAA 採用專為 DLSS 開發的超解析技術，以原生解析度締造更栩栩如生的高品質影像
>    - 透過機器學習預測高解析度畫面，達到較好的效果，效能影響較小，但犧牲幀率來提升來提高圖像質量
- `pygame.draw.rect(surface, color, rect, width=0, border_radius=0, border_top_left_radius=-1, border_top_right_radius=-1, border_bottom_left_radius=-1, border_bottom_right_radius=-1)`：繪製矩形
    - `rect`：矩形的 Rect 物件`(x, y, width, height)` 
    - `width`：選填，邊框粗細
        - `width=0`：填滿矩形（畫出實心矩形）
        - `width>0`：只畫邊框，值決定邊框的厚度（像素）
        - `width`大於矩形寬度或高度時：會變成實心矩形
    - `border_radius`：選填，預設為`0`，控制圓角半徑
    - `border_*_radius`：選填，預設為`-1`，分別控制四個角的圓角半徑
>[!Note]圓角半徑（border radius）是什麼？
>圓角半徑（border_radius）指的是矩形四個角的圓滑程度，即矩形的角如何從直角變成圓弧。當 border_radius 設為 0（預設值）時，矩形的角是標準的 90° 直角；當 border_radius 設為正數時，矩形的角就會變圓

>[!Note]`border_radius`的效果
>數值`0`（預設） → 標準直角矩形
>數值`>0` → 圓角矩形，數值越大，圓角越圓
>數值`> min(width, height) / 2` → 會變成橢圓或半圓
>數值`-1`→ 無效（不會影響矩形）
- `pygame.draw.circle(surface, color, center, radius, width=0)`：畫一個圓
    - `center`：圓心座標`(x, y)`
    - `radius`：圓半徑 
- `pygame.draw.ellipse(surface, color, rect, width=0)`：畫一個橢圓（基於矩形範圍）
    - `rect`：決定橢圓形狀的矩形區域
- `pygame.draw.arc(surface, color, rect, start_angle, end_angle, width=1)` ：畫一條弧線（基於矩形範圍）
    - `start_angle`、`end_angle`：弧線的起始與結束角度，單位為弧度
>[!Note]弧度
>在`pygame.draw.arc()`中，起始角度（start_angle）和結束角度（end_angle）的單位是弧度（radian），而不是一般常見的度數（degree）。這可能會讓人感到困惑，所以我們來簡單解釋一下
>
>#### 什麼是弧度？
>
>弧度（radian）是角度的另一種測量方式：
>- 360° = 2𝜋 弧度
>- 180° = 𝜋弧度
>- 90°  = $\frac{𝜋}{2}$弧度
>- 45°  = $\frac{𝜋}{4}$弧度
>
>換算公式：
>$$弧度＝度數×\frac{𝜋}{１８０}$$
>
>Python內建的`math.radians(degrees)`可以幫助我們轉換，例如：
>```python
>import math
>#轉換 90° 為弧度，結果是 𝜋/2
>print(math.radians(90))  # 轉換 90° 為弧度，結果是 𝜋/2
>#輸出 1.5707963267948966
>```
>
>畫一條從 0° 到 180°（半圓）的弧線
>```python
>pygame.draw.arc(screen, RED, rect, math.radians(0), math.radians(180), width=3)
>```
>
>#### 角度方向
>
>在`pygame.draw.arc()`中，角度是按照**數學標準方向**計算的：
>- 0 弧度（0°） → 從右側開始
>- π/2 弧度（90°） → 上方
>- π 弧度（180°） → 左側
>- 3π/2 弧度（270°） → 下方
>由上可知，**`pygame.draw.arc()`的繪製方向是「逆時針」的**，如果你想畫出從 90°（上方）到 270°（下方）的半圓弧，應該這樣設定：
>```python
>pygame.draw.arc(screen, RED, rect, math.radians(90), math.radians(270), width=3)
>```
>>高二上數學
- `pygame.draw.polygon(surface, color, point_list, width=0)`：畫一個多邊形
    - `point_list`：頂點座標的列表`[(x1, y1), (x2, y2), ...]` 

>[!Tip]小技巧
>看到現在不知道大家有沒有發現，不論是畫哪種形狀，開頭都會先用到`pygame.draw`，然後再接要畫的形狀函數，而如果是使用VScode來寫程式的話，系統都會自動提示你有那些函數可接，所以在記指令時我們只要記得每個函數大概的意思就可以了，剩下的系統會提示你
>![螢幕擷取畫面 2025-02-08 143523](https://hackmd.io/_uploads/S1g2npVYke.png)
>我們剛才說的九種函數都在這裡
>![螢幕擷取畫面 2025-02-08 143757](https://hackmd.io/_uploads/Bklhn6Etkl.png)
>參數忘了也沒關係，系統會提示

### 文字處理

在`pygame`中，主要由`pygame.font`來處理文字相關的操作，主要有載入字型、設定大小、渲染文字等功能

- `pygame.font.init()`：初始化`pygame.font`（通常`pygame.init()`會自動執行）
- `pygame.font.get_init()`：檢查`pygame.font`是否已初始化，回傳 `True`或`False`
- `pygame.font.quit()`：關閉`pygame.font`
- `pygame.font.get_default_font()`：取得`pygame`預設字型的名稱，通常是`"freesansbold.ttf"`
- `pygame.font.get_fonts()`：回傳系統上可用的字型名稱清單
- `pygame.font.match_font(name, bold=False, italic=False)`：查找字型是否存在，若存在則回傳路徑，若找不到則回傳`None`
    - `name`：字型名稱
    - `bold`：選填，指定是否查找**加粗**（**bold**）版本的字型
    - `italic`：選填，指定是否查找**斜體**（**italic**）版本的字型
- `pygame.font.SysFont(name, size, bold=False, italic=False)`：載入一個字型並創建字型物件
    - `name`：字型名稱，若設為`None`則使用預設字型
    - `size`：字型大小
    - `bold`：選填，粗體
    - `italic`：選填，斜體
- `pygame.font.Font(file, size)`：載入一個字型檔案並創建字型物件
    - `file`：檔案路徑，若設為`None`則使用預設
    - `size`：字型大小
>[!Important]字型物件
>當你創建好一個字型物件後，記得要將他保存起來，也方便你接下來的操作，例如：
>```python
>font = pygame.font.SysFont("microsoftjhenghei", 100)
>```
- `text_surface = font.render(text, antialias, color, background=None)`：將文字渲染為`Surface`物件
    - `text`：要輸出的文字
    - `antialias`：是否開啟抗鋸齒，`True`是開啟，`False`是不開啟
    - `color`：字體顏色
    - `background`：選填，背景顏色，若為`None`則透明
- `text_rect = text_surface.get_rect(center=(x, y))`：取得文字的矩形區域，回傳為`Rect`物件
    - 可以在`get_rect()`裡加參數來**設定圖片的初始位置，在定位的同時移動到指定位置**，以下是可用參數

        |參數|作用|參數|作用|
        |-------------|----------------|-----------|------------------|
        |`topleft`    |設定矩形的左上角座標|`midtop`   |設定矩形的頂部中央座標|
        |`topright`   |設定矩形的右上角座標|`midbottom`|設定矩形的底部中央座標|
        |`bottomleft` |設定矩形的左下角座標|`midleft`  |設定矩形的左側中央座標|
        |`bottomright`|設定矩形的右下角座標|`midright` |設定矩形的右側中央座標|
        |`center`     |設定矩形的中心點座標|
- `screen.blit(text_surface, text_rect)`：將文字渲染到視窗上，仍須更新視窗才會顯示，另外`text_rect`也可以換成`(x, y)`座標
>[!Tip]完整流程
>```python
>font = pygame.font.SysFont("microsoftjhenghei", 100)
>text_surface = font.render("文字", True, (0, 255, 255))
>text_rect = text_surface.get_rect(center=(350, 350))
>screen.blit(text_surface, text_rect)
>pygame.display.flip()
>```
- `font.size(text)`：測量指定文字的寬度和高度，回傳`(width, height)`
>[!Important]以下指令適用於`Surface`物件

- `set_bold(value)`：設定是否加粗，`value=True/False`
- `get_bold()`：檢查字型是否加粗，回傳`True`或`False`
- `set_italic(value)`：設定是否斜體
- `get_italic()`：檢查字型是否斜體
- `set_underline(value)`：設定是否有底線
- `get_underline()`：檢查字型是否有底線
- `metrics(text)`：取得指定文字的字元度量資訊，回傳列表`(min_x, max_x, min_y, max_y, advance_x)`，若某個字元在字型中找不到將回傳`None`
    - |參數|意義|
      |---|---|
      |`min_x`|字元左側邊界的 X 座標|
      |`max_x`|字元右側邊界的 X 座標|
      |`min_y`|字元底部邊界的 Y 座標|
      |`max_y`|字元頂部邊界的 Y 座標|
      |`advance_x`|下一個字元的起始位置（表示字元的寬度加上間距）|
>[!Note]常用的字型名稱
>- `microsoftjhenghei`：微軟正黑體，推薦使用
>- `microsoftyahei`：微軟雅黑體
>- `mingliu`：細明體，傳統風格
>- `pmingliu`：新細明體，繁體中文
>- `simsun`：中易宋體，簡體中文
>- `simhei`：中易黑體，簡體中文
>- `dengxian`：等線體
>- `fangsong`：仿宋體，古典風格
>- `kaiti`：楷體，手寫風格

### 圖像處理

在`pygame`中，主要由`pygame.image`來負責圖像方面的操作，提供了圖片縮放、色彩透明度以及像素碰撞等功能

- `pygame.image.load("path/to/image.png")`：載入圖片
    - `"path/to/image.png"`：檔案路徑，要記得`\`要換成`\\`或`/`
    - 支援格式：PNG、JPG、GIF（靜態）、BMP、TGA
    - 如果圖片格式不支援，會拋出`pygame.error: Unsupported image format`錯誤
>[!Note]可以使用`convert()`或`convert_alpha()`來提高效能
>在`pygame`中，使用`.convert()`或`.convert_alpha()`**提高效能的主要原因**在於**顯存格式的匹配**。以下是它們如何提升效能的細節：
>- 內部格式轉換
>  當你用`pygame.image.load()`載入圖片時，圖片的格式可能與螢幕的顯存格式不同，這會導致`blit()`（繪製圖片）時，每次都需要額外的計算來匹配格式，從而降低效能
>    - `.convert()`：將圖片的像素格式轉換為與顯示畫面（Surface）的格式相同，這樣`blit()`可以直接複製記憶體區塊，而不需要即時轉換格式，因此顯示速度大幅提升
>    - `.convert_alpha()`：同樣會轉換格式，但會保留 Alpha（透明通道）資訊，適用於 PNG 這類有透明部分的圖片
>- 減少 CPU/GPU 運算開銷
>    - **如果不使用**`.convert()`，每次`blit()`都要即時進行格式轉換，這會增加 CPU/GPU 的運算負擔，導致遊戲掉幀或卡頓
>    - 使用`.convert()`後，圖片格式與顯示畫面相匹配，繪製時可以直接使用顯存中的數據，減少額外的運算開銷，提高`blit()`的執行效率
>```python
>image = pygame.image.load("path/to/image.png").convert()  # 移除透明度，加快顯示
>image_alpha = pygame.image.load("path/to/image.png").convert_alpha()  # 保留透明度
>```
- `pygame.transform.scale(image, (new_width, new_height))`：前面提到過的圖片縮放
- `pygame.transform.smoothscale(image, (new_width, new_height))`：**平滑縮放**（適用於 PNG、JPG），**減少鋸齒化，但效能消耗較高**
- `pygame.transform.rotate(image, angle)`：旋轉圖片，但旋轉後圖片大小可能會改變
    - `angle`：角度（順時針旋轉）
- `pygame.transform.rotozoom(image, angle, scale)`：旋轉並縮放
    - `scale`：縮放倍率，`1.0`表示不變
- `pygame.transform.flip(image, flip_x, flip_y)`：水平和垂直翻轉
    - `flip_x`：水平翻轉（`True`/`False`）
    - `flip_y`：垂直翻轉（`True`/`False`）
:::success
- `image.set_alpha(alpha_value)`：改變透明度，適用於`.convert_alpha()` 圖片
    - `alpha_value`：`0~255`，`0`表示完全透明，`255`表示完全不透明
- `image.set_colorkey((R, G, B))`：使某個顏色變為透明
- `image.get_size()`：取得圖片尺寸，回傳為`(w, h)`
- `image.get_rect()`：取得圖片的矩形區域，回傳為`Rect`物件，與前面提到過的`text_surface.get_rect()`類似
- `screen.blit(image, (x, y))`：在`(x, y)`位置繪製圖片，仍須更新視窗才會顯示，與前面提到的`screen.blit(text_surface, text_rect)`類似
:::

### 結束Pygame

當程式結束時，應確保Pygame正確關閉
- `pygame.quit()`：關閉Pygame

## [下一篇](https://hackmd.io/@Huanyu763/PythonPygame事件處理)
## [回到主頁](https://hackmd.io/@Huanyu763/home)