跳轉到內容

Celestia/Celx 指令碼/CELX Lua 方法

來自華夏公益教科書

此摘要描述了對 Celestia 中 Lua/CELX 指令碼的支援,主要包括 CELX API。本文件以及 Celestia 中的 CELX 支援可能包含一些錯誤或漏洞。請報告您發現的任何問題。

關於本文件

[編輯 | 編輯原始碼]

它最初是為了記錄 Celestia v1.3.1pre11 開發期間可用的功能,然後隨著新功能的貢獻而擴充套件。

CELX 使用 Lua 程式語言,所以您實際上是在編寫程式。這與舊的 CEL Celestia 指令碼完全不同,舊的 CEL Celestia 指令碼只是一系列固定命令。因此,您可能需要具備一些程式設計經驗,否則本文件對您幫助不大。

閱讀 Lua 文件的前幾節也是一個好主意,可以在以下位置找到:

CELX 在 Celestia 中的工作原理

[編輯 | 編輯原始碼]

Celestia 大致(!) 透過重複以下步驟來工作:

  • 檢查使用者輸入,相應地更改渲染設定(例如,啟用軌道的渲染,更改觀察者位置/方向)
  • 更新模擬時間
  • 如果啟用了跳轉,更新觀察者的位置
  • 使用當前設定(渲染標誌,時間,位置)渲染所有物件

如果 CELX 指令碼已啟動,它將在渲染開始前執行。然後 Celestia 將控制權交給 Lua 直譯器,它將繼續從上次停止的地方執行指令碼。當 CELX 方法在指令碼中被呼叫時,例如 celestia:print(),Lua 直譯器會呼叫一個小的 C++ 函式,該函式會將引數從 Lua 型別轉換為 C++ 型別,呼叫正確的 Celestia 方法來執行操作,並在必要時將 C++ 返回值轉換回 Lua 值。請注意,Lua 直譯器呼叫了此 C++ 函式,因此當該函式返回時,指令碼將繼續執行:永遠不會有機會將控制權交回 Celestia 迴圈。為此,指令碼必須呼叫 wait() 函式,該函式使 Lua 直譯器返回控制權。

在 Celestia 1.3.1 中忘記呼叫 wait() 意味著 Celestia 永遠不會再次獲得控制權,因此無法處理停止或退出指令碼的命令 - 它完全被阻塞了。從版本 1.3.2 開始,Celestia 定期檢查指令碼是否超過了最大允許的執行時間(5 秒),如果超過了,它將終止指令碼。

應該很清楚的是,大多數操作實際上並沒有立即更改任何內容。相反,指令碼會更改一個設定,該設定稍後在渲染過程中使用,從指令碼的角度來看,這發生在呼叫 wait() 的時候。因此,如果觀察者的位置更改十次,而沒有在中間呼叫 wait(),則不會有任何影響 - 只有最後一個位置才會實際用於渲染。

有關 Lua 語法的完整描述,請閱讀 http://www.lua.org/manual/5.0/
Celestia 版本 1.5.0 使用 Lua 版本 5.1,它與早期 Celestia 版本中使用的 Lua 版本 5.0 略有不同。
Lua 5.1 手冊可在 http://www.lua.org/manual/5.1/ 找到
有關 Lua 版本 5.0 和 5.1 之間更改的詳細資訊,請參見 http://www.lua.org/manual/5.1/manual.html#7

一些快速入門說明

  1. Lua 命令可以透過文字行終止符或分號來終止。要在文字的單行中包含多個 Lua 命令,請用分號 (;) 分隔它們,但如果行中只有一個 Lua 命令,則不需要分號。
  2. 使用諸如“記事本”、“記事本++”或“寫字板”之類的行編輯器無需文字格式來編寫您的 CELX 指令碼;
  3. 短(單行)註釋以兩個連字元“--”開頭;
  4. 長(多行)註釋使用“--[[ comment ]]”。
  5. 當您在 CELX 指令碼的第一行中使用註釋“-- Title: string:text”時,string:text 標題將在 Celestia/檔案/指令碼下拉選單中顯示,而不是檔名。

示例

-- Title: Example script
-- This is a short comment line.
-- [[ This
      is
      a
      long
      comment
      line.]]
a = 5; b = 6 -- two Lua commands on a single line
c = 3        -- one Lua command on a line

變數和型別

[編輯 | 編輯原始碼]

Lua 變數不需要宣告,也沒有型別,但是內容有型別。

