程式語言基礎 link

在我們詳細介紹Ren’Py的程式語言之前,我們必須首先介紹一下Ren’Py腳本的結構。這包括:腳本文件如何分割為語句塊(block),而語句塊(block)是由多行腳本構成;各行腳本如何分割為基本元素(element),並構成語句(statement)。

文件 link

Ren’Py遊戲腳本由 game/ 目錄下眾多副檔名為 .rpy 的文件組成。Ren’Py會依次檢查每一個文件(按照他們路徑的Unicode碼順序),並把文件內容用作腳本。

總之,把一份腳本打散成多個文件,與一份腳本保存在一個大文件中,兩種方法是等效的。主控流程可以在文件之間透過調用 腳本標籤 跳轉。把一份腳本切分為多個文件跟創作者個人風格有關——有些遊戲製作者喜歡使用小文件(像一個事件一個文件,或者每一天一個文件),而其他製作者傾向於使用一個完整的大腳本文件。

為了提高載入速度,Ren’Py啟動時會把 .rpy 文件編譯為 .rpyc 文件。當一個 .rpy 文件發生變更時, .rpyc 只有重啟Ren’Py進程才會更新。另外,如果一個 .rpyc 文件並沒有對應的 .rpy 源文件,這個 .rpyc 文件依然會被使用。當 .rpy 文件已經刪除而 .rpyc 文件沒有刪除的情況下,可能會導致運行時出現問題。

檔案名必須以字母或者數字開頭,並且開頭不能用“00”,因為“00”開頭的文件是Ren’Py內部使用的。

根目錄 link

根目錄是包含構建該遊戲所有文件的目錄(儘管有些文件並不參與遊戲構建)。其他內容參見 構建發行版 。像README(須知)類文件應該放在根目錄中。

創建新遊戲時,根目錄會被創建在“項目目錄(Projects Directory)”中。“項目目錄”可以在啟動器中進行設置。 例如,如果項目目錄名為 renpygames,新建遊戲名為“HelloWorld”,那麼根目錄將會是 renpygames/HelloWorld

game目錄 link

game目錄是在根目錄下一個名為“game”的目錄。例如,根目錄是 renpygames/HelloWorld,game目錄就是 renpygames/HelloWorld/game

game目錄包含了遊戲中用到的所有文件。對於game目錄包含的所有子目錄: Ren’Py會搜索所有 .rpy.rpyc 文件,合併為遊戲腳本; Ren’Py會搜索 .rpa 歸檔文件,自動在遊戲中使用。 當Ren’Py遇到指定路徑的文件時,該路徑都是game目錄下的相對路徑(但 config.searchpath 可以修改這個默認路徑)。

注釋(comment) link

