程式語言基礎 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)就是beach
、night
和happy
。單字
at
、as
、behind
、onlayer
、with
和zorder
都不能用於圖像名中。- 字串(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語法規則一樣。其他前綴則不能用,比如u
、b
和f
。 連續3個引號不能在普通字串中使用,其實際用途請參考 獨白模式 。- 簡單表達式(simple expression)
簡單表達式就是一個Python表達式,用於在Ren’Py腳本中運行Python。一個簡單表達式使用以下類型作開頭:
一個變數名。
一個字串。
一個數字。
圓括號中包含的任意表達式。
其後可以接續任意數量的:
名稱前的一個英文句號字元。
圓括號內的Python表達式。
舉例,
3
、(3 + 4)
、foo.bar
和foo(42)
都是簡單表達式。但3 + 4
則不是“簡單”表達式,因為該表達式是一個算式字串且沒有使用圓括號。- 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表達式中可以使用變數。通過 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語句和表達式通常就足夠了。