Lua 中有八種基本型別

  1. nil
    • Nil 是值 nil 的型別,其主要屬性是與任何其他值不同;它通常表示缺少有用的值。
  2. boolean
    • Boolean 是值 false 和 true 的型別。
      nil 和 false 都使條件為假;任何其他值都使它為真。
  3. number
    • Number 表示實數(雙精度浮點數)。
  4. string
    • String 表示任何 8 位字元的陣列。
  5. table
    • 表格可以用作陣列,這些陣列不僅可以用數字索引,還可以用任何值索引(除了 nil)。
      表格也可以包含所有型別的的值(除了 nil)。
  6. userdata
    • 用於控制 Celestia 的物件屬於這種特殊的型別 userdata。
  7. function
    • 函式型別是一個可執行表示式,編譯自 Lua 和 CELX 程式碼塊。
  8. thread
    • 這裡不作進一步解釋。

示例
同一個變數“a”可以具有不同型別的內容。

a = 1                -- a is 1, an integer number
a = a / 2            -- a is now 0.5, changed into a floatingpoint number
a = "Hello World"    -- a contains a string now 
a = a / 3            -- ERROR, because a string is divided by a number! 
a = true             -- a is true, a boolean
a = not a            -- a is now false, a boolean

示例
表格可以像這樣使用。

t = {}                                  -- define Table t
t["key1"] = "value1"                    -- long form to store a string
t.key2 = "value2"                       -- short form to store a string
u = { key1="value1", key2="value2" }    -- u is now the same as t 
v = { 1,2,3,4,5 }                       -- v[1] is now 1, v[2] is 2, etc.

要操作 userdata,您可以呼叫物件的方. 要將 Lua 用於 Celestia,您主要只需要瞭解可用的物件、定義在它們上的方法以及如何呼叫它們 - 任何已經瞭解面向物件程式設計的人都會感覺賓至如歸。

在指令碼的開頭,celestia 物件會自動定義,它儲存對 Celestia 的核心功能的引用!要操作此 celestia 物件,您可以呼叫定義在它上的方法,方法是使用“celestia:”字首,如 celestia 方法 部分所示。

示例

-- Get observer instance of the active view and store it in "obs"
obs = celestia:getobserver()

-- Find the celestial object representing Earth and store it in "earth"
earth = celestia:find("Sol/Earth")

-- Do something to confuse the reader, but possible in CELX
-- The object with name mars is made equal to the object with name earth
mars = earth
-- You can also use obs and earth like this.
obs:goto(earth)
-- This will start the goto-command, which moves the observer to Earth,
-- just as if you had pressed the [G] key in Celestia, after selecting Earth.

函式是一個可執行表示式,編譯自 Lua 和 CELX 程式碼塊,其值具有函式型別。

函式可以有用於輸入值的引數,並且函式也可以返回零個、一個或多個值(有關詳細資訊,請參閱 Lua 文件)。

您可以在 CELX 指令碼的開頭定義一個或多個函式,並且可以在 CELX 指令碼的主體中呼叫它們一次或多次。

示例

-- Define function with name "add_one" and parameterlist "i" (a number).
function add_one(i) 
   -- use 'local' to declare variables local to function: 
   local j = i + 1 
   -- return the value of "j", a number.
   return j 
end
-- Define function with name "divide" and parameterlist "i, j" (two numbers).
function divide(i, j) 
   -- return the value of the division "i / j", a number.
   return i / j 
end
-- Start of the main body of your script
<... other script code ...>
-- and now call the functions: 
a = add_one(1) 
b = divide(a, 2)
<... other script code ...>

函式“wait(number:n)”在 Celestia 中預定義,等待 number:n 秒。它很特殊,因為它會將控制權交回 Celestia,您必須這樣做以避免阻塞 Celestia。

Lua 中定義了許多其他函式(參見 Lua 文件),例如數學函式或字串操作。

備註

  1. 並非所有 Lua 庫都被載入,您無法訪問 io 和除錯功能(這極大地降低了來自“惡意”指令碼的安全問題的風險)。有關更多資訊,請參見方法 celestia:requestsystemaccess()

控制結構

[編輯 | 編輯原始碼]

Lua 擁有典型的控制結構,例如 forwhilerepeatif

示例

-- Execute the block of codelines (...) 10 times after each other,
-- where "i" is incremented with 1 during each loop.
for i = 1, 10 do 
   ... 
end
-- Execute the block of codelines (...)
-- as long as "i" is smaller than or equal to 11.
i = 1 
while i <= 11 do 
   ... 
   i = i + 1 
end
-- Execute the block of codelines (...) 
-- until "i" is equal to "j".
i = 1
j = 22
repeat 
   ... 
   i = i + 1 
