層疊式圖像 link

當某個精靈(sprite)集的複雜度到達某個等級後,分別定義出每種可能的組合就會變得非常不便。 例如,某個角色有4套服裝、4種髮型和6種表情,就總共有96種組合方式。 針對每種可能的組合創建靜態圖像會占用很多磁碟空間和編程時間。

為了應對這種使用場景,Ren’Py提供了一種辦法,可以定義多個圖層(layer)組成的圖像。 (此處的圖層跟Ren’Py中其他地方的“圖層”不太一樣,更類似於Photoshop或者GIMP等繪圖程序中圖層的概念。) 有兩種方法選擇圖層中需要顯示的元素,一直是通過圖像的 屬性 ,另一種是根據條件即時計算。

使用 layeredimage 語句和一些指定格式的腳本可以定義層疊式圖像。 LayeredImage() 對象是另一種 Python 形式的層疊式圖像。它不是 可視組件,但可以用 image 語句聲明,用法也與可視組件類似。

本頁結尾包含了使用層疊式圖像的建議和樣例。

定義層疊式圖像 link

The language used to define layered images consists of only a few statements, to introduce the layers. Here is an example which, while not making much practical sense, is technically correct and outlines the layeredimage syntax 腳本語言需要引入若干圖層,然後使用一些語句定義圖層上要顯示的圖像。 這裡是一個樣例,沒有什麼高超的靈感和技巧,只是在層疊式圖像上加上輪廓線。

layeredimage augustina:
    zoom 1.4
    at recolor_transform

    always:
        "augustina_base"

    attribute base2 default

    group outfit:
        attribute dress default:
            "augustina_dress"
        attribute uniform

    group face auto:
        pos (100, 100)
        attribute neutral default

label start:
    show augustina # 顯示裙子和neutral狀態表情
    aug "我喜歡這件裙子。"

    show augustina happy # 在auto組中自定生成定義
    aug "但我更喜歡……"

    show augustina uniform -happy # 用校服替代裙子,neutral替代happy表情
    aug "這件校服!"

這段腳本有點長,不過它很規整易讀。下面我們將展示如何簡化這段腳本。

首先, layeredimage 語句以精靈(sprite)的名字開頭。這條語句屬於Ren’Py腳本語言,運行在初始化階段。

層疊式圖像的語句塊(block)可能包含always、group和if語句。 group 語句可以包含屬性(attribute)。 alwaysif 語句必須帶可視組件(displayable),而同個組內的attribute語句可以任何選擇帶一個。 以上所有語句都可以帶特性(property)。

always 語句定義的圖層(layer)總是顯示,就像是精靈(sprite)的背景。

group 語句引入一組屬性(attribute),同一時間內只顯示某一項屬性(attribute)。 所以層疊式圖像其實只顯示角色的一套服裝、一對眼睛、一對眉毛和一張嘴。指定的屬性組特性(property)會傳入對應的attribute,並讓屬性組自動定義各個屬性。

attribute 語句引入的圖層,是僅在圖像需要對應屬性(attribute)時才會顯示。例如,“augustina_outfit_dress”僅在出現“dress”屬性時才會顯示。 如果使用了關鍵字 default ,在沒有其他有衝突的屬性出現時,就會默認顯示的屬性;在這個樣例中,只要不使用“wink”屬性,就顯示“augustina_eyes_open”屬性的圖像。

最後, if 語句添加了一個圖層,該圖層使用一條Python語句在不同的可視組件間選擇顯示的對象。Python語句總是重新計算,並顯示第一個滿足條件表達式為True的圖像。

特性(property)由特性名稱和一個簡單表達式構成,可以傳給每一個圖層。一些特性(property)會改變某些語句的功能。 如果含有某一個或多個 變換特性 會創建一個 Transform() 對象並wrap出顯示結果。 at後面的某個變換(transform)或者變換列表也會讓可視組件產生變化。例如,這裡的pos特性(property)創建了一個變換(transform),移動角色“mouth”圖像的位置。

最終圖像的尺寸等於能包圍所有圖層的方框尺寸。所以最好直接讓某一個圖層就是最終圖像的完整尺寸,這個尺寸能包含所有的圖層。 第一個圖層在最終圖像最後面,而最後的圖層在最終圖像最前面——在這個樣例中,眼鏡的圖層覆蓋在所有其他圖層上。 建議避免在包含的圖像中使用變換特性(property),比如 xcenterxalign, 因為圖像尺寸未知的情況下那些特性可能會出問題。

