如何使用 Surface 表面物件?以及表面(影像)的透明度,透明色彩鍵,色彩,大小等問題
訂閱 480
本節內容不涉及矩形的碰撞偵測和子表面。
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