Mod:基礎
基礎 |
---|
入門 • 基礎 • Lua腳本 • Data.wak • 實用工具 |
製作指南 |
音頻 • 敵人 • 生物群系 • 天賦 • 法術 • 精靈表 • 材料 • 圖像放射器 • 特殊行為 • CMake使用 |
組件/實體 |
組件文檔 • 枚舉 • 特殊標籤 • 所有標籤列表 |
Lua編程 |
Lua API • 實用腳本 |
其他信息 |
法術和天賦的ID • 聲音事件 • 魔數(Magic Numbers) |
本頁旨在簡要介紹Noita修改的所有基本概念。ECS(即 Entity-Component-System(實體-組件-系統) 的縮寫),目錄結構,Lua鉤子,等等
Mod的安裝位置
兩個常見的Mod位置是:
Noita/mods/
- 手動下載的Mod或Mod開發。steamapps/workshop/content/881100/
- 你通過Steam 創意工坊下載的Mod可以在這裡找到。
Mod目錄結構
這是一個示例MOD,顯示了你應該遵循的基本文件結構
myAwesomeMod/ ├── data/ │ └── enemies_gfx/ │ └── player.png ├── files/ │ └── my_custom_script.lua ├── init.lua └── mod.xml
讓我們把它細分一下:
myAwesomeMod/
- 這是 根 文件夾,是你Mod的基本路徑。這個myAwesomeMod是你所自定義的mod文件名,列如法術實驗室mod的名字則是spell_lab。這直接就是mod文件夾的名字,需要謹慎起名,因為在之後的開發中這個名字的調用是必須要的。
data/
- 這個文件夾的結構與我們之前提取的Noita的數據文件完全相同。 當你想覆蓋基本資源時,請使用這個ONLY。
enemies_gfx/
- 一個儲存所有精靈表的文件夾。(簡單來說就是材質/貼圖)
player.png
- 米納的動畫精靈表(Minä|米納,玩家控制的主角)。 在data/文件夾內,當這個mod被激活時,它直接替換了基本遊戲的精靈表
files/
- 這個文件夾用於存放所有你對於Mod所自定義的資源/腳本/數據,主要就是防止和其他mod衝突,自定義的內容應該放在這個文件夾裡面。一般開發別動data文件里的內容為好。
my_custom_script.lua
- 一個自定義的lua腳本文件,它可以做任何事情,也可以從任何地方調用。在自定義途中你可以給這個腳本起一個和功能相關的名字。
init.lua
- 你製作Mod的起點,包括世界初始化的鉤子,玩家生成之類的內容。這是一個"Hello world"的開始。
mod.xml
- MOD元數據定義文件,包括mod名稱、mod描述和一堆其他的初始設置。
引用不同路徑中的文件
如上所述,data/
和 files/
這兩個文件夾之間的行為非常不同。由於這個原因,你在其中引用的文件也略有不同。data/
基本上可以看作是Noita內部自己的虛擬文件系統,可以直接引用,但其他一切都需要有你的完整mod路徑。 例如Lua中的文件,同樣具有上述結構。
-- 数据文件的部分路径(当被覆盖时也是如此,即使它不包括在你自己的mod中)
dofile_once("data/scripts/lib/utilities.lua")
-- 自己脚本的完整路径
dofile_once("mods/myAwesomeMod/files/scripts/my_custom_script.lua")
在定義路徑時,同樣的事情也適用於XML。 (例如,精靈表、投射物、效果,任何東西)
實體組件系統基礎知識
實體是基於一些簡單的規則:
- 可以包含任何數量的組件,甚至是相同的組件
- 可以有子實體,定義它們自己的組件
- 可以繼承其他實體,複製其功能
- 只可以有一個名字(name)
- 可以有多個標籤(tags)
例子
讓我們從基本遊戲文件中分解出一個實體的例子: data/entities/props/banner.xml
<Entity tags="prop">
<VelocityComponent />
<SimplePhysicsComponent />
<SpriteComponent
z_index="1"
image_file="data/props_gfx/banner.xml"
offset_x="0"
offset_y="0"
></SpriteComponent>
</Entity>
這是你能找到的最簡單的實體之一,裡面只有三個組件組成。如果在遊戲中產生,你應該看到一個簡單的動畫旗幟掉落在地上,沒有任何特殊功能。
VelocityComponent
速度組件:一般來說,任何與物理有關的東西都需要有一個 "物理學"組件。它可以定義一些東西 (如個別實體的重力), 但在這裡我們只是用默認值啟動它。你可以在下面找到所有的值component_documentation.txt
。SimplePhysicsComponent
簡單的物理組件:賦予這個實體非常簡單的物理屬性。它會一直往下掉,或停在任何牆壁上,通常不能與一般的物理對象發生碰撞,也不能被踢到。對於適當的物理學,你需要一個物理體組件(PhysicsBodyComponent)和物理形狀組件(PhysicsShapeComponent),你可以在數據文件中找到許多不同的例子。SpriteComponent
精靈組件:簡單地將一個圖像文件附加到實體上,並帶有任何指定的偏移量等。這裡定義了一個XML文件作為圖像的來源,當你想在實體上添加動畫精靈時,這是很有必要的。如果你的精靈圖是一個靜態圖像,你也可以在這裡直接引用它。
讓我們看一下圖像文件 data/props_gfx/banner.xml
:
<Sprite
filename="data/props_gfx/banner.png"
offset_x="12"
offset_y="30"
default_animation="stand">
<!-- stand -->
<RectAnimation
name="stand"
pos_x="0"
pos_y="0"
frame_count="7"
frame_width="32"
frame_height="32"
frame_wait="0.11"
frames_per_row="7"
loop="1"
></RectAnimation>
</Sprite>
這些獨立的元數據文件本質上是在實體組件系統之外的,它們只是以與其他一切相同的XML格式定義精靈元數據。因此,在component_documentation.txt
中找不到XML元素的文檔,因為這些不是組件也不是實體。但是,讓我們把這個問題也分解一下:
- 在這裡,我們終於引用了我們想要繪製的實際圖像文件
- 主要內容
<Sprite>
中的元素僅有一個<RectAnimation>
子元素,它可以有多個這樣的元素,每個動畫都有一個 (對任何角色都是正常的)
- 動畫的名字(name)是 "站立(stand)",它也被引用為默認動畫。名稱(name)可以是任何東西,但必須與使用它們的東西相匹配。(這是編程基本規則)
frame_*
屬性是不言自明的,但基本上是定義動畫時最重要的部分。這些必須與你的圖像文件中的精靈表相匹配。
你可以去看看這個文件data/props_gfx/banner.png
, 這一切應該就變得相當明了了。
創建和刪除實體
有許多方法可以讓你產生/殺死實體。最簡單的方法是直接使用Lua:
- 生成時用
EntityLoad("path/to/entity.xml" , x, y)
- 刪除用
EntityKill(entity_id)
僅僅作為一個例子,其他可能的生成/清除地點包括:
ProjectileComponent::spawn_entity
投射物組件的spawn_entity可用於在投射物碰撞時生成任何實體。CameraBoundComponent
攝像機邊界組件可以用來限制經常使用的實體的生成率/距離 (例如:敵人,燈籠,......)LifetimeComponent
存在時間組件,從字面上看是給了一個實體一定的存在時間DamageModelComponenet
損傷組件使得實體擁有命中率和受到傷害。實體在生命值變成0時被殺死。- ...除此之外還有更多
標籤
實體和組件都可以有任何數量的標籤(tags)附加在它們身上。標籤是對一種 "事物 "進行分類的非常簡單的方法,而且可以很容易地即時創建,不需要任何額外的定義。例如,獲取玩家周圍所有敵人的列表就是這麼簡單。EntityGetWithTag("enemy")
。
来自翻译:EntityGetWithTag("enemy")这段代码是说实体获取标签(EntityGetWithTag)叫做 敌人(enemy)
大多數標籤沒有任何其他內容,但有一組特殊標籤其中有引擎內硬編碼的功能附加在它們身上
注釋:
- 實體標籤被定義在
tags
當中,而組件標籤是在_tags
當中。 - 引擎目前只支持非常有限自定義標籤,這些標籤在所有MOD中都是全局性的(也就是所有mod共享)。這對於模型間的兼容性來說非常重要,請記住這一點。
- 通過社區測試,目前的上限似乎是
tags
224個,_tags
則是210個。
- 通過社區測試,目前的上限似乎是
- 特殊標籤是Noita整個實體-組件系統的重要組成部分,所以請務必閱讀該頁面。
需要注意的是,由于tag有上限,所以能用name就用name。
實體繼承
- 通過以下方式執行
Base
基礎實體組件。- 基礎實體組件的文件路徑在
file
文件夾里。
- 基礎實體組件的文件路徑在
- 通過定義新的內部基礎元素標籤覆蓋基礎實體組件。
- 當覆蓋時,基礎(Base)實體必須有你試圖覆蓋的組件被定義。否則會發生錯誤。
- 你自己增加的內容通常在基礎元素之外。
- 你可以隨心所欲地繼承多個基礎實體
- 所有的實體標籤都會被捆綁在一起
init.lua
為任何mod運行的第一段代碼。包括預先確定的函數名稱,你可以用它來連接某些事件,並提供一個地方來收集你的mod的所有文件重寫。
下面的內容幾乎是直接取自mods/example/init.lua
的。 所有的代碼都是可選的,你可以只填寫你需要的部分。
可用的功能鉤子
-- 在加载一个新的(?)游戏时按顺序调用。
function OnModPreInit() end
function OnModInit() end
function OnModPostInit() end
-- 当播放器实体被创建时调用,并确保播放器周围的区块已经被加载和创建。
function OnPlayerSpawned(player_entity) end
-- 当玩家死亡时被调用。
function OnPlayerDied( player_entity ) end
-- 一旦游戏世界被初始化就会被调用。 不保证玩家周围有任何大块的东西。
function OnWorldInitialized() end
-- 每当游戏要开始更新世界时,都会调用。
function OnWorldPreUpdate() end
-- 每当游戏完成更新世界时,都会调用。
function OnWorldPostUpdate() end
-- 当生物群落配置被加载时被调用。
function OnBiomeConfigLoaded() end
-- 最后一点是Mod API可用的地方。在这之后,materials.xml将被加载。
function OnMagicNumbersAndWorldSeedInitialized() end
-- 当游戏暂停或取消暂停时调用。
function OnPausedChanged( is_paused, is_inventory_pause ) end
-- 如果玩家在游戏暂停时改变了任何MOD设置,将在游戏取消暂停时被调用。
function OnModSettingsChanged() end
-- 将在游戏暂停时被调用,可以由暂停菜单或一些库存菜单调用。请注意这一点,因为在游戏暂停时调用,并不是所有东西都会表现良好。
function OnPausePreUpdate() end
覆蓋和擴展系統
這些句子通常被添加到init.lua
的末尾/開頭。這段代碼在所有mods的文件系統被註冊後運行。
-- 基本上dofile("mods/mymod/files/actions.lua")会出现在gun_actions.lua的末尾
ModLuaFileAppend("data/scripts/gun/gun_actions.lua", "mods/mymod/files/actions.lua")
-- 同理,但对于药水来说
ModLuaFileAppend("data/scripts/items/potion.lua", "mods/mymod/files/potion_appends.lua" )
-- 将使用指定的文件覆盖一些神奇的数字
ModMagicNumbersFileAdd("mods/mymod/files/magic_numbers.xml")
-- 将你自己的材料附加到游戏的材料列表中
ModMaterialsFileAdd("mods/mymod/files/custom_materials.xml")
-- 使用这个来注册自定义的fmod事件。事件映射文件可以通过FMOD Studio中的文件->导出GUIDs生成。
ModRegisterAudioEventMappings("mods/mymod/files/audio_events.txt")
重要而有趣的文件
方便的實現
magic_numbers.xml
- 很多變量可以控制遊戲和玩法許多方面的行為。從虛擬解析度(用於控制你所看到的區塊的數量)到生物溢出的血量,很好實行。
data/scripts/lib/utilities.lua
- 大量由Nolla集成的實用功能。包括很多基本的2D平台遊戲的數學幫助,ECS和更多別的。通過閱讀就可以了解事物的工作原理,而不是多次重新實現基本的東西。
開始時可能不太有用
genome_relations.csv
- 遊戲中的所有生物(包括玩家)對彼此關係的表格。
- 可以自由編輯;例如,讓所有生物都對玩家友好到爆炸。
translations/common.csv
- 包括遊戲的所有基本翻譯。很適合交叉連接某些法術名稱,因為在遊戲中看到的大部分文字實際上並不存在於代碼中,而是在這裡。
- 也可以自由編輯,讓你可以重命名/重寫任何法術或遊戲的文本內容。
scripts/wang_scripts.csv
- "全球 "生物群落功能註冊。這裡定義的任何名稱都可以用於所有的地區和像素場景
- 注意:所有的生物群落仍然需要單獨實現這些功能
- 可以自由編輯,加入自己的內容。
post_final.frag
- 主要的 "OpenGL著色器 "文件,可以自由編輯和添加以創建你自己的著色器效果。如果沒有編程/著色器的經驗,不建議使用。
好玩的清單
- 材料:
data/materials.xml
- 天賦:
data/scripts/perks/perk_list.lua
- 魔藥:
data/scripts/items/potion.lua
- 法術:
data/scripts/gun/gun_actions.lua
- 狀態:
data/scripts/status_effects/status_list.lua
- 關於如何擴展這些功能,見上文init.lua的部分。
調試工作(debug)
Noita目前沒有任何一種專門的IDE/測試環境用於開發。很多開發時間確實會花在重啟遊戲以嘗試新的變化上。下面是調試Noita mods的最常見的方法列表:
- 開發建設
noita_dev.exe
:- 從一個開發控制台開始。這是直接發現你的Lua/XML中發生的任何錯誤的最好方法
- 該可執行文件應位於
tools_modding/
,但只能從根目錄下啟動(即旁邊的noita.exe
)。如果你到目前為止一直遵循指示,它應該已經在那裡了。 - 按下
F1
來顯示綁定鍵的列表。 按下F5
來啟用大多數調試功能。 - 需要看到的是
print()
輸出到控制台,但GamePrint()
在任何地方仍然有效(在遊戲中顯示在左下角的位置). - 注意:眾所周知,這對許多人來說會降低性能。因此,經常在這兩種構建之間切換是完全可以的。
- 記錄到文件中:
- 通過特定的魔法數字啟用。
- 或者下載一個不錯的MOD,它可以為你做這個: Modworkshop
- 記錄到
Noita/logger.txt
- 欺騙性的GUI模型:
- 很適合測試遊戲功能,不需要擺弄任何調試功能。
- 生成物品/天賦/法杖,傳送,增加生命值,等等。所有這些都直接來自遊戲中的HUD
- 下載: [Steam Workshop | Github]
- Noita 還支持 Decoda Lua debugger:
- 需要單獨設置。說明見
tools_modding/lua_debugging.txt
- 需要單獨設置。說明見
注意:遊戲應該在任何MOD文件發生變化時進行檢測,從而在開始新遊戲時硬重啟遊戲,但目前已知這並不太可靠。因此,現在建議你總是通過手動退出/關閉遊戲來完全重新啟動你的遊戲。