group和attribute語句在某個層疊式圖像中可以出現多次,所有指定屬性(attribute)的圖像都會顯示。

if 語句是個例外,所有Python表達式都會在初始化階段進行計算。

使用層疊式圖像 link

要使用這個層疊式圖像,而不是其他層疊式圖像,變數evil必須給定一個值,比如::

default evil = True

這樣,層疊式圖像就可以像其他圖像(image)一樣顯示了。幾乎可以肯定,至少需要給定角色的一套服裝——雖然Ren’Py不強制要求,圖像還是需要顯示一套的::

show augustina jeans

當精靈(sprite)顯示時,額外屬性(attribute)的要素只要不衝突就都會添加到圖像上。 (使用Ren’Py時廣泛存在的,匹配不到已定義圖像的情況,基本上不會發生在層疊式圖像上。) 所以,

show augustina wink

會啟用與wink屬性(attribute)關聯的圖層。我們可以可以關閉wink屬性,使用:

show augustina open

因為open狀態的眼睛與wink狀態的眼睛衝突。我們還可以直接移除wink屬性,使用:

show augustina -wink

這樣也會顯示open屬性,因為它是默認項。

層疊式圖像還可以使用在scene語句中。

自動化屬性 link

我們的第一個樣例中有不少重複,很多屬性(attribute)的名稱已經在可視組件中定義過。 為了幫助創作者節約冗餘的輸入時間,Ren’Py可以根據圖像名稱、組名稱和屬性名稱自動決定可視組件的名稱。 使用下劃線連接上述名稱就能實現這一點。

這樣做的時候,創作者還可以利用屬性(attribute)的另一項功能特性——第一行可以添加任意特性(property),並省略整個語句塊(block)。

之前的樣例可以這樣寫:

layeredimage augustina:

    always:
        "augustina_base"

    group outfit:
        attribute dress
        attribute jeans

    group eyes:
        attribute open default
        attribute wink

    group eyebrows:
        attribute normal default
        attribute oneup

    group mouth:
        pos (100, 100)
        attribute smile default
        attribute happy

    if evil:
        "augustina_glasses_evil"
    else:
        "augustina_glasses"

這個樣例跟之前那個是等價的(前提是使用的是相同名稱的可視組件)。例如,在outfit組中的dress屬性使用名為“augustina_outfit_dress”的可視組件。

還可以更進一步,讓一個組內自動定義屬性(attribute)。在定義組時使用關鍵字auto,就能讓這個組自動搜索正則表達式匹配到的圖像,並在屬性不存在的情況下自動定義組內圖像屬性。

attribute 一樣,特性(property)也可以放在組的第一行並省略語句塊。always語句中的可視組件和特性(property)也可以採用同樣的方式。

樣例的最終格式如下:

layeredimage augustina:

    always "augustina_base"

    group outfit auto

    group eyes auto:
        attribute open default

    group eyebrows auto:
        attribute normal default

    group mouth auto:
        pos (100, 100)
        attribute smile default

    if evil:
        "augustina_glasses_evil"
    else:
        "augustina_glasses"

這是定義同樣的圖像時,最精簡的方法。當每個組中需要添加更多屬性(attribute)時,自動定義功能節省的時間更多。 如果我們不需要默認屬性,還可以減少幾行腳本。那樣,每個組都只需要一行。

alwaysif 語句中不能省略可視組件的名稱,所以在這些地方使用的圖像名稱需要盡可能簡短。合理的圖片命名可以很輕鬆地定義出成千上萬種圖層的組合方式。

語句參考 link

需要注意,當層疊式圖像首次定義時,if 語句中的所有條件表達式都在初始化階段就會被計算。

layeredimage語句 link

layeredimage 語句在Ren’Py用作某個層疊式圖像定義的開頭語句。 該語句是Ren’Py腳本語言的一部分,可以在 init time 階段運行。 與 帶ATL語句塊的image語句 類似,layeredimage語句在開頭定義圖像名稱並開啟一個語句塊,後面的內容則大相徑庭。 圖像名稱中可以包含空格,類似於Ren’Py中的其他類型的圖像名稱。

定義layeredimage的語句塊中可能包含下列語句,以及一些特性(property)。

image_format

