程式語言基礎 link
在我們詳細介紹Ren’Py的程式語言之前,我們必須首先介紹一下Ren’Py腳本的結構。這包括:腳本文件如何分割為語句塊(block),而語句塊(block)是由多行腳本構成;各行腳本如何分割為基本元素(element),並構成語句(statement)。
文件 link
Ren’Py遊戲腳本由game目錄下眾多副檔名為 .rpy
的文件組成。Ren’Py會依次檢查每一個文件(按照他們路徑的Unicode碼順序),並把文件內容用作腳本。
總之,把一份腳本打散成多個文件,與一份腳本保存在一個大文件中,兩種方法是等效的。主控流程可以在文件之間透過調用腳本標籤(label)跳轉。把一份腳本切分為多個文件跟創作者個人風格有關——有些遊戲製作者喜歡使用小文件(像一個事件一個文件,或者每一天一個文件),而其他製作者傾向於使用一個完整的大腳本文件。
為了提高載入速度,Ren’Py啟動時會把 .rpy
文件編譯為 .rpyc
文件。當一個 .rpy
文件發生變更時, .rpyc
只有重啟Ren’Py進程才會更新。另外,如果一個 .rpyc
文件並沒有對應的 .rpy
源文件,這個 .rpyc
文件依然會被使用。當 .rpy
文件已經刪除而 .rpyc
文件沒有刪除的情況下,可能會導致運行時出現問題。
檔案名必須以字母或者數字開頭,並且開頭不能用“00”,因為“00”開頭的文件是Ren’Py內部使用的。
基礎目錄 link
基礎目錄是包含構建該遊戲所有文件的目錄。(這可能也包含一些跟遊戲無關的文件。)像README(須知)類文件應該放在基礎目錄中。
基礎目錄會被創建在Ren’Py目錄下,以創作者遊戲的名稱命名。例如,如果創作者的Ren’Py目錄名為renpy-6.11.2,遊戲名為“HelloWorld”,創作者的基礎目錄就是renpy-6.11.2/HelloWorld。
遊戲目錄 link
遊戲目錄很可能是在基礎目錄下一個名為“game”的目錄。例如,如果創作者的基礎目錄是renpy-6.11.2/HelloWorld,創作者的遊戲目錄就會是renpy-6.11.2/HelloWorld/game。
Ren’Py會按以下順序依次搜索所有目錄:
根據可執行檔案名,去掉後綴名。比如,如果可執行文件被命名為moonlight.exe,Ren’Py將會尋找基礎目錄下名為“moonlight”的目錄。
根據可執行檔案名,去掉後綴名,再去掉下劃線“_”及其前綴。比如,如果可執行文件是moonlight_en.exe,Ren’Py會尋找名為“en”的目錄。
按照“game”、“data”、“launcher”的順序。
啟動器(launcher)只會識別“game”和“data”目錄。
遊戲目錄包含了遊戲內使用的所有文件。其自身及其所有子目錄下,會被掃描出所有 .rpy 和 .rpyc 文件,並拼裝組合成整個遊戲的腳本。 .rpa 文件也會被掃描到,這些文件會被遊戲自動使用。當遊戲指定某個需要載入的文件路徑時,文件路徑會與遊戲目錄關聯。(注意config.searchpath可以控制並修改這一點。)
注釋(comment) link
Ren’Py腳本文件可能會包含一些注釋(comment)。每條注釋都以記號(‘#’)開頭,直到該行文本結束。不過有一種情況例外,注釋(comment)不能用在某個字串的一部分。
# 這是一條注釋。
show black # 這也是一條注釋。
"# 這不是一條注釋因為它是一個字串的一部分。"
Ren’Py忽略注釋, 所以腳本處理過程中那段注釋如同不存在。
邏輯行(logical line) link
一個腳本文件可以被切割為一些邏輯行(logical line)。一條logical line(邏輯行)往往在文件中頂格起始,換行結束,有一些例外:
該行結尾是反斜槓(’')。
該行包含幾個開括號字元(‘(’, ‘{’, or ‘[‘),而該行沒有匹配到對應的閉括號字元(‘)’, ‘}’, or ‘]’。
一個包含換行的字串中。
一個邏輯行結束後,下一行就是另一個邏輯行的開始。
Ren’Py程式語言中大多數語句都只由一個邏輯行,有一些語句則包含多行。
"這是一條邏輯行"
"因為這條邏輯行包含一個字串,
所以換行也依然是同一條邏輯行。"
$ a = [ "由於括號的存在,這也是一條",
"可以突破換行的邏輯行。" ]
空的邏輯行會被忽略。
縮進和語句塊(block) link
縮進 是我們指代Ren’Py語句每個邏輯行開頭的空間。在Ren’Py中,縮進必須使用空格。
縮進被用來將一些語句分組形成語句塊(block)。一個語句塊是一組邏輯行,通常也是一組語句。將一個文件分割為語句塊的原則是:
一個語句塊在文件開頭被打開載入。
在某個邏輯行使用了比上一行更多縮進量時,就表示開始了一個新語句塊。
在一個語句塊中所有的邏輯行必須保持同樣的縮進量。
當一個邏輯行的縮進量比其他行更少,表示上一個語句塊的結束。
對Ren’Py來說,縮進非常重要,甚至縮進量能引起語法或者邏輯錯誤。同時,縮進的使用表明了塊結構,使我們不需要瀏覽整個腳本文件就能識別出塊結構。
"這是一個語句,後面跟著的是if語句,那是一個語句塊的一部分。"
if True:
"這個語句是新語句塊的一部分。"
"這個語句也是新語句塊的一部分。"
"這個語句又是第一個語句塊的一部分了。"
語句元素 link
Ren’Py語句由一些基本部分組成。
- 關鍵字(keyword)
關鍵字是一個英文單字,必須在遊戲腳本中合法出現。關鍵字通常用於出現在語句和屬性中。
名字以一個下劃線(_)開頭的關鍵字僅限Ren’Py內部使用,除非文件另有說明。當一個關鍵字名字開頭是兩條下劃線__但結尾沒有兩條下劃線__,在使用時它會改變為特定文件版本號。
- 名稱(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)就是beach
、night
和happy
。- 字串(string)
字串以一個引用字元(”、’或者`)開頭,包含幾串文字,並以同樣的引用字元結尾。
反斜槓(\)用於字元轉義,一些特殊字元,比如%(需要寫作\%)、[(需要寫作\[)、{(需要寫作\{)。它還用於包含下一行,此時使用\n串。
在Ren’Py字串中,連續多個空格會被壓縮為一個空格字元,除非某個空格前面有一個反斜行。
'Strings can\'t contain their delimiter, unless you escape it.'
- 簡單表達式(simple expression)
簡單表達式就是一個Python表達式,用於在Ren’Py腳本中運行Python。一個簡單表達式使用以下類型作開頭:
一個變數名。
一個字串。
一個數字。
圓括號中包含的任意表達式。
其後可以接續任意數量的:
名稱前的一個英文句號字元。
圓括號內的Python表達式。
舉例,
3
、(3 + 4)
、foo.bar
和foo(42)
都是簡單表達式。但3 + 4
則不是“簡單”表達式,因為該表達式是一個算式字串且沒有使用圓括號。- at列表(At List)
at列表由一系列簡單表達式組成,使用英文逗號字元分隔。
- python表達式
python表達式是指任意的、可能不包含分號的python表達式。這些表達式常用於if和while語句中,處理對應的情況。
通用語句語法 link
大多數Ren’Py語句使用通用的語法。而say語句是個例外,其使用開頭的某個關鍵字標識say語句。如果語句中包含變數的話,會跟在該關鍵字後面。
變數後面會跟著一個或多個特性(property)。特性(property)可以使用任意順序排列,每個屬性均只會出現一次。一項特性(property)以一個關鍵字開頭。對大多數的特性(property)來說,屬性名字會跟之前出現的語法元素(element)之一保持一致。
若該語句包含一個語句塊(block),那行語句會以冒號(:)結尾。否則的話,以換行結尾。
python表達式語法 link
Note
本段內容現在可以先跳過不看。當你覺得無法理解某個樣例,或者你覺得需要理解更深層次的運行機制時,可以再返回來看本段內容。
Ren’Py的很多地方都會用到python表達式。例如,定義一個新角色就意味著調用charactre(角色)的函數。由於python表達式功能十分強大,只是用其很小部分就足以實現一個基本的Ren’Py遊戲。
這是一個python表達式的概要。
- 整數(integer)
整數是一個不帶小數點的數字。
3
和42
就都是整數。- 浮點數(float)
浮點數是一個帶小數點的數字。
.5
、7.
和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表達式中允許使用變數。透過定義語句或者python語句產生的數值可以存放在變數中。變數以字母或者下劃線開頭,後接0個或若干個字母、數據或下劃線。舉例如下:
name 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")
我們調用了Charactre函數。其給定了一個固定位置參數,也就是字串“Eileen”。其給定了兩個關鍵字參數:
type
被賦值為adv
,而color
被複製為字串“#0f0”。構造器是一類專門用於返回一個新對象的函數,且會被使用相同的方式調用。
閱讀此份文件時,你可能會看到這樣的函數聲明:
- Sample(name, delay, position=(0, 0), **properties) link
這個樣例函數並不真正在Ren’Py中使用,而只存在這份文件中。
這個函數:
函數名為“Sample”
有兩個固定位置參數,分別是name和delay。真實情況下,在文件中應該有參數的詳細說明。
有一個關鍵字參數position,其預設值為(0, 0)。
由於函數結尾是 **properties, 這意味著其可以使用 樣式特性 作為額外的關鍵字參數。 其他的特殊形式結尾還有*args,表示其可以使用任意數量的固定位置參數,而**kwargs表示在文件中已詳細描述過的固定位置參數。
Python的強大,遠非我們這份文件所能完全展現。若希望學習python的更多細節,我們推薦Python入門教學, python.org 。由於我們認為對於Ren’Py來說,更深一層的python知識不是必要的,了解python語句和表達式通常就足夠了。