URLhttps://learnscript.net/zh-hant/pygame/surface/draw/
    複製連結移至說明  範例

    如何繪製表面(影像,字型)?以及色彩混合模式,裁剪區域,鎖定等問題

    閱讀 16:36·字數 4983·發佈 
    Youtube 頻道
    訂閱 375

    Pygame 中的色彩混合模式

    在 Pygame 中,如果Surface物件支援透明度,那麽在繪製擁有透明度的色彩時,混合模式將決定色彩的顯示效果,即被繪製的色彩如何與相同位置的原有色彩進行計算。如果原有色彩沒有透明度或者表面物件不支援透明度,那麽即便設定了混合模式也不會生效。

    pygame模組提供了以下變數,可用於在函式或方法中設定色彩的混合模式,BLEND_ADDBLEND_SUBBLEND_MULTBLEND_MINBLEND_MAXBLEND_RGBA_ADDBLEND_RGBA_SUBBLEND_RGBA_MULTBLEND_RGBA_MINBLEND_RGBA_MAXBLEND_RGB_ADDBLEND_RGB_SUBBLEND_RGB_MULTBLEND_RGB_MINBLEND_RGB_MAXBLEND_PREMULTIPLIEDBLEND_ALPHA_SDL2

    為表面填入色彩

    Surface物件的fill方法,可用於為遊戲表面的指定區域填入某種色彩,並指定混合模式。

    fill(color, rect, special_flags)

    color 參數

    color參數是一個包含色彩資訊的物件,該物件的書寫格式與Color物件的建構子的rgbvalue參數類似。

    rect 參數

    rect參數是一個包含矩形資訊的物件,決定了表面物件的一些特性,該物件的書寫格式與Rect物件的建構子的single_arg參數類似。

    special_flags 參數

    special_flags參數是色彩的混合模式,你可以檢視色彩混合模式一段來了解更多。

    色彩,矩形

    關於Color建構子的rgbvalue參數,你可以檢視Pygame 中的 Color 物件一段。關於Rect建構子的single_arg參數,你可以檢視Pygame 中的 Rect 物件一段。

    在下面的範例中,我們繪製了兩個矩形,其中一個透明,另一個不透明,他們有部分區域是重疊的,混合模式為色彩相加。

    fill.py
    from pygame import Surface, SRCALPHA, BLEND_RGBA_ADD
    
    # 建立支援透明度的表面,並設定表面的透明度 s = Surface((800, 600), SRCALPHA) # 繪製一個不透明矩形 s.fill('#ff0000', [100, 100, 100, 100]) # 繪製一個透明矩形,與不透明矩形部分重疊 s.fill('#ffff0099', [150, 150, 100, 100], BLEND_RGBA_ADD)
    # 建立遊戲視窗並繪製 s from pygame import display w = display.set_mode((800, 600)) w.blit(s, (0, 0)) display.flip()
    import time time.sleep(3)

    在表面中繪製表面

    Pygame 繪製 Surface 表面
    影片示範 YouTube

    Surface物件的blit方法,可用於在遊戲表面中繪製另一個表面。

    blit(source, dest, area=None, special_flags=0)

    source 參數

    source參數是需要被繪製的表面物件。

    dest 參數

    dest參數表示了繪製的開始位置,他可以是依次包含 X 座標和 Y 座標的 Python 浮點數序列物件,或者是包含矩形資訊的物件(書寫格式與Rect物件的建構子的single_arg參數類似),矩形的左上角座標即為繪製的開始位置(矩形的大小不會起到任何作用)。

    area 參數

    area參數是一個包含矩形資訊的物件,用於指定繪製source參數所表示的表面的哪個區域,該物件的書寫格式與Rect物件的建構子的single_arg參數類似。

    special_flags 參數

    special_flags參數是色彩的混合模式,你可以檢視色彩混合模式一段來了解更多。

    傳回值

    blit方法的傳回值是一個Rect物件,表示目標表面中被實際繪製了內容的區域,該區域不會超出表面的裁剪區域。

    Surface物件的blits方法,可用於在遊戲表面中繪製多個其他表面。

    blits(blit_sequence, doreturn=1)

    blit_sequence 參數

    blit_sequence參數是一個包含數個元組的 Python 序列物件,每一個元組的形式均類似於(source,dest,area,special_flags),其中的sourcedestareaspecial_flags的含義和書寫格式與blit方法的sourcedestareaspecial_flags參數相同。

    你可以省略元組中的元素areaspecial_flags,因此,元組的形式也可以類似於(source,dest)(source,dest,area)(source,dest,special_flags)

    doreturn 參數

    如果doreturn參數等價於True,那麽blits方法將傳回實際繪製區域,否則將傳回None

    傳回值

    blits方法的傳回值是None或一個包含數個Rect物件的 Python 串列,Rect物件表示目標表面中被實際繪製了內容的區域,該區域不會超出表面的裁剪區域。

    色彩深度為 8 的 Pygame Surface 物件不支援色彩的透明度

    如果Surface物件的色彩深度為 8,那麽表面將不支援色彩的透明度,source參數所表示的表面中的色彩的透明度將被忽略。

    blit.py
    from pygame import Surface
    
    # 建立一些表面物件 s1 = Surface([100, 100]) s1.fill(0xff0000, [0, 0, 100, 100]) s2 = Surface([50, 50]) s2.fill('green', [0, 0, 50, 50]) s3 = Surface([100, 100]) s3.fill('#0000ff', [0, 0, 100, 100])
    # 建立遊戲視窗並繪製多個表面 from pygame import display w = display.set_mode((800, 600)) w.blits([ (s1, (0, 0)), (s2, (100, 0)), # 只繪製 s3 的左上角區域 (s3, (150, 0), [0, 0, 25, 25]) ]) display.flip()
    # 等候 3 秒鐘 import time time.sleep(3)

    轉換表面的像素格式

    如果一個表面物件需要被多次的繪製,那麽可以事先轉換像素格式,使其與需要繪製到的表面的像素格式相同。

    Surface物件的convert方法,將根據給出的像素格式建立一個新的不支援透明度的表面,如果沒有給出任何參數,則采用遊戲視窗對應的表面的像素格式。

    convert()
    convert(surface)
    convert(depth, flags=0)
    convert(masks, flags=0)

    surface 參數

    surface參數是一個表面物件,將采用該表面物件的像素格式。

    depth,flags,masks 參數

    參數depthflagsmasks,與Surface物件的建構子的同名參數的作用和書寫格式相同,分別表示表面的色彩深度,特性,以及用於色彩對映整數的遮罩。

    傳回值

    convert方法的傳回值是一個已經轉換了像素格式的新的Surface物件。

    convert方法類似,Surface物件的convert_alpha方法同樣會根據給出的像素格式建立一個新的表面,只不過該表面支援透明度。

    convert_alpha()
    convert_alpha(surface)

    surface 參數

    surface參數是一個表面物件,將采用該表面物件的像素格式。

    傳回值

    convert_alpha方法的傳回值是一個已經轉換了像素格式的新的Surface物件。

    表面

    關於Surface建構子的相關參數,你可以檢視Pygame 中的 Surface 物件一段。

    在下面的範例中,雖然使用了變數SRCALPHA,但表面物件cs並不支援透明度,因此,第一個紅色正方形沒有透明效果。

    convert.py
    # 匯入並建立遊戲視窗
    from pygame import display, Surface, SRCALPHA
    w = display.set_mode((800, 600))
    
    # 建立支援透明度的表面物件,填入具有透明度的紅色正方形 s = Surface([100, 100], SRCALPHA) s.fill('#ff000099', [0, 0, 100, 100])
    # 轉換像素格式,新表面不支援透明度 cs = s.convert(16, SRCALPHA) print(f'cs 特性:{cs.get_flags()}') # 轉換像素格式,新表面支援透明度 cas = s.convert_alpha() print(f'cas 特性:{cas.get_flags()}')
    # 在遊戲視窗中繪製 cs 和 cas w.blit(cs, (0, 0)) w.blit(cas, (100, 100)) display.flip()
    import time time.sleep(3)

    在表面中繪製影像和文字(字型)

    Pygame 繪製影像和文字
    影片示範 YouTube

    事實上,在 Pygame 中無論是影像還是文字,最終只能以Surface表面物件的形式被繪製。對於影像,在使用image模組載入影像檔案後,你將獲得已經繪製了影像的表面物件,對於文字,你需要首先建立Font物件,然後使用字型物件的render方法,將指定的文字轉換為一個表面物件。

    render(text, antialias, color, background=None)

    text 參數

    text參數是包含了需要繪製的文字的字串。

    antialias 參數

    如果antialias參數等價於True,那麽被繪製的文字將擁有反鋸齒效果。

    color 參數

    color參數表示文字的色彩,其書寫格式與Color物件的建構子的rgbvalue參數類似。

    background 參數

    background參數表示文字的背景色彩(預設為None,背景透明),其書寫格式與Color物件的建構子的rgbvalue參數類似。

    傳回值

    render方法的傳回值是繪製了文字的Surface物件。

    Font 物件的 render 方法不會處理字串中的跳脫序列

    Font物件的render方法不會處理字串中的跳脫序列,比如,換行字元\n和定位字元\t,他們可能會被表示為一個或數個空心方塊,這意味著要繪製多行文字可能需要多次呼叫render方法。

    font_image.py
    # 匯入模組並進行初始化
    from pygame import font, image
    font.init()
    
    # 使用 Pygame 預設字型繪製文字 Hello f = font.Font(size=30) ts = f.render('Hello', True, [2, 255, 0], '#ffffff')
    # 載入影像檔案 img = image.load('candy.png')
    # 建立遊戲視窗並繪製 ts 和 img from pygame import display w = display.set_mode([800, 600]) w.blit(ts, (50, 50)) w.blit(img, (100, 100)) display.flip()
    import time time.sleep(3)

    取得和設定表面的裁剪區域

    每一個 Pygame 的表面物件都擁有一個裁剪區域,位於裁剪區域以外的像素是不可修改的,預設情況下,裁剪區域等同於表面自身,這表示你可以為表面中的任意像素設定色彩。

    Surface物件的get_clip方法,可用於取得表面物件的裁剪區域。

    get_clip()

    傳回值

    get_clip方法的傳回值是表示表面裁剪區域的Rect物件。

    Surface物件的set_clip方法,可用於設定表面物件的裁剪區域。

    set_clip(rect)

    rect 參數

    rect參數是一個包含矩形資訊的物件,該物件用於指定表面的裁剪區域,其書寫格式與Rect物件的建構子的single_arg參數類似。

    如果rect參數為None,那麽裁剪區域將等同於表面自身。

    在下面的範例中,白色的正方形被設定為了表面的裁剪區域,而之後繪製的綠色正方形並沒有全部顯示,因為他的一部分在裁剪區域之外,當我們重新將裁剪區域設定為表面自身後,藍色正方形被完整的繪製。

    clip.py
    from pygame import Surface
    
    s = Surface([800, 600]) # 繪製一個白色的正方形並將其設定為裁剪區域 s.fill('white', ((100, 100), (100, 100))) s.set_clip((100, 100), (100, 100)) print(f'目前裁剪區域:{s.get_clip()}')
    # 繪製一個與白色正方形部分重疊的綠色正方形 s.fill('#00ff00', (150, 150, 100, 100))
    # 將整個表面設定為裁剪區域 s.set_clip(None) print(f'目前裁剪區域:{s.get_clip()}')
    # 繪製一個與白色正方形部分重疊的藍色正方形 s.fill('#0000ff', [50, 50, 100, 100])
    # 建立遊戲視窗並繪製 s from pygame import display w = display.set_mode((800, 600)) w.blit(s, (0, 0)) display.flip()
    import time time.sleep(3)
    目前裁剪區域:<rect(100, 100, 100, 100)>
    目前裁剪區域:<rect(0, 0, 800, 600)>

    Surface 物件的裁剪區域不會超出表面自身表示的範圍

    set_clip方法的rect參數指示一個超出表面自身範圍的裁剪區域時,該裁剪區域將被調整(超出表面自身範圍的區域將不被考慮),以使其完全處於表面所表示的範圍之內。

    clip_outside.py
    from pygame import Surface
    
    s = Surface([100, 100]) # 裁剪區域超出了表面的大小 s.set_clip((0, 0, 110, 120)) print(f'目前裁剪區域:{s.get_clip()}')
    目前裁剪區域:<rect(0, 0, 100, 100)>

    鎖定和解除鎖定表面

    Surface物件的lockunlock方法,可用於鎖定和解除鎖定表面。當一個表面被鎖定時,Pygame 將不能對其進行繪製和管理,這意味著該表面無法顯示在遊戲中,除非他被解除鎖定,正因如此,你不應該讓一個Surface物件長時間處於鎖定狀態。

    lock()
    unlock()

    Surface物件的mustlock方法,可用於判斷是否必須鎖定表面,在存取與表面像素相關的資料之前,該方法幾乎不會被使用,因為 Pygame 會自行管理表面的鎖定和解除鎖定。

    mustlock()

    傳回值

    如果mustlock方法傳回True,那麽表示表面需要鎖定。

    Surface物件的get_locked方法,可用於判斷表面是否已經被鎖定。

    get_locked()

    傳回值

    如果get_locked方法傳回True,那麽表示表面已經被鎖定。

    Surface物件的get_locks方法,可用於取得已經被鎖定的表面,通常是指表面自身,但也可能是該表面的子表面。

    get_locks()

    傳回值

    get_locks方法傳回一個 Python 元組,元組中包含了被鎖定的表面物件。這裏需要說明的是,如果你多次呼叫Surface物件的lock方法,那麽Surface物件可能會重複出現在元組中。

    Surface 物件通常被自動鎖定或解除鎖定

    當需要對遊戲表面進行某種讀取或寫入時,一些方法或函式將自動鎖定或解除鎖定Surface表面物件,因此,需要主動呼叫lock方法的情況並不多,除非有大量鎖定和解除鎖定表面的操作,比如,對表面中的每個像素逐一進行讀取或修改。

    在下面的範例中,由於我們鎖定了表面物件s1,因此,將其繪製到表面物件s2會引發例外狀況pygame.error: Surfaces must not be locked during blit

    lock.py
    from pygame import Surface
    
    s1 = Surface([800, 600]) s1.fill('white', [0, 0, 100, 100]) print(f'是否需要鎖定:{s1.mustlock()}') # 鎖定表面兩次 s1.lock() s1.lock() print(f'是否已經鎖定:{s1.get_locked()}') print(f'已經存在的鎖定:{s1.get_locks()}')
    s2 = Surface([800, 600]) # ERROR 無法繪製被鎖定的表面 s2.blit(s1, [0, 0])
    pygame.error: Surfaces must not be locked during blit

    原始碼

    src/zh-hant/surface/draw·codebeatme/pygame·GitHub

    講解影片

    Pygame 繪製 Surface 表面·YouTube
    Pygame 繪製影像和文字·YouTube
    Pygame 轉換像素格式,提高 Surface 表面的算繪效率·YouTube