如何建立遊戲視窗?以及取得和設定視窗與熒幕資訊等問題
訂閱 375
Pygame 建立視窗,以及設定標題和切換全熒幕,display 模組簡介影片示範 YouTube
Pygame 中的 display 模組
Pygame 套件的display
模組,提供了與遊戲視窗,熒幕相關的功能,當你匯入pygame
模組時,display
模組會被pygame
模組匯入。
初始化 display 模組
與pygame
模組一樣,display
模組擁有用於初始化的函式init
,該函式會在pygame
模組的init
函式中被呼叫,這意味著一旦使用pygame
模組進行初始化,呼叫display
模組的init
函式將是沒有必要的。
init()
可以重複呼叫 init 函式
你可以反覆呼叫init
函式,這沒有任何問題,即便在呼叫quit
函式之後。
# 匯入模組 display
from pygame import display
# 初始化
display.init()
判斷 display 模組是否已經初始化
與pygame
模組一樣,display
模組擁有判斷display
模組是否已經初始化的函式get_init
。
get_init()
- 傳回值
如果
get_init
函式傳回True
,那麽表示display
模組已經進行了初始化。
在呼叫 quit 函式之後,get_init 函式將傳回 False
在呼叫quit
函式之後,get_init
函式將傳回False
,這表示再次呼叫init
函式將產生實際效果,他會重新初始化display
模組。
# …
print(f'display 已經初始化?{display.get_init()}')
display 已經初始化?True
取消初始化 display 模組
與pygame
模組一樣,display
模組擁有用於取消初始化的函式quit
,該函式會在pygame
模組的quit
函式中被呼叫,這意味著一旦使用pygame
模組取消了初始化,呼叫display
模組的quit
函式將是沒有必要的。
quit()
呼叫 quit 函式將導致遊戲視窗被關閉
如果你已經向玩家展示了遊戲視窗,那麽呼叫quit
函式將導致這些遊戲視窗被關閉。
可以重複呼叫 quit 函式
和init
函式一樣,你可以反覆呼叫quit
函式,這沒有任何的問題。
建立遊戲視窗
display
模組的set_mode
函式,將根據給出的顯示模式(可理解為參數的組合)建立遊戲視窗和一個表示表面的Surface
物件,根據參數的不同,遊戲視窗將以不同的狀態顯示。set_mode
函式會傳回建立的Surface
物件,並呼叫init
函式,如果display
模組尚未進行初始化。
如果遊戲視窗已經被建立,那麽再次呼叫display
模組的set_mode
函式,將改變遊戲視窗的顯示模式,比如表面的大小。
set_mode(size=(0, 0), flags=0, depth=0, display=0, vsync=0)
- size 參數
size
參數是一個 Python 數值序列物件(比如元組,串列),其第一個元素表示視窗表面的寬度,第二個元素表示視窗表面的高度,或一個 PygameVector2
物件(物件的x
變數對應表面寬度,物件的y
變數對應表面高度)。如果
size
參數所包含的寬度和高度為0
,那麽set_mode
函式將建立一個表面大小和熒幕大小相同的視窗。- flags 參數
flags
參數是一個整數,他決定了被建立的遊戲視窗將以何種方式被顯示。pygame
模組提供了以下的變數,你可以使用或位元運算子|
來組合他們,並作為flags
參數的值。FULLSCREEN
(視窗將全熒幕顯示),DOUBLEBUF
(視窗將使用雙重緩沖,僅在采用 OpenGL 進行算繪時有效),OPENGL
(視窗將采用 OpenGL 進行算繪),RESIZABLE
(視窗可以被改變大小),NOFRAME
(視窗將沒有邊線),SCALED
(根據熒幕或視窗大小等比例縮放視窗表面,不會改變視窗對應的Surface
物件的大小),SHOWN
(預設值,視窗將被開啟並顯示),HIDDEN
(視窗將被開啟並隱藏)。- depth 參數
depth
參數是一個表示色彩深度的整數,一般情況下,設定該參數是沒有必要的,因為系統會自動選擇最合適的色彩深度,除非你希望使用自己的像素格式。需要指出的是,隨意設定
depth
參數可能導致遊戲執行緩慢。- display 參數
display
參數是一個整數,用於表示視窗將顯示在第幾個熒幕中,如果為0
(預設值),那麽視窗將顯示在預設的熒幕中,如果為1
,那麽視窗將顯示在第二個熒幕中。- vsync 參數
vsync
參數是一個整數,如果為1
,那麽視窗將嘗試采用垂直同步,如果flags
參數采用了OPENGL
或SCALED
的話。當然,是否能夠采用垂直同步,還取決於電腦硬體以及顯示驅動的組態。
- 傳回值
set_mode
函式的傳回值是一個表示表面的Surface
物件。
SDL 1.2.10 之前,如果set_mode
函式的size
參數所表示的寬度和高度為零,那麽將導致例外狀況。
在 Pygame 2 中,pygame
模組的HWSURFACE
變數已經被取代,之前他可作為set_mode
函式的flags
參數的值,表示視窗將在全熒幕模式下啟用硬體加速。
遊戲視窗的表面大小可能與傳遞給 set_mode 函式的 size 參數的值不符
在全熒幕模式或允許改變視窗大小的情況下,遊戲視窗的表面的大小(視窗對應的Surface
物件的大小)可能與傳遞給set_mode
函式的size
參數的值不相符。比如,在呼叫set_mode
函式時,將flags
參數設定為FULLSCREEN
,將size
參數設定為(540,960)
,而目標熒幕的大小為 1920x1080,那麽 Pygame 會自行調整視窗表面的大小,這可能會導致玩家看到不應該出現的內容。
表面
關於表面物件Surface
,你可以檢視如何使用 Surface 表面物件?以及表面(影像)的透明度,透明色彩鍵,色彩,大小等問題一節。
在下面的範例中,我們設定遊戲視窗的表面大小為 600x400,並為全熒幕顯示模式,最終,視窗的表面大小被設定為了 640x480。
由於沒有編寫遊戲迴圈,以及檢測遊戲事件的程式碼,因此被建立的遊戲視窗僅支援少量的使用者操作。
# …
from pygame import RESIZABLE, FULLSCREEN
# 建立一個表面 700x500,可以改變大小的視窗
s = display.set_mode([700, 500], RESIZABLE)
print(f'表面大小:{s.get_size()}')
# 變更為全熒幕顯示,表面大小 600x400
s = display.set_mode((600, 400), FULLSCREEN)
print(f'表面大小:{s.get_size()}')
# 等候 3 秒
import time
time.sleep(3)
表面大小:(700, 500)
# 表面的大小發生了改變
表面大小:(640, 480)
如何使用 set_mode 函式確保遊戲視窗的表面大小不會發生改變?
要確保遊戲視窗的表面大小不發生改變,你可以將pygame
模組的SCALED
變數加入set_mode
函式的flags
參數,雖然遊戲視窗的表面將根據熒幕或視窗大小進行等比例縮放,但視窗對應的Surface
物件的大小不會發生變化。
與之前的範例不同,當我們將SCALED
加入flags
參數之後,全熒幕顯示的遊戲視窗的表面大小並不會改變。
from pygame import display, FULLSCREEN, SCALED
# 全熒幕顯示,表面大小 600x400,可縮放
s = display.set_mode((600, 400), FULLSCREEN | SCALED )
print(f'表面大小:{s.get_size()}')
表面大小:(600, 400)
不能使用 set_mode 函式隨意修改顯示模式
你可以使用display
模組的set_mode
函式來修改遊戲視窗的顯示模式,但一些參數組合可能會在反覆修改顯示模式的過程中導致例外狀況,雖然最初采用這些組合時,不會產生任何的問題。
在某些情況下,如果第一次呼叫set_mode
函式時沒有采用SCALED
,那麽修改顯示模式時也不能采用SCALED
,否則可能會導致例外狀況pygame.error: failed to create renderer
。
from pygame import display, SCALED
# 最初沒有采用 SCALED
display.set_mode([700, 500])
# 改為采用 SCALED 將導致例外狀況
display.set_mode((600, 400), SCALED)
pygame.error: failed to create renderer
判斷顯示模式是否可用
display
模組的mode_ok
函式,可用於判斷指定的顯示模式是否可用,由於該函式的參數size
,flags
,depth
,display
,vsync
的含義與set_mode
函式類似,因此這裏不再解釋,你可以參考建立遊戲視窗一段來了解他們。
mode_ok(size=(0, 0), flags=0, depth=0, display=0, vsync=0)
- 傳回值
如果
mode_ok
函式的傳回值為0
,那麽表示由參數指定的顯示模式不可用,否則mode_ok
函式將傳回該顯示模式下的最佳色彩深度(整數型別)。
在下面的範例中,由於顯示模式可用,因此mode_ok
函式傳回了該顯示模式下的最佳色彩深度。
# 匯入並初始化 display 模組
from pygame import display
display.init()
# 判斷顯示模式是否可用
print(display.mode_ok([1024, 768], depth=8, display=1))
24
取得顯示模式所支援的視窗表面大小
display
模組的list_modes
函式,可用於取得指定顯示模式所支援的視窗的表面大小,由於該函式的參數depth
,flags
,display
的含義與set_mode
函式類似,因此這裏不再解釋,你可以參考建立遊戲視窗一段來了解他們。
list_modes(depth=0, flags=pygame.FULLSCREEN, display=0)
- 傳回值
list_modes
函式的傳回值為-1
或一個 Python 串列,如果為-1
,那麽表示任何表面大小均被顯示模式支援,如果為空的 Python 串列,那麽表示指定的顯示模式不支援任何的表面大小(即顯示模式不可用),否則 Python 串列中的每一個元組均對應一個視窗表面的大小,元組的形式為(x,y)
,其中x
表示表面的寬度,y
表示表面的高度。
在下面的範例中,我們沒有為list_modes
函式指定任何參數,因此該函式會傳回全熒幕模式所支援的視窗表面大小。
# 匯入並初始化 display 模組
from pygame import display
display.init()
# 列出全熒幕模式所支援的視窗表面大小
print(f'全熒幕模式支援的表面大小:{display.list_modes()}')
全熒幕模式支援的表面大小:[(2560, 1440), (1920, 1440), (1920, 1200), (1920, 1080), (1680, 1050), (1600, 1200), (1600, 1024), (1600, 900), (1440, 1080), (1440, 900), (1366, 768), (1360, 768), (1280, 1024), (1280, 960), (1280, 800), (1280, 768), (1280, 720), (1176, 664), (1152, 864), (1024, 768), (800, 600), (720, 576), (720, 480), (640, 480)]
取得和設定遊戲視窗的標題
display
模組的get_caption
函式可用於取得遊戲視窗的標題和圖示標題。
get_caption()
- 傳回值
get_caption
函式的傳回值是一個形式類似於(title,icontitle)
的 Python 字串元組,其中title
表示視窗標題,icontitle
表示視窗的圖示標題。
在 Pygame 2 中,get_caption
函式所獲得的遊戲視窗標題和遊戲視窗的圖示標題總是相同的。
display
模組的set_caption
函式可用於設定遊戲視窗的標題和圖示標題。
set_caption(title, icontitle=None)
- title 參數
title
參數是一個表示遊戲視窗標題的字串。- icontitle 參數
icontitle
參數是一個表示遊戲視窗的圖示標題的字串。
在 Pygame 2 中,沒有必要給出set_caption
函式的icontitle
參數,因為這沒有任何效果。
get_caption,set_caption 函式對呼叫位置沒有特殊要求
get_caption
和set_caption
函式,可以在display
模組未被初始化或遊戲視窗未被建立的情況下呼叫,這不會影響遊戲視窗標題的顯示。
什麽是視窗的圖示標題?
在一些作業系統中,視窗的圖示標題是指視窗在最小化時所顯示的標題。
下面,我們在呼叫set_mode
函式之前,設定了遊戲視窗的標題,這沒有任何問題。
# …
# 設定遊戲視窗的標題
display.set_caption('一個 Pygame 遊戲')
print(display.get_caption())
# …
('一個 Pygame 遊戲', '一個 Pygame 遊戲')
設定遊戲視窗的圖示
display
模組的set_icon
函式可用於設定遊戲視窗的圖示,該函式可能會呼叫init
函式,如果display
模組尚未進行初始化。當然,呼叫set_icon
函式不是必須的,因為遊戲視窗擁有 Pygame 提供的預設圖示。
set_icon(surface)
- surface 參數
surface
參數是一個繪製了圖示的Surface
物件,該圖示將作為遊戲視窗的圖示。
set_icon 函式應該在建立遊戲視窗之前呼叫
如果你希望設定遊戲視窗的圖示,那麽應該在建立遊戲視窗之前呼叫set_icon
函式,因為,一些作業系統可能不允許修改視窗的圖示,在視窗被建立之後。
下面,我們在呼叫set_mode
函式之前,設定了遊戲視窗的圖示。
# …
# 在執行腳本前,請將命令列跳躍至 window.py 所在的目錄
from pygame import image
# 設定遊戲視窗的圖示
display.set_icon(image.load('python.ico'))
# …
最小化遊戲視窗
display
模組的iconify
函式可將遊戲視窗最小化(圖示化),當然,並非所有的作業系統都支援視窗的最小化,iconify
的傳回值會說明遊戲視窗的最小化是否成功。
iconify()
- 傳回值
如果
iconify
函式傳回True
,那麽說明遊戲視窗已經成功最小化。
from pygame import display
# 建立並最小化遊戲視窗
display.set_mode([800, 600])
print(f'最小化成功?{display.iconify()}')
最小化成功?True
判斷遊戲視窗的表面是否處於活動狀態
display
模組的get_active
函式,可用於判斷遊戲視窗的表面是否處於活動狀態。如果處於活動狀態,則表示遊戲視窗的表面在熒幕上是活動的,但他對於玩家未必是可見的,比如,遊戲視窗被其他視窗遮蓋。如果通過iconify
函式或玩家手動將遊戲視窗最小化,那麽表面將處於非活動狀態。
get_active()
- 傳回值
如果
get_active
函式傳回True
,那麽表示遊戲視窗的表面處於活動狀態。
遊戲視窗的表面是否處於活動狀態與視窗是否擁有焦點無關
需要指出,get_active
函式依然可能傳回True
,即便目前的遊戲視窗沒有獲得焦點。
from pygame import display
# 建立遊戲視窗
display.set_mode((800, 600))
print(f'活動狀態?{display.get_active()}')
# 最小化遊戲視窗後,視窗處於非活動狀態
display.iconify()
print(f'活動狀態?{display.get_active()}')
活動狀態?True
活動狀態?False
取得遊戲視窗的大小
display
模組的get_window_size
函式,可用於取得遊戲視窗的顯示區域的大小。
get_window_size()
- 傳回值
get_window_size
函式的傳回值是一個形式類似於(width,height)
的 Python 元組,其中width
為視窗顯示區域的寬度,height
為視窗顯示區域的高度。
遊戲視窗的顯示區域大小可能與遊戲視窗的表面大小不同
如果你在呼叫set_mode
函式時為flags
參數傳遞了SCALED
,那麽get_window_size
函式所傳回的遊戲視窗的顯示區域大小,可能與遊戲視窗的表面大小(set_mode
函式的size
參數)不同,因為遊戲視窗的表面可能會被縮放。
在下面的範例中,我們建立了一個表面很小的視窗,由於熒幕較大並且采用了SCALED
,因此 Pygame 將縮放視窗表面。
from pygame import display, SCALED
# 建立一個較小的視窗,SCALED 將縮放視窗的表面
s = display.set_mode([300, 200], SCALED)
print(f'顯示區域大小:{display.get_window_size()}')
print(f'表面大小:{s.get_size()}')
顯示區域大小:(1800, 1200)
表面大小:(300, 200)
取得桌面(熒幕)大小
display
模組的get_desktop_sizes
函式,可用於取得所有桌面(熒幕)的大小。
get_desktop_sizes()
- 傳回值
get_desktop_sizes
函式的傳回值是一個包含元組的 Python 串列,每一個元組對應一個桌面(熒幕)的大小,其形式為(x,y)
,其中x
表示桌面(熒幕)的寬度,y
表示桌面(熒幕)的高度。
# 匯入並初始化 display 模組
from pygame import display
display.init()
# 取得所有桌面的大小
print(f'所有桌面:{display.get_desktop_sizes()}')
所有桌面:[(2560, 1440), (1920, 1080)]
切換遊戲視窗的全熒幕模式
display
模組的toggle_fullscreen
函式,可用於將遊戲視窗在視窗模式和全熒幕模式之間切換。
toggle_fullscreen()
- 傳回值
如果
toggle_fullscreen
函式傳回0
,那麽表示遊戲視窗已成功切換至全熒幕模式或視窗模式。如果toggle_fullscreen
函式傳回-1
,那麽表示切換模式的過程中遇到了問題,遊戲視窗可能會被重新建立。
toggle_fullscreen 函式可能無法切換遊戲視窗的模式
在某些情況下,toggle_fullscreen
函式並不能完成遊戲視窗的模式切換,這可能是因為 Pygame 與顯示驅動之間存在某些問題。此外,在 Windows 系統中,遊戲視窗的表面大小需要在受支援的範圍內,或set_mode
函式的flags
參數需要包含SCALED
,否則將視窗切換至全熒幕模式可能會遇到問題。
關於如何判斷遊戲視窗的表面大小是否被支援,請參考取得顯示模式所支援的視窗表面大小一段。
在下面的範例中,由於大小 700x600 並未被 Windows 系統支援,因此,第一次呼叫toggle_fullscreen
函式傳回了-1
,遊戲視窗被重新建立。
from pygame import display
# 建立遊戲視窗並在全熒幕模式和視窗模式之間切換
display.set_mode((700, 600))
print(f'切換至全熒幕模式:{display.toggle_fullscreen()}')
print(f'切換至視窗模式:{display.toggle_fullscreen()}')
Warning: re-creating window in toggle_fullscreen
print(f'切換至全熒幕模式:{display.toggle_fullscreen()}')
切換至全熒幕模式:-1
切換至視窗模式:0
取得熒幕的個數
display
模組的get_num_displays
函式,可用於取得熒幕的個數。
get_num_displays()
- 傳回值
get_num_displays
函式的傳回值是一個整數,表示熒幕的個數。如果display
模組沒有初始化,則傳回值為0
。
在 SDL 2 之前的版本中,get_num_displays
函式總是傳回1
。
# …
# 取得熒幕個數
print(f'熒幕個數:{display.get_num_displays()}')
熒幕個數:2
取得和設定是否啟用熒幕保護程式
display
模組的get_allow_screensaver
和set_allow_screensaver
函式,可用於取得和設定是否允許熒幕保護程式在遊戲執行階段啟動。
get_allow_screensaver()
- 傳回值
如果
get_allow_screensaver
函式傳回True
,那麽表示允許熒幕保護程式在遊戲執行階段啟動,不過該函式一般會傳回False
,因為 Pygame 預設不允許熒幕保護程式啟動。
set_allow_screensaver(value=True)
- value 參數
value
是一個布林值,如果為True
,則表示允許熒幕保護程式在遊戲執行階段啟動。
set_allow_screensaver 函式可能不會達到預期效果
設定是否允許熒幕保護程式在遊戲執行階段啟動,需要作業系統的支援,因此set_allow_screensaver
函式可能無法達到預期效果。當系統未能成功設定熒幕保護程式時,你無法從set_allow_screensaver
函式得知這一點,因為 Pygame 無法獲得作業系統的回饋。
# 匯入並初始化 display 模組
from pygame import display
display.init()
# 取得和設定是否允許熒幕保護程式在遊戲執行階段啟動
print(f'允許熒幕保護程式啟動?{display.get_allow_screensaver()}')
display.set_allow_screensaver()
print(f'允許熒幕保護程式啟動?{display.get_allow_screensaver()}')
允許熒幕保護程式啟動?False
允許熒幕保護程式啟動?True