如果給定的圖像是一個字串,並且提供了image_format特性,就將 image_format 插入到圖像名,根據得到的名稱搜尋對應的圖片文件。 例如,“sprites/eileen/{image}.png”會在sprites子目錄下搜尋所有png圖片文件。 (auto組不使用image_format特性,因為auto組自動搜尋已定義的圖像對象而不是圖片文件。)

format_function

這是一個函數,在初始化階段執行,用於代替 layeredimage.format_function 函數,將圖像資訊格式化並傳入某個可視組件。

attribute_function

這是一個函數或可調用對象,用於調整最終顯示的圖像屬性(attribute)。 在圖像上應用一些屬性時,該函數會被調用。函數會返回對應圖層調整後的屬性的集合。 該函數可以用於計算負責的屬性依賴關係,或者隨機選擇屬性。詳見 選擇顯示屬性

at

應用於層疊式圖像的一個變換(transform)或變換的列表。

transform properties

如果存在變換特性,都會用於構建一個應用於可視組件的 Transform()

offer_screen

若為True,層疊式圖像將嘗試匹配整個界面,對其子組件調整位置和尺寸。 若為False,層疊式圖像將嘗試在更小的包圍矩形空間內放置各元素,每次顯示的層疊式圖像可能並不一樣。

若為None,即預設值,由配置項 config.layeredimage_offer_screen 決定。該配置項的預設值是True。

always語句 link

always 語句定義一個在層疊式圖像中始終顯示的圖像,該圖像不會與任何一個圖像屬性(attribute)做關聯。 always語句必須提供一個可視組件,當然也可以使用特性(property)。 這兩部分可以放在同一行,也可以放在一個語句塊(block)中。

always語句使用下列特性:

if_all

屬性(attribute)名稱的字串或字串列表。如果出現了這項特性,只有所有特定的屬性都出現時,才顯示圖層(layer)。

if_any

屬性(attribute)名稱的字串或字串列表。如果出現了這項特性,只要有任意特定的屬性出現時,就顯示圖層(layer)。

if_not

屬性(attribute)名稱的字串或字串列表。如果出現了這項特性,只有所有特定的屬性都不出現時,才顯示圖層(layer)。

transform properties

如果存在變換特性,都會用於構建一個應用於可視組件的 Transform()

at

應用於圖層的一個變換(transform)或變換的列表。

if語句 link

if 語句(或者更完整的if-elif-else語句)允許創作者設置一個或多個條件表達式。這些條件表達式會運行時進行計算。 每個條件表達式與某個可視組件關聯,第一個結果為True的條件表達式對應的圖像會被顯示。如果沒有條件表達式為True,else 語句對應的圖像就會顯示。

一個稍微複雜的 if 語句樣例如下:

if glasses == "evil":
    "augustina_glasses_evil"
elif glasses == "normal":
    "augustina_glasses"
elif glasses == "funky":
    "augustina_glasses_clown"
else:
    "augustina_nose_mark"

每個圖層必須給定一個可視組件。if語句還可以使用下列特性(property):

if_all

屬性(attribute)名稱的字串或字串列表。如果出現了這項特性,條件表達式檢查是否所有的命名屬性(attribute)都出現了。

if_any

屬性(attribute)名稱的字串或字串列表。如果出現了這項特性,條件表達式檢查是否任意的命名屬性(attribute)出現了。

if_not

屬性(attribute)名稱的字串或字串列表。如果出現了這項特性,條件表達式檢查是否所有的命名屬性(attribute)都未出現。

transform properties

如果存在變換特性,都會用於構建一個應用於圖層的 Transform()

at

應用於圖層的一個變換(transform)或變換的列表。

layeredimage 語句運行時, if 語句就會轉換為 ConditionSwitch()

predict_all 不為True時,應該避免修改if語句的條件表達式。因為層疊式圖像要嘛顯示要嘛即將顯示,修改if語句條件表達式會導致沒有預載入的圖像就被使用。 這種設計主要用於很少變化的角色自訂選項。

attribute語句 link

attribute 語句添加了一個可視組件,當使用給定的屬性(attribute)時顯示對應的圖像(image)。 比如,在前一個樣例中,調用 show augustina dress 會導致“augustina_dress”作為整個“augustina”的一部分並顯示。