until i == j
-- Compare "i" and "j" with each other and execute a
-- certain block of codelines (...1, ...2 or ...3),
-- depending on the result of this comparison.
if i > j then 
   ...1
elseif i < j then 
   ...2 
else 
   ...3
end
-- To loop over the contents of a table "tbl", you can use this:
for key, value in pairs(tbl) do
   -- tbl[key] == value
   ...
end
-- Use this for tables used as arrays, i.e. indexed by numbers 1..n: 
for i, value in ipairs(tbl) do	
   -- tbl[i] == value
   ... 
end

物件和方法 (CELX API)

[編輯 | 編輯原始碼]

本節介紹 CELX Lua 指令碼中可用的 userdata 類(物件型別)。

除了預定義的 celestia 物件,還有其他與 celestia 相關的物件來控制 Celestia。您無法自己建立物件(即 userdata),必須呼叫某個方法來建立物件。由於指令碼啟動時只有 celestia 物件(忽略與 Celestia 無關的方法)可用,因此您必須使用它來建立其他物件。

以下與 celestia 相關的物件可在 CELX 指令碼中使用

  1. 觀察者物件:
    觀察者物件用於訪問特定於檢視的屬性,例如檢視者位置、檢視者方向、參考系和跟蹤狀態。要操作觀察者物件,您可以呼叫在其上定義的觀察者方法,如 觀察者方法 一節所示。
  2. 物件物件:
    CELX 中的“物件”物件是指像行星或恆星這樣的天體。要操作“物件”物件,您可以呼叫在其上定義的“物件”方法,如 物件方法 一節所示。
  3. 位置物件:
    位置物件包含空間中某個點的精確座標。要操作位置物件,您可以呼叫在其上定義的位置方法,如 位置方法 一節所示。
  4. 向量物件:
    向量物件是幾何物件,在三維座標系中具有長度和方向 [X,Y,Z]。要操作向量物件,您可以呼叫在其上定義的向量方法,如 向量方法 一節所示。
  5. 旋轉物件:
    旋轉物件在內部是四元數,這是在數學上描述三維旋轉的一種方法(即它可以轉換為旋轉矩陣)。旋轉也可以用於描述物件或觀察者的方向(即觀察者所看方向和“向上”方向)。要操作旋轉物件,您可以呼叫在其上定義的旋轉方法,如 旋轉方法 一節所示。
  6. 幀物件:
    幀物件描述了 celestia 座標系,並說明了每個三維座標系的 X、Y 和 Z 軸是如何對齊的。座標系在 Don Goyette 編寫的可用 Celestia .Cel Scripting Guide v1-0g 中的“座標系”一章中有詳細介紹。要操作幀物件,您可以呼叫在其上定義的幀方法,如 幀方法 一節所示。
  7. 相位物件:
    物件的時序可以細分為一個或多個相位。每個相位物件都有自己的軌跡、旋轉模型、軌道系和主體系。要操作相位物件,您可以呼叫在其上定義的相位方法,如 相位方法 一節所示。
  8. CELscript 物件:
    CELscript 物件包含一個包含有效 CEL 指令碼的字串,該字串可以透過使用“celestia:createcelscript()”方法嵌入 CELX 指令碼。要操作 CELscript 物件,您可以呼叫在其上定義的 CELscript 方法,如 CELscript 方法 一節所示。

示例
要呼叫 observer 的方法 getposition(),您首先必須從 celestia 獲取一個觀察者例項,然後對其呼叫 getposition()。

obs = celestia:getobserver() 
pos = obs:getposition()

備註

  1. 在使用本文件中的各種類的名稱時,這些名稱在指令碼中沒有任何實際意義。即使“celestia”也只是一個變數,它儲存著型別為 celestia 的物件,實際上並沒有什麼特殊之處。

在下一節中,將列出每個方法及其簽名

return_value_type object:methodname(type:parameter, type:parameter [, type:optional parameter])

之後是

  • 簡短的描述,說明方法的作用;
  • 引數/引數列表及其用途;
  • 可能還有一些關於如何使用此方法、它究竟做了什麼、一些注意事項等的說明
  • 最後給出了關於使用方法的示例

物件和方法索引

[編輯 | 編輯原始碼]

1.6.0 僅在 Celestia 1.6.0 及更高版本中可用

物件和方法索引 (字母順序)

[edit | edit source]

1.6.0 僅在 Celestia 1.6.0 及更高版本中可用

Callbacks

[edit | edit source]

回撥函式是在外部事件發生時執行的函式。

目前Celestia中有兩種回撥函式可用

注意: 回撥函式的功能有限

  • 回撥函式必須在1秒內完成,否則將被終止;
  • 您不能在回撥函式中使用wait()函式!