Ren’Py腳本文件可能會包含一些注釋(comment)。每條注釋都以記號 (#) 開頭,直到該行文本結束。不過有一種情況例外,注釋(comment)不能用在某個字串的一部分。

# 這是一條注釋。
show black # 這也是一條注釋。

"# 這不是一條注釋因為它是一個字串的一部分。"

Ren’Py忽略注釋, 所以腳本處理過程中那段注釋如同不存在。

邏輯行(logical line) link

一個腳本文件可以被切割為一些邏輯行(logical line)。一條logical line(邏輯行)往往在文件中頂格起始,換行結束,有一些例外:

  • 該行結尾是反斜槓 (\)。

  • 該行包含幾個開括號字元(({[),而該行沒有匹配到對應的閉括號字元 ()}])。

  • 任何 字串中出現換行,包括單引號中的字串。這條規則與Python的規範不同。

一個邏輯行結束後,下一行就是另一個邏輯行的開始。

Ren’Py程式語言中大多數語句都只有一個邏輯行。

"這是一條邏輯行"

"因為這條邏輯行包含一個字串,
 所以換行也依然是同一條邏輯行"

$ a = [ "由於括號的存在,這也是一條",
        "可以突破換行的邏輯行。" ]

空的邏輯行會被忽略。

縮進和語句塊(block) link

縮進 是我們指代Ren’Py語句每個邏輯行開頭的空間。在Ren’Py中,縮進必須使用空格。

縮進被用來將一些語句分組形成語句塊(block)。一個語句塊是一組邏輯行,通常也是一組語句。將一個文件分割為語句塊的原則是:

  • 一個語句塊在文件開頭被打開載入。

  • 在某個邏輯行使用了比上一行更多縮進量時,就表示開始了一個新語句塊。

  • 在一個語句塊中所有的邏輯行必須保持同樣的縮進量。

  • 當一個非空邏輯行的縮進量比其他行更少,表示上一個語句塊的結束。

對Ren’Py來說,縮進非常重要。錯誤的縮進量能引起語法或者邏輯錯誤。同時,縮進的使用表明了語句塊結構,比使用其他標識的語言簡單。

"這是一個語句,後面跟著的是if語句,那是一個語句塊的一部分。"

if True:

    "這個語句是新語句塊的一部分。"

    "這個語句也是新語句塊的一部分。"

"這個語句又是第一個語句塊的一部分了。"

語句元素 link

Ren’Py語句由一些基本部分組成。

關鍵字(keyword)

關鍵字是一個英文單字,必須在遊戲腳本中合法出現。關鍵字通常用於出現在語句和屬性中。

關鍵字主要用於引入語句(statement)和特性(property)。

名稱(name)

名稱以一個字母或者下劃線開頭,之後跟隨著0個或者若干個字母、數字或者下劃線。出於我們的需求,在“U+00a0”和“U+fffd”之間的unicode字元都被認為是字母。

Warning

以一個下劃線 (_) 開頭的名稱都是Ren’Py內部預留的,除非文件另有說明。

以兩個下劃線 (__) 開頭但不以兩個下劃線結尾的名稱,會被轉為那個名稱的特定文件類型版本。

圖像名(image name)

圖像名(image name) 由一個或多個部分構成,以空格分隔。 圖像名的第一部分稱作 圖像標籤(image tag) 。圖像名後面的部分都是 圖像屬性(image attributes) 。圖像的各部分都是由字元、數字和下劃線組成的字串。

例如,一個圖像名為 mary beach night happy 。圖像標籤(tag)就是 mary ,而圖像屬性(attribute)就是 beachnighthappy

單字 atasbehindonlayerwithzorder 都不能用於圖像名中。

字串(string)

字串以一個引用字元(”、’或者`)開頭,包含一些字元,並以同樣的引用字元結尾。

反斜槓(\)用於字元轉義,一些特殊字元,比如%(需要寫作\%)、[(需要寫作\[)、{(需要寫作\{)。它還用於包含下一行,此時使用\n串。

在Ren’Py字串中,連續多個空格會被壓縮為一個空格字元,除非某個空格前面有一個反斜行。

'Strings can\'t contain their delimiter, unless you escape it.'

"There will be a space between the two following
 words."

"There will be a line break between\nthese."

"And there will be three spaces between\ \ \ these."

可以使用前綴 r,用法與Python語法規則一樣。其他前綴則不能用,比如 ubf。 連續3個引號不能在普通字串中使用,其實際用途請參考 獨白模式

Note

這條規則僅對 直接 寫在Ren’Py腳本中的字串有效,比如 say語句遊戲內菜單 中的字串。 在 python語句 或表達式中的字串與Python語法一樣。

簡單表達式(simple expression)

簡單表達式就是一個Python表達式,用於在Ren’Py腳本中運行Python。一個簡單表達式使用以下類型作開頭:

  • 一個變數名。

  • 一個字串。

  • 一個數字。

  • 圓括號中包含的任意表達式。

其後可以接續任意數量的:

  • 名稱前的一個英文句號字元。

  • 圓括號內的Python表達式。

舉例,3(3 + 4)foo.barfoo(42) 都是簡單表達式。但 3 + 4 則不是“簡單”表達式,因為該表達式是一個算式字串且沒有使用圓括號。

python表達式

python表達式是指任意的、可能不包含分號的python表達式。這些表達式常用於 ifwhile 語句中,處理對應的情況。

通用語句語法 link

大多數Ren’Py語句使用通用的語法。而 say語句 語句是個例外,其使用開頭的某個關鍵字標識say語句。如果語句中包含變數的話,會跟在該關鍵字後面。

變數後面會跟著一個或多個特性(property)。特性(property)可以使用任意順序排列,每個屬性均只會出現一次。一項特性(property)以一個關鍵字開頭。對大多數的特性(property)來說,屬性名字會跟之前出現的語法元素(element)之一保持一致。

若該語句包含一個語句塊(block),那行語句會以冒號(:)結尾。否則的話,以換行結尾。

python表達式語法 link

Note

本段內容現在可以先跳過不看。當你覺得無法理解某個樣例,或者你覺得需要理解更深層次的運行機制時,可以再返回來看本段內容。

Ren’Py的很多地方都會用到python表達式。例如,定義一個新角色就意味著調用charactre(角色)的函數。由於python表達式功能十分強大,只是用其很小部分就足以實現一個基本的Ren’Py遊戲。

這是一個python表達式的概要。

整數(integer)

整數是一個不帶小數點的數字。 342 就都是整數。

浮點數(float)

浮點數是一個帶小數點的數字。 .57.9.0 就都是浮點數。

字串(string)

python字串以英文符號的雙引號(“)或單引號(‘)開頭,並使用同樣的符號結尾。斜槓(\)被用來轉義換行符,並可以使用特殊字元(\n)表示換行。與Ren’Py字串不同,python字串不能分多行。

True, False, None

這是三個特殊的值。 True 表示真值, False 表示假值。 None 表示空值。

元組(tuple)

元組(tuple)是一種容器,其元素(item)數量非常重要。例如,我們可以使用一個2維元組(也被稱作pair)來裝寬度和高度數據,或者使用一個4維元組(包含x、y、寬度和高度)來裝一個三角形的數據。

元組(tuple)開頭有一個左括號 ( ,可以由0個或若干個逗號分隔的python表達式,並以一個右括號 ) 結束。比較特殊的是,只有一個元素(item)的元組中,元素後面必須帶一個逗號。各種例子如下:

()
(1,)
(1, "#555")
(32, 24, 200, 100)
列表(list)

列表(list)是一種容器,用來裝各種類型的數據。列表以 [ 開頭,包含一系列逗號分隔的表達式,並以 ] 結束。舉例如下

[]
[1]
[1, 2]
[1, 2, 3]
變數(variable)

python表達式中可以使用變數。通過 define語句 語句或者 default語句 語句定義變數,數值可以存放在變數中。 變數名的規則與 語句元素 中的 name 相同。例如:

playername
love_love_points
trebuchet2_range

以下劃線“_”開頭的變數是預留給Ren’Py專用,創作者不應使用。

欄位(field)訪問

python模組(module)和對象(object)都有欄位(field)的概念,可以在欄位(field)後接一個英文句號“.”和一個表達式(通常是一個變數),實現對欄位的訪問。例如

config.screen_width

實現了對config中screen_width欄位的訪問。

調用(call)

python表達式可以調用一個函數並獲得一個返回值。函數調用以一個表達式開頭(通常是函數名),後面跟著一對圓括號,括號內有一系列參數。參數列表開頭是個python表達式,也是固定位置參數。後面則是關鍵字參數,由參數名、等號和表達式組成。下面是一個例子:

Character("Eileen", type=adv, color="#0f0")

我們調用了 Character() 函數。其給定了一個固定位置參數,也就是字串“Eileen”。其給定了兩個關鍵字參數: type 被賦值為 adv ,而 color 被複製為字串 "#0f0"

除了函數之外,其他可以調用的對象都統稱為 callables

閱讀此份文件時,你可能會看到這樣的函數聲明:

Sample(name, delay, position=(0, 0), **properties) link

這個樣例函數並不真正在Ren’Py中使用,而只存在這份文件中。

這個函數:

  • 函數名為“Sample”

  • 有兩個固定位置參數,分別是name和delay。真實情況下,在文件中應該有參數的詳細說明。

  • 有一個關鍵字參數position,其預設值為(0, 0)。

由於函數結尾是 **properties,這意味著其可以使用 樣式特性 作為額外的關鍵字參數。 其他的特殊形式結尾還有 *args,表示其可以使用任意數量的固定位置參數,而 **kwargs 表示在文件中已詳細描述過的關鍵字參數。

若在函數簽名中出現了 / 符號,表示該符號 之前 的參數都是固定位置參數,不可以用關鍵字參數。 若在函數簽名中出現了 * 符號,表示該符號 之後 的參數都是關鍵字參數,只有使用 name=value 語法傳參。

Python的強大,遠非我們這份文件所能完全展現。若希望學習python的更多細節,我們推薦Python入門教學, python.org 。由於我們認為對於Ren’Py來說,更深一層的python知識不是必要的,了解python語句和表達式通常就足夠了。