attribute語句使用一個屬性(attribute)名稱。其也可以使用兩個關鍵字。 default 關鍵字表示,在沒有明確使用同組其他屬性的情況下作為預設的屬性。 null 關鍵字防止Ren’Py自動搜索對應屬性的可視組件, 對某些有使用條件 if_allif_anyif_notattribute_functionconfig.adjust_attributesconfig.default_attributes 的屬性時很有用。

相同的屬性名可以同時用在多個 attribute 分句中(auto 組自動定義的屬性會在後續另行說明), 在滿足條件時都顯示相應的可視組件(if_allif_anyif_not 特性可以調整最終結果)。

如果沒有直接給定可視組件(displayable),Ren’Py會根據層疊式圖像名稱、組(group)、組變種(group variant)和屬性(attribute),算出一個可視組件的名稱。 詳見 pattern 章節。

attribute語句使用下列特性(property):

if_all

屬性(attribute)名稱的字串或字串列表。如果出現了這項特性,只有所有特定的屬性都出現時,才顯示圖層(layer)。

if_any

屬性(attribute)名稱的字串或字串列表。如果出現了這項特性,只要有任意特定的屬性出現時,就顯示圖層(layer)。

if_not

屬性(attribute)名稱的字串或字串列表。如果出現了這項特性,只有所有特定的屬性都不出現時,才顯示圖層(layer)。

transform properties

如果存在變換特性,都會用於構建一個應用於可視組件的 Transform()

at

應用於層疊式圖像的一個變換(transform)或變換的列表。

if_* 從句會基於最終圖像的屬性列表進行嘗試,具體方式詳見 這裡, 但它 不會修改 屬性列表。

layeredimage eileen:
    attribute a
    attribute b default if_not "a"
    attribute c default if_not "b"

在上面的例子中,屬性 bc 總是 屬性列表的一部分(原因是他們的 default 從句)。 調用 show eileen a 時,屬性 a 根據腳本中寫的需求決定是否顯示,而屬性 b 不同,因為有 if_not 特性的約束。 但是,儘管對顯示結果不起作用,屬性 b 始終處於屬性列表中,即意味著屬性 c 始終對顯示結果不起作用。

group語句 link

group 語句可以將幾種屬性組成一個組(group),同組內各屬性互斥。 除非該組聲明為 multiple,否則同組內的屬性 ab 用在諸如 show eileen a b 之類地方會出現報錯。 正確的用法是,只使用屬性 a 自動隱藏 b,反之亦然。 另外,多個 attribute 從句傳入同一個屬性名是合法的。一般出現這種情況的原因是同一個屬性包含多個精靈(sprite),詳見本節結尾內容。

group 語句使用一個名稱(name)。該名稱並不常用,但可以用於生成組內屬性的默認名稱。 對 multiple 類型的組來說,名稱則真的沒什麼用處。

這個名稱後面可能跟著關鍵字 auto 。 如果在組內的任意屬性後面的確存在auto,且定義了組內的任意屬性後,Ren’Py會掃描自己的圖像列表以匹配組的正則表達式(詳見 below)。 with the specificity that in that case, a multiple group’s name is part if the pattern, and that the format_function passed to the layeredimage is ignored.

找到的所有圖像,如果匹配不到已定義的屬性,就會自動在組內添加屬性,就像使用 attribute 語句定義group一樣。 詳見 樣例 章節的實際樣例。

後面還可以跟關鍵字 multiple 。出現時該關鍵字時,可以同時選中某個組的多個成員。 這個功能可以用於某個自動定義多個屬性的組,以便同時對組內成員同時設置相同的特性(property)或屬性(attribute),前提是各個屬性間都不存在互斥關係。 但是與關鍵字 default 定義的屬性會有衝突。 注意,mutiple 類型的組與普通的組差別很大。很多對普通組來說都沒有問題的特性,都不適用於 multiple 類型的組。

在以上這些可選的關鍵字後面,group語句第一行就可以聲明相應的特性(property),也能以包含特性和屬性的語句塊形式跟著group後面。

group語句可以使用 attribute 語句中設置的特性——即 if_anyat 等等。 應用到整個組的特性會分別應用到組內的各個屬性(attribute),但會被組內屬性自帶的特性所覆蓋。 此外,有兩個特性是專門用於組的:

variant

這應該是一個字串。如果存在這項特性,它會添加一個元素。 該元素最終會成為自動生成圖像名的一部分,以及搜索自動定義屬性的正則表達式的一部分,前提是定義在 auto 組中。

