@longfei
2016-12-14T05:42:36.000000Z
字数 12990
阅读 4239
Don'tStarve
Mod教程
按下面流程制作的一个示范已经上传到了我的网盘,如果在制作过程中有什么疑问,可以参考。
实例下载
mod tools
这是一个官方提供的工具合集,除了提供上传到创意工坊的功能之外,其他的介绍如下:
图片的具体需求:
2和3对大小要求不一样的原因是,放在地上的图片,是可以在spriter里调整大小的。
但3不能,3原本是多大,在游戏里就会显示出多大。我第一次做的时候选用64*64的图片来做3,结果实际显示的大小刚好有人物的拳头那么大。
在讲下面的内容之前,要补充一些下面会用到的说明:
一个在地图上(注意是地图上,放在物品栏里的不算)显示的实体,显示出来的是一个动画。
一个实体可以有多个动画,通过代码来控制播放。简单的比如一棵草,有三个动画:成熟、被采摘后,枯萎后。
对于一个实体的地图表现,以下这些参数是很重要的
现在可以来讲相应内容了。假设你已经用图片处理工具弄好了相应的图片。
然后就开始来正式制作一个MOD吧,这里仅仅讲单机版的。联机版的稍有不同但也没多大差别,聪明的人自然懂得举一反三。
建立mod文件夹和基本文件
在游戏目录下的mods文件夹里建立一个文件夹,名字就叫mymod吧。
然后在mymod里,建立modinfo.lua和modmain.lua两个文件。
modinfo是用于储存你的mod基本信息的,包括mod名字、mod描述、mod作者以及mod版本等等,mod设置也写在这个文件里。
modmain.lua是控制整个MOD文件调用的核心,要想把mod里的专属武器、专属人物输入到游戏里,都需要经过这个文件。这个文件很重要,但在做一个专属装备的时候,它的作用仅仅是写几行代码,让装备能被注册到游戏里而已。
添加物品栏图片
在\mymod\images\inventoryimages下添加物品栏图片 myitem.png
注意,images这个文件夹,名字不能随意改动,后面的inventoryimages文件夹可以改动,甚至也可以不要,直接将图片放在images文件夹下也可以。不过还是推荐使用inventoryimages,能够区分不同图片的区别,也不会造成重名问题。 这个路径是涉及到后面编程时的代码的,区分大小写。所以如果总是报错,记得先检查大小写是否正确。
然后在这个文件夹下,新建一个.xml文件。输入以下内容并保存
<Atlas>
<Texture filename="myitem.tex" />
<Elements>
<Element name="myitem.tex" u1="0" u2="1" v1="0" v2="1" />
</Elements>
</Atlas>
.xml文件是用来控制切割图片的,不过对于这样只有一张的图,就直接取整张,无需切割了。这里也不做过多的解释。
游戏里使用的图片是.tex格式的,但如果你的png图片长、宽都是2的整次方倍,并且是8位RGB,背景透明的,那么mod tools会帮你自动转换成.tex图片。推荐使用这种方法来转换图片,而不要使用TEXCreator,虽然后者转换的图片也能被游戏使用,但可以在游戏运行日志里看到对不合长宽范式的图片会有警告信息,也许会在某处出错。
如果mod tools没有转换你的图片,那么肯定是你的图片不符合格式。它对格式有着严格要求:
RGB 8位,带ALPHA通道,png,长、宽是2的整数次方倍(长宽可以不相等,不过对于物品栏图标来说,最好还是要相等)。一个简单的处理办法是,用PhotoShop新建一个长宽符合要求的RGB 8位,背景内容为透明的画布,然后把原图片复制过来,保存为png格式。
添加地上动画
在\mymod\exported\下建立一个新的文件夹,名字随意,就叫ground_myitem吧
然后再在这个文件夹下建立一个文件夹,同样名字随意,我的习惯是仍然叫ground_myitem
然后在这个文件夹下添加地上动画图片 ground_myitem.png
接着打开你的Spriter,File-->New Project ,点击OK,在弹出的浏览框里找到
饥荒游戏根目录\mods\mymod\exported\ground_myitem,点击选择文件夹。(注意下面的"文件夹:"输入框里不要填字)
然后你会看到这样的画面
点开右边的那个文件夹,在里面双击图片ground_myitem.png,移动那个十字到你觉得合适的位置。
附带说一句,mod tools提供的spriter是简易免费版,不提供如图所示的九宫格自动定位坐标点的功能。你需要在steam上购买spriter pro,或者去百度盗版的spriter pro。
这个十字就是图片的控制点,决定着你的人物在拾取它的时候会拾取哪个部位,对拾取这个动作其实影响不大,但是对后面手持的影响就很大了。然后把图片拖到中间的大屏幕上,设定合适的大小(位置不用管)
然后看到下面的Animations栏,要改动名字。
entity_000,这个是对应着装备的Bank的名字,我们就改成myitem_bank吧。
NewAnimation则对应着Animation的名字,就改成idle吧。
做完这些,你就可以保存了,注意保存的位置必须要在图片文件夹所在的位置,比如这里就是
\mods\mymod\exported\ground_myitem
保存的名字,就是你的装备的Build名,这里就叫myitem_build吧。
这样一来,物品的地上动画也做好了。
添加手上动画
在\mymod\exported\下建立一个新的文件夹,名字随意,就叫swap_myitem吧,然后再在这个文件夹下,建立一个新的文件夹,将图片放入其中。此处必须把图片放在文件夹中,不可放在外层。scml文件则必须放在外层。文件夹的名字对应着这个物件的symbol名,这里不妨就填swap_myitem。然后,同3一样,打开spriter,
手上动画和地上动画还有一个很大的区别,就是你在spriter里调节的大小、方向,是不会在手上显示出来的。你的图片里,武器朝向哪个方向,有多大,那么实际到了游戏就维持着相同的样子。所以如果你要改动在手上的武器朝向或大小,只能改图片。
你设定的图片控制点,就是人物的手持位置。比如我把控制点设置在了武器的尖头上,实际效果如下图:
如此,就完成了所有的美术准备,下一步就是代码了。
首先我们要给这个新武器起个名字,就叫myitem吧。
name = "My item example" --Mod的名字
description = "A simple item example" --Mod描述
author = "LongFei" --作者名
version = "0.1" --Mod版本
forumthread = ""--MOD在klei论坛的下载地址,没有可以留空,但不可删除
api_version = 6--mod的API版本
--priority = -9999 --mod的启动优先级,越低的越晚启动,一般不用设置,除非和其他MOD有冲突需要调整
dont_starve_compatible = true--以下几句,都是设置兼容性的,分别对应DS,ROG,SW和DST
reign_of_giants_compatible = true
shipwrecked_compatible = true
dst_compatible = false
icon_atlas = ""--mod的图标设置
icon = ""--mod的图标图片
PrefabFiles = {
"myitem",--PrefabFiles是一张注册表,是用来向游戏注册prefab的,所有的新设定的prefab都必须在这里注册。如果你有多个prefab,就在中间用逗号隔开。prefab在某种意义上可以说是饥荒世界的原子,武器也算是一个prefab,所以也要注册。
}
local assets=
{
Asset("ANIM", "anim/myitem_build.zip"),--这个是放在地上的动画文件
Asset("ANIM", "anim/swap_myitem_build.zip"), --这个是手上动画
Asset("ATLAS", "images/inventoryimages/myitem.xml"),--物品栏图标的xml
Asset("IMAGE", "images/inventoryimages/myitem.tex"),--物品栏图标的图片
}
--目前我还弄不清楚下面这代码的具体意义,但就先这样空着吧,不能随意乱删,因为有一定的格式要求
local prefabs =
{
}
local function OnEquip(inst, owner) --当你把武器装备到手上时,会触发这个函数
owner.AnimState:OverrideSymbol("swap_object", "swap_myitem_build", "swap_myitem")--这句话的含义是,用swap_myitem_build这个文件里的swap_myitem这个symbol,覆盖人物的swap_object这个symbol。swap_object,是人物身上的一个symbol,swap_myitem_build,则是我们之前准备好的,用于手持武器的build,swap_myitem就是存放手持武器的图片的文件夹的名字,mod tools自动把它输出为一个symbol。
owner.AnimState:Show("ARM_carry") --显示持物手
owner.AnimState:Hide("ARM_normal") --隐藏普通的手
end
local function OnUnequip(inst, owner)
owner.AnimState:Hide("ARM_carry") --隐藏持物手
owner.AnimState:Show("ARM_normal") --显示普通的手
end
local function fn()--这个函数就是实际创建物体的函数,上面所有定义到的函数,变量,都需要直接或者间接地在这个函数中使用,才能起作用
local inst = CreateEntity()--创建一个实体,常见的各种inst,根源就是在这里。
local trans = inst.entity:AddTransform()--给实体添加转换组件,这主要涉及的是空间位置的转换和获取
local anim = inst.entity:AddAnimState()--给实体添加动画组件,从而实体能在游戏上显示出来。
MakeInventoryPhysics(inst)--给实体设定为"物品"的物理属性,这是一个写在data\scripts\standardcomponents里的标准函数,类似的还有MakeCharacterPhysics,就是设定"人物"的物理属性,基本上所有会动的生物,都会有MakeCharacterPhysics
anim:SetBank("myitem_bank")--设置实体的bank,此处是指放在地上的时候,下同
anim:SetBuild("myitem_build")--设置实体的build
anim:PlayAnimation("idle")--设置实体播放的动画
inst:AddComponent("inventoryitem")--添加物品栏物品组件,只有有了这个组件,你才能把这个物品捡起放到物品栏里。
inst.components.inventoryitem.imagename = "myitem" --物品栏图片的名字
inst.components.inventoryitem.atlasname = "images/inventoryimages/myitem.xml"--物品栏图片的xml文件。为什么会有这么两句呢?在单个文件下也许会迷惑,但如果换成一个张大图就容易理解了。举个例子,游戏的操作界面,HUD,你可以在data\images下找到HUD.tex,用textool打开就会看到是一整张大的图片,包含了整个操作界面的所有图片,xml就是用来切割分块这张大的图片,并分别给它们重新命名的,新的命名就会被前面的imagename 使用。
inst:AddComponent("equippable")--添加可装备组件,有了这个组件,你才能装备物品
inst.components.equippable:SetOnEquip( OnEquip ) -- 设定物品在装备和卸下时执行的函数。在前面定义的两个函数是OnEquip,OnUnequip里,我们主要是围绕着改变人物外形设定了一些基本代码。 在装上的时候,会让人物的持物手显示出来,普通手隐藏,卸下时则反过来。需要注意的是,OnEquip,OnUnequip都是本地函数,要想让它们发挥作用,就必须要通过这里的组件接口来实现。
inst.components.equippable:SetOnUnequip( OnUnequip )
return inst
end
return Prefab("common/inventory/myitem", fn, assets, prefabs)--最后,返回这个实体到modmain里注册。Prefab这个函数,第一个参数只需要看最后一个/后面的部分,视为这个prefab的ID,fn则是上面定义的fn,是这个物品的创建函数,assets,对应上面的assets,主要是用于注册美术资源,如果你在这里注册了相应的美术资源,就不需要在modmain里再注册一次。prefabs,目前还未明确具体的作用。
为了让你的新装备不依赖于控制台产生,就需要给它设定一定的生成方式。这里只介绍最简单的一种,就是给装备设置一个Recipe,让它能被制作。
联机和单机在这个地方,总体上差不多,但细节会有变化,要分开来说明。首先从单机版开始。
在单机里,添加Recipe,是通过定义一个Recipe类的实例来实现的。
lua本身没有类这个概念,在饥荒里,类是通过函数来实现的,Recipe类的构造函数就是Recipe函数。
在海难DLC下,Recipe函数有以下变量:self, name, ingredients, tab, level, game_type, placer, min_spacing, nounlock, numtogive, aquatic, distance。非海难DLC,则是以下变量,name, ingredients, tab, level, placer, min_spacing, nounlock, numtogive。
其中第一个变量self是定义一个类都必须有的变量self,代表了这个类本身,只在定义类的时候有用。通过类的构造函数定义类的实例,只需要填后面的变量就行了。前面4个变量name,ingredients,tab,level比较重要,只讲解这部分的含义,后面的变量,nounlock是说是否会像古代科技那样,即使制造了一次也无法解锁相应科技栏,默认为否。numtogive则是说一次制造给几个物品。其它的,请自己查找Recipe.lua和Recipes.lua下的代码了解具体含义。另外,单机的Recipe没有buildertag,所以如果你希望你的专属物品只能被你的专属人物制造的话,应该把这部分的代码写入人物的构造函数里而不是写在modmain里。
Ingredient("lotus_leaf", 1, "images/inventoryimages/lotus_leaf.xml")
RECIPETABS['SAMANSHA_TAB'] = {str = "SAMANSHATAB", sort=999, icon = "samansha_tab.tex", icon_atlas = "images/samansha_tab.xml"}
在填完上面4个基本参数之后还不够,单机的Recipe函数,不接收被制作物品的xml路径,所以你需要先用一个变量来接收Recipe函数的返回值(物品的Recipe表),然后给这个表的atlas元素赋值图片路径。一个例子如下:
--用一个局部变量deerhatRecipe 接收Recipe函数的返回表,然后给表中的atlas元素赋上对应的xml路径。
local deerhatRecipe = Recipe("deerhat", {deerhorn, deerhat_1}, RECIPETABS.SAMANSHA_TAB, TECH.MAGIC_TWO)
deerhatRecipe.atlas = "images/inventoryimages/deerhat.xml"
联机版比起单机版,在这方面的支持更为给力。从上面单机版麻烦新制作栏添加方法以及图片xml路径设定就可以看出,官方原本是没打算让玩家添加新的可制作物品的。但联机版则受到官方鼓励。他们给出了mod用的两个函数:AddRecipeTab和AddRecipe。
添加新的制作栏,不需要像单机那样在RECIPETABS表里添加新元素了,我们有mod专用的函数:AddRecipeTab,变量依序为rec_str, rec_sort, rec_atlas, rec_icon, rec_owner_tag,分别代表制作栏名称,制作栏优先级(决定你的制作栏会被放在左侧边栏的第几个位置),制作栏图片的xml地址,制作栏图片的名字,会显示该制作栏的人物需要拥有的tag。
一个例子如下:
AddRecipeTab("samansha", 999, "images/hud/samansha_tab.xml", "samansha_tab.tex", "samansha")
AddRecipe函数的变量,与联机版的Recipe函数,在去掉Recipe的第一个变量self之后,是完全相同的。
所有的变量,依序是name, ingredients, tab, level, placer, min_spacing, nounlock, numtogive, builder_tag, atlas, image。
前面讲过的前4个参数,在这里的用法是一样的。而新增的后面三个参数builder_tag, atlas, image,则是方便了我们MOD制作。中间的placer,minspacing是为了可放置的建筑物设计的,此处暂且略过不提。
--中间有好几个nil,是因为这些参数可以不填
AddRecipe("lotus_umbrella", {lotus_leaf}, samansha_tab, TECH.SCIENCE_ONE, nil, nil, nil, nil, "samansha","images/inventoryimages/lotus_umbrella.xml","lotus_umbrella.tex")
以上两个函数,都属于mod API,所以必须要写在modmain里,否则无法运行,会报错。
至此,专属武器的基本框架就算制作完成了。想要测试效果的,可以打开MOD后,进入游戏,在控制台里输入c_give("myitem")
,便可获得该武器,或者根据你自己配置的Recipe,在制作栏里将其制作出来。下一篇讲如何给武器添加一些常用的功能,以及打造自己的个性武器。
接上一篇的最后,现在,做好了一把手持装备雏形的我们,要给这个装备设置伤害和特殊功能,使它能够当成一把武器来使用。要实现这一步,首先要了解,饥荒里的prefab和component的区别。
一个prefab,可以有多个组件,每个组件负责不同的功能。而添加组件,是通过AddComponent来完成的。比如说接着上一篇最后部分构造函数的代码。
local function fn()
local inst = CreateEntity()
local trans = inst.entity:AddTransform()
local anim = inst.entity:AddAnimState()
MakeInventoryPhysics(inst)
anim:SetBank("myitem_bank")
anim:SetBuild("myitem_build")
anim:PlayAnimation("idle")
inst:AddComponent("inventoryitem")--这就是一个组件,添加'物品栏物品'这个组件,让这个prefab能够放在物品栏里。下面两行则是设置这个组件的一些参数,代表着它在物品栏中的图片表示。
inst.components.inventoryitem.imagename = "myitem"
inst.components.inventoryitem.atlasname = "images/inventoryimages/myitem.xml"
inst:AddComponent("equippable")--这个组件是可装备组件,只有添加了这个组件,才能让物品可被装备。下面两行分别表示设置这个函数在被装备和被卸下时触发的函数。一般都会用这两个函数来设置人物的外观变化(比如把武器显示在人的手上)
inst.components.equippable:SetOnEquip( OnEquip )
inst.components.equippable:SetOnUnequip( OnUnequip )
return inst
end
那么,接下来就要设置武器的伤害和功能了。游戏本身赋予的组件相当丰富,几乎所有道具的功能,都是通过组件实现的。不同的道具,可能只在组件参数设置上有所区别。比如说黄宝石法杖能召唤晨星,绿宝石法杖能分解建筑,但它们都是通过spellcaster组件来实现这个功能的,只是对应的法术实现函数不一样罢了。
武器的属性,是由weapon组件实现的。只要添加两条代码,即可设置攻击力
inst:AddComponent("weapon")
inst.components.weapon:SetDamage(damage)--设置武器的攻击力damage
武器还有一个耐久度属性,这个是通过finiteuses属性来完成的。初始化设置的,一般会添加这三条代码
inst:AddComponent("finiteuses")--添加有限耐久组件,按次数算
inst.components.finiteuses:SetMaxUses(MaxUse)--设置最大耐久MaxUse
inst.components.finiteuses:SetUses(CanUse)--设置当前耐久CanUse
然后,我们可以给武器添加一些特别的功能,这个可以参考其他道具来做。比如说火把有个Lighter组件,通过这个组件就可以点火。橙宝石法杖有个blinkstaff组件,通过这个组件我们就能实现瞬移。
当你想要实现某个游戏中已有道具的功能,或者对这个功能做些许改动的时候,就可以先通过饥荒英文WIKIA找到你想要的道具对应的prefab字符串ID,(即Wikia里写的Debug Spawn),然后从这个字符串ID去搜索同名文件,进而找到这个道具的构造函数所在,在构造函数中,搜索AddComponent,找到你想要的功能对应的组件。
下面列一个表给出一些常见的组件,以及它们常用于哪些物品,有什么用途。
组件名 | 范例 | 解释 |
---|---|---|
tool | axe | 工具组件,像砍树、挖矿这些活动,都是通过向相应的工具(斧子,镐子)添加这个组件,并修改一些组件参数来实现的 |
shaver | razor | 刮胡子组件,有了这个就可以刮威尔逊的胡子以及牛毛了。 |
trap | trap | 陷阱组件,有了这个,就可以把兔子困在陷阱里了。 |
waterproofer | umbrella | 防水组件,有了这个,就可以给人物增加防雨能力,当防雨百分比>=100%时,就达到了完全防水的效果 |
其它的就不多说了,想要实现特殊功能,就自己去查找相应的代码吧。