如何使用 Surface 表面物件?以及表面(影像)的透明度,透明色彩鍵,色彩,大小等問題
訂閱 375
本節內容不涉及矩形的碰撞偵測和子表面。
Pygame 取得 Surface 表面的大小及其 Rect 矩形物件影片示範 YouTube
Pygame 表面(影像)透明度控製,Surface 物件簡介影片示範 YouTube
Pygame 中的 Surface 物件
在 Pygame 中,可以將Surface
表面物件理解為畫布,一些內容會被繪製在畫布中,比如,影像,圖形或另一個畫布。某些模組的函式的傳回值是一個Surface
表面物件,比如,display
模組的set_mode
函式,如果你希望使用建構子建立Surface
物件,則size
參數是必需的,其他參數可以省略。一旦Surface
物件被建立,其特性和色彩深度將是不可改變的,並將被黑色填入。
Surface(size, flags, depth, masks)
Surface(size, flags, surface)
- size 參數
size
參數表示表面的大小,他可以是依次包含表面寬度和高度的 Python 浮點數序列物件,或一個Vector2
物件(物件的x
變數對應表面寬度,物件的y
變數對應表面高度)。- flags 參數
flags
參數是一個整數,決定了表面物件的一些特性,可以是以下pygame
模組變數,SRCALPHA
(使用色彩中的透明度資訊來計算透明度)。- depth 參數
depth
參數是表示色彩深度的整數,一般不需要設定,除非你希望使用自己的像素格式,隨意指定depth
可能導致遊戲執行緩慢。- masks 參數
masks
參數是一個包含四個整數的 Python 元組,表示用於轉換色彩和對映整數的遮罩。- surface 參數
surface
參數是作為參考的另一個表面物件,當你沒有或無法提供參數flags
,depth
或masks
時,將采用該表面物件的特性,色彩深度或遮罩。
在下面的範例中,表面s1
和表面s2
的色彩深度相同。
# 匯入 Surface 物件
from pygame import Surface
# 建立大小為 800x600,色彩深度為 16 的表面
s1 = Surface((800, 600), depth=16)
print(f'色彩深度:{s1.get_bitsize()}')
# 表面 s2 的色彩深度與 s1 相同
s2 = Surface([400, 300], 0, s1)
print(f'色彩深度:{s2.get_bitsize()}')
色彩深度:16
色彩深度:16
取得表面的大小
Surface
物件的get_width
,get_height
,get_size
方法,可用於取得表面的寬度,高度和大小。
get_width()
- 傳回值
get_width
方法的傳回值是表示表面寬度的整數。
get_height()
- 傳回值
get_height
方法的傳回值是表示表面高度的整數。
get_size()
- 傳回值
get_size
方法的傳回值是形式為(width,height)
的 Python 整數元組,其中width
為表面寬度,height
為表面高度。
from pygame import Surface
# 建立大小為 800x600 的表面
s = Surface((800, 600))
# 顯示表面的大小
print(f'寬度:{s.get_width()} 高度:{s.get_height()} 大小:{s.get_size()}')
寬度:800 高度:600 大小:(800, 600)
根據表面的大小建立矩形
Surface
物件的get_rect
方法,可根據表面的大小建立一個新的矩形,預設情況下,新矩形的左上角為原點,大小與表面相同。
get_rect(**kwargs)
- kwargs 參數
可變參數
kwargs
所包含的位置參數將用於設定新的矩形物件,位置參數的名稱需要與矩形物件的變數名稱相同。- 傳回值
get_rect
方法的傳回值是Rect
物件。
矩形
關於Rect
矩形物件的變數,你可以檢視取得和設定矩形資訊一段。
在下面的範例中,我們根據表面物件s
建立了一個新的矩形,並設定了該矩形的左上角座標。
from pygame import Surface
# 建立大小為 800x600 的表面
s = Surface((800, 600))
# 根據表面建立矩形,並設定左上角座標為 10 10
print(s.get_rect(topleft=(10, 10)))
<rect(10, 10, 800, 600)>
取得表面的特性
Surface
物件的get_flags
方法,可用於取得表面的特性,你可以通過與位元運算子&
來判斷表面是否具有某一特性。以下是一些表示表面特性的pygame
模組變數,HWACCEL
(使用硬體加速),RLEACCEL
(表面采用 RLE 編碼),SWSURFACE
(表面儲存在系統記憶體,而非顯卡記憶體),PREALLOC
(表面采用預分配記憶體),SRCALPHA
(表面支援像素色彩中的透明度),SRCCOLORKEY
(使用表面的透明色彩鍵來計算透明度)。
get_flags()
- 傳回值
get_flags
方法的傳回值是表示表面特性的整數。
from pygame import Surface, SRCALPHA
# 建立支援透明度的表面
s = Surface([400, 300], SRCALPHA)
# 通過 & 判斷表面是否支援透明度
f = s.get_flags()
print(f'表面支援色彩透明度?{f & SRCALPHA == SRCALPHA}')
表面支援色彩透明度?True
取得和設定表面的透明度
如果Surface
表面物件被設定了透明度,那麽表面中繪製的內容將被透明度影響,當然這還要取決於繪製時所采用的參數。
Surface
物件的get_alpha
方法,可用於取得表面的透明度。
get_alpha()
- 傳回值
get_alpha
方法傳回表示表面透明度的整數,範圍從0
到255
。
Surface
物件的set_alpha
方法,可用於設定表面的透明度。
set_alpha(value)
set_alpha(value, flags=0)
- value 參數
value
參數是表示表面透明度的整數,範圍從0
到255
,其中0
為完全透明,255
為不透明。這裏需要特別說明,如果將
value
參數設定為空值None
,那麽不但表面不再擁有透明度,像素中的透明度也不再生效,即便你在建立表面物件時,將建構子的flags
參數設定為了SRCALPHA
。- flags 參數
flags
參數可以被設定為pygame
模組的RLEACCEL
變數,以在未啟用硬體加速的情況下提供更好的效能,這會導致表面在其內容被修改時的效率下降,但被其他表面算繪時的效率上升。
from pygame import Surface, SRCALPHA
# 建立支援透明度的表面,並設定表面的透明度
s = Surface((800, 600), SRCALPHA)
s.set_alpha(50)
print(f'表面的透明度:{s.get_alpha()}')
# 在表面繪製兩個透明度不同的矩形
from pygame import draw
draw.rect(s, '#ff0000', [0, 0, 50, 50])
draw.rect(s, '#ff000099', [50, 0, 50, 50])
# 建立遊戲視窗並繪製 s
from pygame import display
w = display.set_mode((800, 600))
w.blit(s, (0, 0))
display.flip()
import time
time.sleep(3)
表面的透明度:50
取得和設定表面的透明色彩鍵
Pygame 影像背景的透明處理影片示範 YouTube
如果Surface
表面物件擁有透明色彩鍵,並且所繪製內容的色彩與透明色彩鍵相同(色彩中的紅色,綠色,藍色相同),那麽該內容將不會被繪製,無論表面物件自身是否支援色彩的透明度。
Surface
物件的get_colorkey
方法,可用於取得表面所使用的透明色彩鍵。
get_colorkey()
- 傳回值
get_colorkey
方法的傳回值是表示透明色彩鍵的形式類似於(r,g,b,a)
的 Python 元組,其中r
表示紅色,g
表示綠色,b
表示藍色,a
表示透明度(始終為255
)。如果表面物件沒有設定透明色彩鍵,那麽get_colorkey
方法會傳回空值None
。
Surface
物件的set_colorkey
方法,可用於設定表面所使用的透明色彩鍵。
set_colorkey(color)
set_colorkey(color, flags=0)
- color 參數
color
參數是一個包含透明色彩鍵資訊的物件,該物件的書寫格式與Color
物件的建構子的rgbvalue
參數類似,色彩中的透明度始終被視為255
(不透明)。如果將color
參數設定為None
,則表示取消表面的透明色彩鍵。- flags 參數
flags
參數可以被設定為pygame
模組的RLEACCEL
變數,以在未啟用硬體加速的情況下提供更好的效能,這會導致表面在其內容被修改時的效率下降,但被其他表面算繪時的效率上升。
在下面的範例中,我們將透明色彩鍵設定為紅色,之後被繪製的第一個紅色矩形將是完全透明的,無論其自身是否擁有透明度,第二個黃色矩形將是半透明的,因為其自身擁有並且表面支援透明度。
from pygame import Surface, SRCALPHA
# 建立支援透明度的表面,並將其透明色彩鍵設定為紅色
s = Surface((800, 600), SRCALPHA)
s.set_colorkey(0xff0000)
print(f'透明色彩鍵:{s.get_colorkey()}')
# 在表面分別繪製紅色和黃色的矩形
from pygame import draw
draw.rect(s, '#ff000088', [0, 0, 50, 50])
draw.rect(s, '#ffff0099', [50, 0, 50, 50])
# 建立遊戲視窗並繪製 s
from pygame import display
w = display.set_mode((800, 600))
w.blit(s, (0, 0))
display.flip()
import time
time.sleep(3)
透明色彩鍵:(255, 0, 0, 17)
預先計算表面中的色彩的透明度
Surface
物件的premul_alpha
方法,可預先將表面中像素的色彩的透明度與紅色,綠色,藍色進行計算,並將計算結果作為新的表面物件傳回。預先計算透明度對於混合模式BLEND_PREMULTIPLIED
非常有效,因為該模式認為色彩中的紅色,綠色,藍色已經與透明度進行了計算,這可以在一定程度上改進算繪的效率。
premul_alpha()
- 傳回值
premul_alpha
方法的傳回值是預先計算了透明度的新的Surface
表面物件。
premul_alpha 方法不會計算表面自身的透明度
Surface
物件的premul_alpha
方法的傳回值不會受表面自身透明度的影響,即使通過set_alpha
方法為表面設定了有效的透明度,因為premul_alpha
只考慮表面中像素的透明度。關於set_alpha
方法,請參考取得和設定表面的透明度一段。
在下面的範例中,我們預先計算表面物件s
的透明度,得到了新的表面物件pa
,將兩個表面物件同時繪製在遊戲視窗中,他們展現了不同的透明度,因為premul_alpha
方法不考慮表面自身的透明度。
from pygame import Surface, SRCALPHA, BLEND_PREMULTIPLIED
# 建立一個表面並填入具有透明度的紅色
s = Surface([100, 100], SRCALPHA)
s.fill([255, 0, 0, 100])
# 將表面自身的透明度設定為 50
s.set_alpha(50)
# 預先計算透明度
pa = s.premul_alpha()
# 建立遊戲視窗並繪製 s 和 pa(pa 使用 BLEND_PREMULTIPLIED)
from pygame import display
w = display.set_mode((800, 600))
w.blit(s, (0, 0))
w.blit(pa, (100, 100), special_flags=BLEND_PREMULTIPLIED)
display.flip()
import time
time.sleep(3)
取得和設定表面的調色板
Surface
物件的get_palette
方法,可用於取得色彩深度為 8 的表面所使用的索引色彩(調色板)。
get_palette()
- 傳回值
get_palette
方法的傳回值是一個包含Color
物件的 Python 元組,每一個Color
物件對應一個索引色彩。
Surface
物件的get_palette_at
方法,可根據給出的索引取得調色板中的某個色彩,僅適用於色彩深度為 8 的表面。
get_palette_at(index)
- index 參數
index
參數是調色板中某個色彩的索引,取值範圍是0
到255
。- 傳回值
get_palette_at
方法的傳回值是一個表示索引色彩的Color
物件。
Surface
物件的set_palette
方法,可用於設定色彩深度為 8 的表面所使用的索引色彩(調色板)。
set_palette(palette)
- palette 參數
palette
參數是一個包含索引色彩資訊的 Python 序列物件,色彩資訊的書寫格式與Color
物件的建構子的rgbvalue
參數類似,但其不支援字串和整數(0xRRGGBBAA
),並且色彩的透明度必須為255
(不透明)。這裏需要說明,
palette
參數不必給出調色板中的全部 256 個索引色彩,比如,當只給出一個索引色彩時,則只有調色板的第一個索引色彩被修改,其余索引色彩不變。
Surface
物件的set_palette_at
方法,可根據給出的索引設定調色板中的某個色彩,僅適用於色彩深度為 8 的表面。
set_palette_at(index, color)
- index 參數
index
參數是調色板中某個色彩的索引,取值範圍是0
到255
。- color 參數
color
參數是一個包含索引色彩資訊的物件,該物件的書寫格式與Color
物件的建構子的rgbvalue
參數類似,但其不支援字串和整數(0xRRGGBBAA
),並且色彩中的透明度始終被視為255
(不透明)。
無法通過 get_palette,get_palette_at 方法所傳回的 Color 物件修改調色板中的色彩
Surface
物件的get_palette
,get_palette_at
方法所傳回的Color
物件是調色板色彩的複本,因此修改他們不會影響調色板中的原有色彩。
色彩
關於Color
建構子的rgbvalue
參數,你可以檢視Pygame 中的 Color 物件一段。
在下面的範例中,我們將調色板的第一個色彩(黑色)修改為了紅色,這將導致黑色背景的表面物件s
被顯示為紅色。
from pygame import Surface, Color
# 建立色彩深度為 8 的表面
s = Surface((800, 600), depth=8)
# 取得調色板
print(s.get_palette())
# 設定調色板中的第一個色彩(黑色)
s.set_palette([(255, 0, 0)])
# 取得調色板中的第一個色彩
c = s.get_palette_at(0)
print(c)
# 設定調色板中的第二個色彩
s.set_palette_at(1, Color('#00FF00'))
# 建立遊戲視窗並繪製 s
from pygame import display
w = display.set_mode((800, 600))
w.blit(s, (0, 0))
display.flip()
import time
time.sleep(3)
((0, 0, 0, 255), (0, 0, 85, 255),…)
(255, 0, 0, 255)
取得和設定表面中的某個像素的色彩
Surface
物件的get_at
和get_at_mapped
方法,可根據給出的座標,取得表面中某個像素的色彩。
get_at(x_y)
get_at_mapped(x_y)
- x_y 參數
x_y
參數是依次包含 X 座標和 Y 座標的 Python 整數序列物件。如果座標所指示的位置超出了表面的範圍,那麽將引發例外狀況IndexError
。- 傳回值
get_at
方法的傳回值是表示像素色彩的Color
物件,如果表面物件不支援透明度,那麽所傳回的Color
物件的透明度始終為255
。get_at_mapped
方法的傳回值是表示像素色彩的對映整數。
Surface
物件的set_at
方法,可用於設定表面中某個像素的色彩。
set_at(x_y, color)
- x_y 參數
x_y
參數是依次包含 X 座標和 Y 座標的 Python 整數序列物件。如果座標所指示的位置超出了表面的有效範圍,那麽set_at
方法不會產生任何影響。- color 參數
color
參數是一個包含色彩資訊的物件,該物件的書寫格式與Color
物件的建構子的rgbvalue
參數類似。如果表面物件使用了調色板,那麽將在調色板中選擇最接近於color
參數的色彩。
get_at,get_at_mapped,set_at 方法的效能問題
在迴圈中使用Surface
物件的get_at
,get_at_mapped
,set_at
方法,可能導致遊戲出現效能問題,以上方法可能會臨時鎖定表面物件。
無法通過 get_at 方法所傳回的 Color 物件修改像素的色彩
Surface
物件的get_at
方法所傳回的Color
物件是像素的色彩的複本,因此對其進行修改不會影響原有像素的色彩。
在下面的範例中,我們通過set_at
方法在遊戲視窗中繪製了一條白色的線段。
from pygame import Surface
# 建立表面,並取得座標為 0 0 的像素的色彩
s = Surface((800, 600))
print(f'座標 0 0 處的色彩:{s.get_at((0, 0))}')
# 繪製一條白色的線段
for i in range(100, 700):
s.set_at([i, 300], 'white')
print(f'座標 100 300 處的色彩:{hex(s.get_at_mapped([100, 300]))}')
# 建立遊戲視窗並繪製 s
from pygame import display
w = display.set_mode((800, 600))
w.blit(s, (0, 0))
display.flip()
import time
time.sleep(3)
座標 0 0 處的色彩:(0, 0, 0, 255)
座標 100 300 處的色彩:0xffffff
轉換色彩與對映整數
色彩的對映整數,即色彩在表面中對應的整數,同一個色彩在不同的表面中,其對映整數可能不同,不同色彩在同一個表面的對映整數可能相同(比如,使用了調色板的表面中的兩個相近的色彩)。要取得表面中某個座標的色彩的對映整數,請參考取得和設定表面中的某個像素的色彩一段。
Surface
物件的map_rgb
方法,可取得指定色彩在表面中的對映整數。
map_rgb(color)
- color 參數
color
參數是一個包含色彩資訊的物件,該物件的書寫格式與Color
物件的建構子的rgbvalue
參數類似,但其不支援字串和整數(0xRRGGBBAA
)。由於對映整數並不考慮透明度,因此色彩資訊中的透明度將被忽略。- 傳回值
map_rgb
方法的傳回值是色彩的對映整數。
Surface
物件的unmap_rgb
方法,可取得指定對映整數在表面中對應的色彩。
unmap_rgb(mapped_int)
- mapped_int 參數
mapped_int
參數是色彩的對映整數。- 傳回值
unmap_rgb
方法的傳回值是一個Color
物件,表示對映整數對應的色彩。
此外,Surface
物件的get_masks
,get_shifts
,get_losses
方法,可用於取得色彩與對映整數轉換所需的遮罩,移位,有效位的資訊。在正常的遊戲開發中,這三個函式很少被使用。
get_masks()
get_shifts()
get_losses()
- 傳回值
get_masks
,get_shifts
,get_losses
方法的傳回值是一個形式類似於(r,g,b,a)
的 Python 整數元組,其中r
,g
,b
,r
分別表示紅色,綠色,藍色,透明度所對應的遮罩,移位,有效位資訊。
from pygame import Surface
# 建立色彩深度為 8 的表面
s1 = Surface([400, 300], depth=8)
# 兩個不同色彩的對映整數相同
m1 = s1.map_rgb([255, 0, 0])
print(m1, s1.unmap_rgb(m1))
m2 = s1.map_rgb([250, 5, 5])
print(m2, s1.unmap_rgb(m2))
# 對映整數不考慮透明度
m3 = s1.map_rgb([255, 0, 0, 100])
print(m3, s1.unmap_rgb(m3))
# 建立色彩深度為 32 的表面
s2 = Surface([400, 300], depth=32)
# 相同的色彩在 s1 和 s2 中的對映整數不同
m3 = s2.map_rgb([255, 0, 0])
print(m3, s2.unmap_rgb(m3))
96 (255, 0, 0, 255)
96 (255, 0, 0, 255)
96 (255, 0, 0, 255)
16711680 (255, 0, 0, 255)
取得表面的界限
Surface
物件的get_bounding_rect
方法,可用於取得表面的界限,該界限是包含所有符合要求的像素的最小矩形,這些像素的色彩透明度大於或等於給出的最小透明度。
get_bounding_rect(min_alpha=1)
- min_alpha 參數
min_alpha
參數是表示最小透明度的整數,其取值範圍不限於0
到255
。- 傳回值
get_bounding_rect
方法的傳回值是表示表面界限的Rect
物件。
get_bounding_rect 方法可能不會傳回預期的結果
如果使用set_colorkey
方法為表面設定了透明色彩鍵,那麽Surface
物件的get_bounding_rect
方法所傳回的結果可能不符合你的預期,遊戲界限可能等同於整個表面。關於方法set_colorkey
,請參考取得和設定表面的透明色彩鍵一段。
至於表面自身的透明度,並不會影響get_bounding_rect
方法的計算結果,因為表面自身的透明度並非像素色彩的透明度。關於表面透明度,請參考取得和設定表面的透明度一段。
get_bounding_rect 方法的效能問題
在迴圈中使用Surface
物件的get_bounding_rect
方法,可能導致遊戲出現效能問題,該方法可能會臨時鎖定表面物件。
在下面的範例中,雖然我們將表面自身的透明度設定為了0
,但之後的表面界限依然被認定為不透明的矩形。
from pygame import Surface, SRCALPHA
# 建立支援透明度的表面
s = Surface((800, 600), SRCALPHA)
# 在表面繪製不透明與透明度為 1 的矩形
from pygame import draw
draw.rect(s, '#ff0000', [0, 0, 50, 50])
draw.rect(s, '#ff000001', [50, 0, 50, 50])
print(f'表面界限:{s.get_bounding_rect()}')
# 將表面自身的透明度設定為 0
s.set_alpha(0)
print(f'表面界限(透明度大於等於 2):{s.get_bounding_rect(2)}')
表面界限:<rect(0, 0, 100, 50)>
表面界限(透明度大於等於 2):<rect(0, 0, 50, 50)>
取得 Surface 表面物件所需的儲存空間
Surface
物件的get_bitsize
方法,可用於取得表面的色彩深度,即需要多少個 bit 來儲存一個像素(對應的色彩),該個數可能小於所需位元組對應的 bit 個數。
get_bitsize()
- 傳回值
get_bitsize
方法的傳回值是一個整數,表示需要的 bit 個數。
Surface
物件的get_bytesize
方法,可用於取得儲存一個像素(中的色彩)所需的位元組數。
get_bytesize()
- 傳回值
get_bytesize
方法的傳回值是一個整數,表示需要的位元組數。
Surface
物件的get_pitch
方法,可用於取得儲存一行像素(中的色彩)所需的位元組數。
get_pitch()
- 傳回值
get_pitch
方法的傳回值是一個整數,表示需要的位元組數。
在下面的範例中,表面s
儲存一個像素需要15
個 bit(2
個位元組,其中一個 bit 沒有被使用)。
from pygame import Surface
# 建立色彩深度為 15 的表面
s = Surface((100, 100), depth=15)
print(f'一個像素需要 {s.get_bitsize()} 個 bit,{s.get_bytesize()} 個位元組')
print(f'一行像素需要 {s.get_pitch()} 個位元組')
一個像素需要 15 個 bit,2 個位元組
取得表面的緩沖區
Surface
物件的get_buffer
方法傳回一個表示表面緩沖區的BufferProxy
物件,通過該物件可以直接存取或操作表面中的資料。get_buffer
方法將隱含的鎖定表面物件,直至BufferProxy
物件被記憶體回收。
get_buffer()
- 傳回值
get_buffer
方法傳回表示緩沖區的BufferProxy
物件。
Surface
物件的_pixels_address
變數是一個整數,表示表面緩沖區的位址。
surface._pixels_address
from pygame import Surface
s = Surface((100, 100))
# 取得表面的緩沖區物件
b = s.get_buffer()
# 取得表面緩沖區的位址
print(f'緩沖區位址:{s._pixels_address}')
緩沖區位址:…
取得表面的緩沖區檢視
Surface
物件的get_view
方法與get_buffer
方法類似,傳回一個表示表面緩沖區的BufferProxy
物件,只不過該物件中的資料經過了篩選。
get_view(kind='2')
- kind 參數
kind
參數是一個字串,表示如何對緩沖區中的資料進行篩選,可以是以下有效取值,'0'
,'1'
,'2'
,'3'
,'r'
,'g'
,'b'
,'a'
。- 傳回值
get_view
方法傳回一個BufferProxy
物件,該物件包含經過篩選的緩沖區資料。
複製表面
Surface
物件的copy
方法傳回一個新的表面物件,該物件對應的表面的大小,特性,像素格式,調色板,自身透明度(並非透明色彩鍵)等,與原有表面相同。
copy()
- 傳回值
copy
方法傳回覆製的Surface
表面物件。
在下面的範例中,雖然表面物件s1
設定了透明色彩鍵,但s2
的色彩透明鍵依然為空值None
。
from pygame import Surface, SRCALPHA
# 建立一個表面,然後複製他
s1 = Surface([400, 300], SRCALPHA, 16)
s1.set_colorkey('#ff0000')
s1.set_alpha(100)
s2 = s1.copy()
# s2 的透明色彩鍵為 None,與 s1 不同
print(f'複製的表面:{s2.get_size()} {s2.get_flags()} {s2.get_bitsize()} {s2.get_colorkey()} {s2.get_alpha()}')
複製的表面:(400, 300) 65536 16 None 100
內容分類
原始碼
講解影片
Pygame 取得 Surface 表面的大小及其 Rect 矩形物件·YouTube
Pygame 表面(影像)透明度控製,Surface 物件簡介·YouTube
Pygame 影像背景的透明處理·YouTube