prefix

給定的prefix前綴會加一個下劃線,並添加到手動或自動定義的屬性名稱前面。如果 prefix 為“leftarm”,遇到的屬性名為“hip”,定義的最終屬性名就是“leftarm_hip”,顯示圖像的完整腳本為 show eileen leftarm_hip

group語句使用的特性(property)與 attribute 語句相同。應用於組(group)的特性會傳給組內的屬性(attribute),除非某項屬性自身重寫了同名的屬性。

定義在同一個層疊式圖像中一些同名的 group 語句塊,會被看作同一個組的不同部分。例如:

layeredimage eileen sitting:
    attribute base default
    group arms variant "behind":
        attribute on_hips
        attribute on_knees
        attribute mixed
    attribute table default
    group arms variant "infront":
        attribute on_table default
        attribute holding_margarita
        attribute mixed

在上面的例子中,eileen_sitting_arms_behind_mixed.png 包含在桌子後面的左手, eileen_sitting_arms_infront_mixed.png 包含在桌子前面的右手。 當調用 show eileen sitting mixed 時,兩個圖像同時顯示,分別在桌子前後。 例子中的 on_hips 屬性與 on_table 屬性互斥,因為它倆沒有同一段代碼塊中聲明,卻屬於同一個組。

範式和格式函數 link

不明確指定圖像屬性的範式,由下列部分構成:

  • 層疊式圖像名稱,空格使用下劃線替換。

  • 組(group)名稱,前提該組不是 multiple 類型。

  • 變種(variant)名稱。

  • 屬性(attribute)名稱。

各部分都使用下劃線連接。例如,我們有一個名為“augustina work”的圖層圖像,名為“eyes”的組, 那麼根據範式 augustina_work_eyes_attribute 匹配圖像。 如果帶一個 bluevariant ,就會根據範式 augustina_work_eyes_blue_attribute 進行匹配。 在下例中:

layeredimage augustina work:
    group eyes variant "blue":
        attribute closed

圖像屬性(attribute)連結的圖像為 “augustina_work_eyes_blue_closed”。 處理時對應的圖片檔案名為 augustina_work_eyes_blue_closed.png。 當然,這個例子中也可以使用 image語句 顯式定義。

如果想要一個 multiple 組的名稱也包含在範式中,可以使用如下語法:

group addons multiple variant "addons"

可以使用 格式函數 修改所有範式的結果:layeredimage.format_function() 就是一種格式函數的實現。 請參考入參列表,需要的情況下可以用自己實現的 格式函數 替換它。

layeredimage.format_function(what, name, group, variant, attribute, image, image_format, **kwargs) link

調用該函數可以將各種屬性和情況的資訊串聯起來,並返回一個可視組件名。可以被創作者定義的函數替換,但增加的其他未知入參會被忽略。

what

一個字串,描述格式內容,可用於各類報錯資訊中。

name

層疊式圖像的名稱。

group

某個屬性的組(group)。未指定或其屬於某種情況的一部分時,可以為None。

variant

組(group)的變種入參,可以是None。

attribute

屬性自身。

image

一個可視組件或一個字串。

image_format

LayeredImage對象的 image_format 參數。

如果 image 為None,那麼 namegroup (若不是None)、variant (若不是None)和 attribute 使用下劃線連接得到的圖像會創建為 image,並返回圖像名稱對應的字串。

如果 images 是一個字串,並且 image_format 不是None,image 轉為字串格式並獲取最終的可視組件。

假設 name 的值是“eileen”,group 的值是“expression”,attribute 的值是“happy”,image 的結果就是“eileen_expression_happy”。 假設 image_format 的值是“images/{image}.png”,最終Ren’Py找到的圖片文件就是“images/eileen_expression_happy.png”。 但要注意不帶format入參時,上面兩種方法找到的都是同一個圖像。

層疊式圖像代理 link

有時候,為了在多個地方使用同一個層疊式圖像,需要給層疊式圖像生成一個代理對象(proxy)。 這樣設計的原因之一是,各處可能使用同一個精靈(sprite)的不同圖像尺寸;另一個原因則是,可以使用層疊式圖像作為對話框頭像(side image)。

LayeredImagePorxy() 對象實現了這個功能,為層疊式圖像創建出可以在各處使用的副本。例如:

