Mod:基礎

出自Noita Wiki
跳至導覽 跳至搜尋
模組製作導航
基礎
入門基礎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共享)。這對於模型間的兼容性來說非常重要,請記住這一點。
    • 通過社區測試,目前的上限似乎是tags224個,_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的最常見的方法列表:

  1. 開發建設 noita_dev.exe:
    • 從一個開發控制台開始。這是直接發現你的Lua/XML中發生的任何錯誤的最好方法
    • 該可執行文件應位於 tools_modding/,但只能從根目錄下啟動(即旁邊的noita.exe)。如果你到目前為止一直遵循指示,它應該已經在那裡了。
    • 按下F1來顯示綁定鍵的列表。 按下F5來啟用大多數調試功能。
    • 需要看到的是print()輸出到控制台,但 GamePrint() 在任何地方仍然有效(在遊戲中顯示在左下角的位置).
    • 注意:眾所周知,這對許多人來說會降低性能。因此,經常在這兩種構建之間切換是完全可以的。
  2. 記錄到文件中:
    • 通過特定的魔法數字啟用。
    • 或者下載一個不錯的MOD,它可以為你做這個: Modworkshop
    • 記錄到 Noita/logger.txt
  3. 欺騙性的GUI模型:
    • 很適合測試遊戲功能,不需要擺弄任何調試功能。
    • 生成物品/天賦/法杖,傳送,增加生命值,等等。所有這些都直接來自遊戲中的HUD
    • 下載: [Steam Workshop | Github]
  4. Noita 還支持 Decoda Lua debugger:
    • 需要單獨設置。說明見 tools_modding/lua_debugging.txt

注意:遊戲應該在任何MOD文件發生變化時進行檢測,從而在開始新遊戲時硬重啟遊戲,但目前已知這並不太可靠。因此,現在建議你總是通過手動退出/關閉遊戲來完全重新啟動你的遊戲。