CEL 到 CELX 遷移

[edit | edit source]

以下部分包含可用 CEL 命令的索引。單擊特定命令,您將被引導至有關其功能以及如何將該 CEL 命令遷移到等效的 CELX 物件和方法的說明。

CEL 命令索引

[edit | edit source]

以下 CEL 命令按照 Don Goyette 在 Celestia .Cel Scripting Guide v1-0g 中對 CEL 指令碼命令的順序和解釋進行組織。這些解釋還包含許多 Don 的示例和語法描述,以幫助從 CEL 遷移到 CELX。

在本節中,CEL 命令和 CELX 方法的引數值以 <type> 或 <name> 的形式列印。在實際使用這些命令或方法時,需要替換這些引數值。

示例

<string>    "Sol/Earth"
<duration>  1.5
<distance>  20000

從 Celestia 1.6.0 和 1.6.1 版本開始,最初僅包含 35 個 Cel 命令的列表已擴充套件到 52 個 Cel 命令。新增命令用 1.6.01.6.1 表示。

  1. cancel
  2. 1.6.0 capture
  3. center
  4. changedistance
  5. chase
  6. cls
  7. 1.6.0 constellationcolor
  8. 1.6.0 constellations
  9. 1.6.0 deleteview
  10. 1.6.0 exit
  11. follow
  12. goto
  13. gotoloc
  14. gotolonglat
  15. labels
  16. lock
  17. lookback
  18. mark
  19. move
  20. orbit
  21. 1.6.0 orbitflags
  22. preloadtex
  23. print
  24. renderflags
  25. 1.6.0 renderpath
  26. rotate
  27. select
  28. set
  29. 1.6.0 setactiveview
  30. 1.6.0 setambientlight
  31. setfaintestautomag45deg
  32. setframe
  33. 1.6.0 setgalaxylightgain
  34. 1.6.0 setlabelcolor
  35. 1.6.0 setlinecolor
  36. setorientation
  37. setposition
  38. 1.6.0 setradius
  39. setsurface
  40. 1.6.1 settextcolor
  41. 1.6.0 settextureresolution
  42. seturl
  43. setvisibilitylimit
  44. 1.6.0 singleview
  45. 1.6.0 splitview
  46. synchronous
  47. time
  48. timerate
  49. track
  50. unmark
  51. unmarkall
  52. wait

備註

[edit | edit source]

常見問題

[edit | edit source]
  • Lua 指令碼在 Celestia 的渲染階段之間執行。因此,如果您進行一些冗長的計算(或無休止的迴圈),Celestia 將無法更新螢幕,甚至無法檢查按鍵(即,您無法透過按下 [Esc] 鍵來停止指令碼)。從指令碼的角度來看,渲染和 UI 處理僅在呼叫 wait() 時發生。如果指令碼超過 5 秒未將控制權返回給 Celestia,則該指令碼將被終止。
  • 如果您想平滑地移動觀察者,請透過設定其位置來執行此操作,然後呼叫 wait()。但請注意:如果在某個天體上激活了“跟蹤”,這會覆蓋指令碼中的任何 observer:setorientation()。高時間速率會在渲染行星之前顯著改變行星的位置,這會導致運動不流暢。如有必要,請在指令碼中檢查並重置時間和時間速率。
  • 在 Windows 上,wait() 可以非常快地返回而不會執行任何渲染,而在 Linux 上,它可靠地強制執行渲染傳遞。
  • 使用者可以在指令碼執行時更改設定,包括選定天體、位置、方向、速度、時間速率、渲染標誌等。不要依賴於這些設定保持不變,如有必要,您必須不斷重置它們。
  • 參考系一開始可能很難掌握。如果您嘗試將觀察者設定為太陽系內的某個位置,但得到的日心距離約為 206 個天文單位,那麼您可能設定了錯誤的參考系。在 1.5.0 版本之前,206 個天文單位是宇宙座標中原點 [0,0,0] 與太陽位置之間的距離。從 1.5.0 版本開始,Celestia 將太陽系的質心放置在 [0,0,0] 處。
  • 如果您的指令碼使螢幕完全變黑或出現其他奇怪的效果,請檢查是否有任何使用 observer:setorientation()observer:lookat() 的情況。您可能將方向設定為“無效”四元數(例如全為零),可能是透過使用 observer:lookat() 使向上向量平行於視點方向。如果發生這種情況,您可以透過執行一個將方向設定為合理值的指令碼(或簡單地重新啟動 Celestia)使 Celestia 恢復可用。
華夏公益教科書