image dupe = LayeredImageProxy("augustina")

會創建一個可以獨立顯示的圖像副本。創建時也可以使用變換作為入參,直接指定剪裁和位置資訊用作頭像:

image side augustina = LayeredImageProxy("augustina", Transform(crop=(0, 0, 362, 362), xoffset=-80))

比較以下兩種不同的圖像定義:

image sepia_augustina_one = Transform("augustina", matrixcolor=SepiaMatrix())
image sepia_augustina_two = LayeredImageProxy("augustina", Transform(matrixcolor=SepiaMatrix()))

sepia_augustina_one 是層疊式圖像“augustina” 原生版本 一個舊照片風格版本,也就是說不需要提供任何屬性(attribute)就可以顯示。 而 sepia_augustina_two 則跟“augustina”一樣可以帶入各種屬性,並同時保持舊照片的風格。 實現方法如下:

show augustina happy eyes_blue dress

然後:

show sepia_augustina_one happy eyes_blue dress
# 無效。因為Transform對象不接受屬性(attribute)

show sepia_augustina_two happy eyes_blue dress
# 有效。顯示“augustina happy eyes_blue dress”的舊照片風格。
class LayeredImageProxy(name, transform=None) link

該類是一個類圖像對象,生成向某個層疊式圖像傳遞屬性的代理。

name

一個字串,表示需要代理的層疊式圖像名稱。

transform

若給定,應是一個變換或變換列表,會應用到代理的圖像上。

選擇顯示屬性 link

有多個因素會影響 show語句 最終顯示結果。 為了明確說明各因素的作用順序,本段內容詳細說明了從 show 指令開始到螢幕最終顯示的完整流程。

  • show 語句根據後面跟隨的圖像標籤(image tag),初始化屬性(attribute)的集合。

  • 如果 config.adjust_attributes 成功匹配到圖像標籤並調用了相關函數,函數將返回一個處理後的屬性集合。 此集合將替代上一步的屬性集合。

  • 如果配置項 config.default_attribute_callbacks 中定義了回調函數,當該函數的觸發條件達成時, 調用函數並將執行結果的屬性加入到上一步的集合中。

上述步驟並不僅限適用於層疊式圖像,Ren’Py對所有需要顯示的圖像和層疊式圖像都要經過前置處理。 因此,圖像屬性集使用下面的步驟必須能找到一個並且只有一個有明確定義的圖像(或層疊式圖像,或Live2D)。 詳見 show語句章節

  • show語句中包含的屬性會與層疊式圖像定義時的屬性合併,通過上述前兩步提出一些並保留剩下的。 如果發現無法識別的屬性則會報錯。無報錯的情況下,Ren’Py根據存在的屬性與圖像標籤做匹配關聯。 這步計算會考察部分屬性與圖像標籤的不相容限制。某些實際的不相容是由非multiple類型的組中的同名屬性引起,使用 if_any/if_all/if_not clauses 分句就不會出現這種問題。 這也是為什麼明明在從句中沒有某個屬性,Ren’Py卻認為該屬性應該啟用並顯示出來的原因,往往在 if_x 從句條件不滿足的情況下容易出現類似問題。 (譯者註:這段原文使用了很多複雜長句,可能翻譯有誤。)

  • 如果某個 attribute_function 函數應用到層疊式圖像,將使用經過前述步驟篩選後的屬性作為入參調用該函數。 該函數可能會返回一個略有差別的屬性集。

  • 再來一次不相容檢查,此次是全量檢查。 這是最後一步處理,剩餘的屬性決定最終顯示效果。

幾點建議 link

在圖像名稱中使用下劃線。

默認情況下,Ren’Py中的層疊式圖像使用下劃線作為圖像名各段的分隔符號。 可以在圖像中臨時使用空格,不過後面很可能會導致問題和故障。

Ren’Py的一條規則是,如果創作者想要顯示一個圖像,那個圖像有一個同名圖像正在顯示,那麼就顯示那個同名圖像。 這個規則也貫徹在層疊式圖像中。創作者可以直接定義並顯示圖層,不過也會導致奇怪的問題,比如一雙眼睛懸浮在空中。

每個圖像使用的圖像標籤(tag)都與主圖像不同的話,就不存在這個問題了。

不需要剪裁圖層。

Ren’Py讀取圖像並載入到RAM之前會進行最佳化,將所有圖像剪裁到非透明像素的包圍框(bounding box)。 因此,在圖像被正確預載入的前提下,創作者剪裁圖像並不會提升性能或減少圖像尺寸。

層疊式圖像不應使用運行過程中會發生變化的數據

注意,定義層疊式圖像之後,在 layeredimage 語句塊中的所有表達式都會在初始化階段計算,因此需要提前考慮各個 if 語句中的異常情況。 這與ATL的變換不同,也與 config.adjust_attributesconfig.default_attributesattribute_function 配置不同。 但與 format_function 類似,都只在層疊式圖像定義後調用。

選擇合適的語法

如果創作者想要一個總是可見的精靈(sprite),可以使用 always 從句或 attribute x default 語法。 always 語句要求創作者顯式提供可視組件(使用 範式 自動生成的屬性不行), 而 attribute 語句會要求“x”對應的屬性名在層疊式圖像中總是處於啟用狀態。

如果創作者想要在使用 show 語句時向層疊式圖像傳入圖像屬性來決定具體顯示的內容, 例如使用 show eileen happy 更換 show eileen jeans,則要在 group 語句塊中使用 attribute 語句(或在 auto 組中隱式)將兩個標籤設置為互斥關係。

如果創作者想要根據某個Python變數或條件表達式決定顯示內容,則使用 if 語句。

如果創作者“即要又要”(比如:使用 show eileen ribbon 顯示藍色或紅色緞帶,緞帶顏色由某個變數決定;是否顯示緞帶又由 ribbon 屬性控制),可以將各種屬性組織為不同“版本”,然後使用 config.adjust_attributes 配置的函數處理。

樣例 link

範式和自動分組

假設下列文件已經存在,並放置到 images/ 目錄(或其子目錄),使用以下代碼:

francis_base.png
francis_face_neutral.png
francis_face_angry.png
francis_face_happy.png
francis_face_very_happy.png
francis_face annoyed.png
francis_supersad.png
layeredimage francis:
    attribute base default
    group face auto
        attribute neutral default
    attribute supersad:
        Solid("#00c3", xysize=(100, 100))

層疊式圖像 francis 會定義一個(預設的) base 屬性(attribute),並使用 範式 與(自動定義的)圖像“francis_base”做關聯: 使用下劃線將圖像名(“francis”)、組名稱(此例中沒有)、變種命中(此例中沒有)和屬性名按順序連接構成圖像名。

接著,包含“face”並且符合範式的屬性都歸入到 face 組,即 neutral 屬性會與“francis_face_neutral”圖像關聯,“neutral”是該組中的一個屬性。

在所有顯式出現的屬性都對照對應的圖像後,face 組就成了一個 auto 類型的組,所有存在的圖像(無論是否自動定義)都會通過範式進行匹配搜索。 此例中,使用範式搜索後會找到3個圖像:“francis_face_angry”、“francis_face_happy”和“francis_face_very_happy”。 分別對應 angryhappyvery_happy 三種屬性。 但是不存在 anoyed 屬性,因為“francis_face annoyed”中有一個空格,不符合使用下劃線連接屬性的範式。

最後定義了 supersad 屬性,因為可視組件是顯式聲明的,不需要通過範式搜索。 roup, so they end up not being used in the francis layeredimage. 圖像“francis_supersad”和“francis_face annoyed”會使用Ren’Py原本的 規則 根據圖片檔案名生成圖像名, 並且無法匹配任何一個屬性或auto組,因為無法用於 francis 層疊式圖像。

可見使用範式關聯圖像與屬性,然後使用auto組能有效減少代碼量。 同一個層疊式圖像值需要13行程式碼就可以定義完成。 這種語法可以有效應對sprite圖集數量的幾何式增長——比如此例中添加任何關於face屬性的圖片不需要修改任何代碼。

Dynamism in attributes 屬性的動態機制

下面的例子中,定義一些屬性,會根據某些變數發生變化:

layeredimage eileen:
    attribute base default
    group outfit auto
    group ribbon prefix "ribbon":
        attribute red
        attribute blue

default eileen_ribbon_color = "red"

init python:
    def eileen_adjuster(names):
        atts = set(names[1:])
        if "ribbon" in atts:
            atts.remove("ribbon")
            atts.add("ribbon_" + eileen_ribbon_color)
        return names[0], *atts

define config.adjust_attributes["eileen"] = eileen_adjuster