饥荒模组制作笔记

本文章内容为本人在B站看UP主菜鸟老李的教学学习饥荒mod制作时做的笔记。B站地址为[

https://www.bilibili.com/video/BV1nv411T7Dy](https://www.bilibili.com/video/BV1nv411T7Dy)

一、采集功能模组

  • 全局变量储存在tuning.lua中,变量名称字母全部大写。引用变量时用:TUNING.STACK_SIZE_SMALLITEMTUNING是一个table(表格)类型的变量,例如:

    table1 = {变量1,变量2}
    

    引用变量1,则采用 table1.变量1 TUNING变量在tuning.lua文件中声明的变量,在 tuning.lua文件中TUNING表格变量中储存了大量要使用的全局变量。

    其中, SATCK_SIZE_SMALLITEM 是小尺寸物品堆叠上限数量。

  • 全局变量无关键字,直接定义,局部变量关键字 local。

  • Pickable:SetUp(product,regen,number)为设置采集数量的函数。

  • configuration_option = {  --模组变量配置
    
    {
    
    name = “name1”,  --modmain脚本里调用的变量,可以理解为变量名
    
    label = “label1”,  --游戏配置选项中显示的标签名
    
    options = {
    
    {description =40倍”, data = 40},
    
    --description为选项框中显示的字符,data为饥荒内置函数要获取的--饥荒游戏代码要使用的值
    
    {description =50倍”, data = 50},
    
    {description =60倍”, data = 60}
    
    },
    
    default = 40
    
    },
    
    {
    
    name = “name2”,  
            --modmain脚本里调用的变量,可以理解为变量名
    
    label = “label2”,  --游戏配置选项中显示的标签名
    
    options = {
    
    {description =40%”, data = 0.4},
    
    {description =60%”, data = 0.5},
    
    {description =80%”, data = 0.6}
    
    },
    
    default = 0.4
    
    }
    
    }
    

    模组配置代码写成这种表格形式,是由饥荒内置函数 GetModConfigData() 决定的。

    要使模组配置代码起作用,需要在 modmain.lua 文件里写代码:

    TUNING.SACK__SIZE_SMALLITEM=GetModConfigData(“name1”)
    

    这里GetModConfigData(“name1”)函数会返回参数name = “name1”的表格中的option表格中玩家在设置里选择的 description 对用的data的值。

  • ecs框架,Entity(实体), Component(组件), System(系统)。组件组合起来形成实体。

  • 所有的实体都可以在prefabs文件夹里找到。

  • 实体代码结构(以摘取的花瓣为例,文件为 petals.lua):

local assets =  --素材,决定在游戏里看到的样子

{         }

local prefabs =  --实体的分类,比如花瓣普通花瓣和恶魔花瓣

{         }
local function OnHaunt(inst, haunter) 
        --方法,定义某些组件里没有的特性,比--如在一定条件下,有几率普通花瓣变成恶魔花瓣。

local function fn()          
        --方法,初始化用的函数,决定功能改变功能一般在这个函数里改

Return Prefab(“petals”, fn, assert, prefabs)  --返回

​ [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-j3cCFVIX-1646965611396)(file:///C:\Users\YG\AppData\Local\Temp\ksohtml12196\wps1.jpg)]

  • Component组件修改方法

    1.源文件修改方法。

    2.通过模组:覆盖原始文件。

    3.通过AddComponentPostInit函数修改,方法高级但是难度大。这个函数的作用:游戏启动–mod文件覆盖原始文件–AddComponentPostInit修改就不用脚本文件覆盖,这就是高级的好处。AddComponentPostInit函数只修改整个组件文件里的一小部分, 而mod文件会覆盖掉整个文件。AddComponentPostInit函数写在modmain.lua文件

    AddComponentPostInit函数格式:AddComponentPostInit(参数1, 参数2)

    参数1 为要修改的组件,字符串为组件名称,” ”。

    参数2 为函数代码,要修改的组件内容,方法。参数2 可以是一段函数代码,也 可以先将函数创建写好,参数2 为函数名称。

    例如,

    local function newPickableSetUp(self)
    
    end
    
    AddComponentPostInit(“pickable”, newPickableSetUp)
    

    对pickable源文件中的函数进行修改

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-32M3tMSa-1646965611397)(file:///C:\Users\YG\AppData\Local\Temp\ksohtml12196\wps2.jpg)]

  • lua语法:每个组件里都有一个类。关于类的使用,在代码pickable注解版.lua中有解释。

  • Pickable:Pick(picker) 控制采集产出物品的函数

    修改采集所得物品时,主要修改的地方

    picker.component.inventory:GiveItem(SpawnPrefab(“log”), nil,self.inst:Getpostion())	 
    

    采集者.组件.库存:GiveItem(道具, nil, 坐标)

    道具:实体(由SpawnPrefab(“log”)产生),nil, 坐标self.inst.Getposition()

    坐标指的是背包里的坐标,不是地图里的坐标。


二、给人物添加采集组件

  • 人物修改相关,人物组成:

    • 组件—构成—预制件—人物模板—人物(各种人物不同)—tuning.lua。

      人物大量的属性都在tuning.lua文件的TUNING这个表里,这个表里的变量赋值可以直 接在modmain文件 里改。

      ​ [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hyusaUS1-1646965611397)(file:///C:\Users\YG\AppData\Local\Temp\ksohtml12196\wps3.jpg)]

    • 给人物添加变量,等级和经验值的思路:全部人物都添加,添加组件。

2.1新建一个level组件
  1. 创建一个组件文件,在模组文件夹,scripts\components\level.lua

  2. 打开文件编写代码,组件由Class函数创建,必须符合Class函数结构对3个参数的要求

  3. Class函数有三个参数

base 定义类的基础,可以是table,可以是函数

_ctor, nil空值

props 默认初始化的数据

  1. 最后把这个class函数返回,这也是组件必须的格式
ocal Level = Class(function(self, inst)  --初始化
	self.inst = inst
	self.level = 1
	self.exp = 0
end,
nil,
{})
return Level
2.3 给人物添加level组件
  1. 在modmain.lua里通过api函数给所有玩家都添加上这个组件,
AddPlayerPostInit(function(inst))--修改人物函数api
    if not inst.components.level then  --检查人物有没有这个组件
        inst:AddComponent("level")  --给人物添加这个组件level
    end
end)
  1. 人物修改函数AddPlayerPostInit(fn),第一个参数为fn函数,fn函数需满足一定的格式。其中一种格式为,其参数为要添加组件的人物实例,其内容为按一定条件筛选要添加组件的人物实例,并为其添加组件,添加组件是使用函数AddComponent("level")

  2. 组件命名开头大学。

2.4 采集经验值设计
  1. 采集组件里,采集触发位置,添加经验值累加
picker.components.level.exp = pick.components.level.exp + 1			
2.5 采集组件升级
  1. 升级设置,升级经验设置为 等级x等价x10
2.6 添加显示采集等级
  1. UI用户界面User Interface, 游戏里面显示等级和经验

  2. 窗口,游戏里所有窗口部件都在widgets文件夹里

  3. 窗口组件,窗口组件都以widgets文件夹里的widget.lua文件中的类Widget为基类,创建新的窗口部件。

    Class(Widget, function(self, owner)
    	Widget._ctor(self, "PickableLevelText")
    end)
    

    继承父类,定义构造函数。

    --首先在文件的头部加载Widget类
    local Widget = require "widgets/widget"  --Widget,基class
    local PickableLevelText = Class(Widget, function(self, owner)  
            --这里用Class来创建一个子类,第一个参数是父类,
    		--第二个参数是构造函数
    		--这里让PickableLevelText继承基类Widgets,
            --这样PickableLevelText就成了一个符合饥荒要求的窗口部件类
    	Widget._ctor(self,"PickableLevelText")	
            --这一句必须写在构造函数的第一句,否则会报错。这里调用了父类的构造函数
    end)	
    
    return PickableLevelText
    

    Widget是一个空窗口,子类继承父类后需要在子类里添加text部件。

  4. 添加text部件(指由Text类创建的部件),添加一个自己建立的text部件,部件名称为newText,作为属性添加到PickableLevelText里,newText是由Text类创建的实例。添加text部件采用函数self:AddChild(Text(BODYEXTFONT, 30, "LV"))

    --首先在文件的头部加载Widget类
    local Widget = require "widgets/widget"  --Widget,基class
    local Text = require "widgets/text"      --Text类,文本处理
    local PickableLevelText = Class(Widget, function(self, owner)  
            --这里用Class来创建一个子类,第一个参数是父类,
    		--第二个参数是构造函数
    		--这里让PickableLevelText继承基类Widgets,
            --这样PickableLevelText就成了一个符合饥荒要求的窗口部件类
    	Widget._ctor(self,"PickableLevelText")	
            --这一句必须写在构造函数的第一句,否则会报错。这里调用了父类的构造函数
    	self.newText = self:AddChild(Text(BODYEXTFONT, 30, "LV"))   
            --添加一个文本变量,接收Text实例
    																
            --Text是一个类,不是一个实例,Text(BODYEXTFONT, 30, "LV")
    																
            --才是一个实例,这就是为什么需要定义构造函数。
    																
            --猜测,Text()就是类Text的构造函数
    																
            --Text()与text文件里的
    																
            --Text = Class(Widget, function(self, font, size, text, colour)...)中
    																
            --的function(self, font, size, text, colour)相对应
    end)	
    
    return PickableLevelText
    
  5. 将PickableLevelText部件添加到游戏主窗口,widgets文件中的controls.lua文件决定游戏主窗口显示,需要对在modmain文件中其进行修改

    AddPlayerPostInit(function(inst)--修改人物函数api,其参数是一个函数。
                               --这个函数格式为以人物实例为参数,内容为筛选人物实例并添加组件
        if not inst.components.level then  --检查人物有没有这个组件
            inst:AddComponent("level")  --给人物添加这个组件level
        end
    end)
    
    local PickableLevelText = GLOBAL.require("widgets/PickableLevelText") 
                           --加载经验文本部件类
    
    local function addPickableLevelWidget(self, owner)
    	self.PickableLevelText = self:AddChild(PickableLevelText(self.owner)) 
             	 --为controls添加PickableLevelText窗口部件实例
    			 --猜测PickableLevelText(self.owner)是由
    			 --PickableLevelText类的构造函数构造出来的实例
    			 --与PickableLevelText = Class(Widget, function(self, owner)...)
    			 --的function(self, owner)相对应
    	
        self.PickableLevelText:SetHAnchor(0) 
                     --设置原点x坐标位置,0、1、2分别对应屏幕中、左、右
    	self.PickableLevelText:SetVAnchor(1) 
                     --设置原点y坐标位置,0、1、2分别对应屏幕中、上、下
    	self.PickableLevelText:SetPosition(70, -50, 0) 
                -- 设置PickableLevelText窗口相对于原点的偏移量,70表示相右,-50表示向下
    end
    
    --这个函数是官方的MOD API,用于修改游戏中的类的构造函数。第一个参数是类的文件路径,根目录为------scripts。第二个为自定义函数
    --自定义函数的结构需要满足AddClassPostConstruct函数对参数的要求。
    AddClassPostConstruct("widgets/controls", addPickableLevelWidget)
    
2.7 UI更新

接下来的方法只能用于离线版,不能打开洞穴。

  1. 在我们写的widgets/pickablelevelText.lua文件里添加一个方法

    --定义一个更新文本内容的方法(只能用于不开洞穴的离线版)
    function PickableLevelText:OnUpdate(uiText)
    	self.newText:SetString(uiText)
    end
    
  2. modmain.lua文件里添加这个调用来更新

    1. 添加一个时钟来更新

      • 时钟也是一个实体

      • 给实体一个时钟功能

      • DoperiodicTask(时间间隔,函数),字面意思是执行周期性任务

        local inst = GLOBAL.CreateEntity()   --饥荒自带的创建实体的函数
        	inst:DoPeriodicTask(1, function()
        		--更新文本信息
        		local level = owner.components.level.level
        		local levelEXP = owner.components.level.exp
        		local uiText = level.."	"..levelEXP.."/"..level*level*10
        		self.PickableLevelText:OnUpdate(uiText)
        	end)
        
2.8 采集数据存档
  • 退出游戏后再进入游戏,经验丢失。需要保存和加载等级经验数据。

    1. 给level组件写一个保存数据的方法

      OnSave() ,返回一个表

      --保存游戏是将当前人物的等级保存下来
      function Level:OnSave()      --保存方法函数,返回必须是一个表,这是固定格式
      	return {
      	level = self.level,
      	exp = self.exp
      	}
      end
      
    2. 给level组件写一个加载数据方法

      OnLoad(data), data是个表

      --加载有游戏时将保存的等级加载进来
      function Level:OnLoad(data)   --加载方法函数,参数必须是一个表,这是固定格式
      	if data ~= nil then       --防止没有data数据读取时游戏崩溃
      		if data.level then
      			self.level = data.level
      		end
      		if data.exp then
      			self.exp = data.exp
      		end
      	end
      end
      

三、释放(触发)技能

3.1技能背景
  • 经验只满足条件,执行技能功能 ,经验值到10就触发技能
  • 采集组件
    • 采集触发经验+1
    • 判断经验值 等于10触发
    • 经验归零
  • UI部分,显示当前经验值
  • 技能具体功能,随机给一个物品
    • 随机
    • 可以放入背包的物品
3.2 随机物品
  • 建立一个可以放入背包的物品的表

  • 在level组件里填加一个随机物品的方法

    --随机给一个物品方法
    function Level:Give()
    	local itemTable = {
    		"cutgrass",
    		"log",
    		"pinecone",
    		"charcoal",
    		"flint",
    		"silk",
    	}
    	local num = math.random(#itemTable)   --#itemTable表示取表的长度
    	return = itemTable[num]
    
  • 技能触发时,得到随机物品

    if picker.components.level.exp >= 10 then   --满足条件触发技能
    	local = randomItem = picker.components.level:Give()   --读取随机物品
        picker.components.inventory:GiveItem(SpawnPrefab(randomItem), nil, self.inst:GetPosition())  --给物品
    	picker.components.level.exp = 0
    	end
    

四、实体

  • 饥荒里实体都在prefab文件夹里

  • 创建预制件,使用函数Prefab("prefabName", fn)

    Prefab(参数1(名称), 参数2(函数),参数3(素材))

    local assets =   --素材 
    {       }
    local function fn()  --控制属性,功能组件的函数
    return Prefab("log", fn, assets)
    
  • 构造fn函数

    1. CreateEntity()主要就是创建一个实体,这个实体自身也带了一些组件
      • Transform:变换组件,控制Prefab的位置、方向、缩放等
      • AnimeState:动画组件,控制Prefab贴图(Build),动画集合(Bank)和动画播放(Animation)
      • Phiysics:物理组件,控制Prefab的物理行为,比如速度,碰撞类型等等
      • Light:光照组件,添加该组件可使得Prefab成为一个光源
      • Network:网络组件,添加与否决定了一个Prefab在主机上生成时,是否会被客户端看到
      • MapEntity:地图实体组件,使用该组件可以为Prefab在小地图上创建一个小图标
      • SoundEmitter:声音组件,控制Prefab的声音集合和播放

五、Prefab的修改

  • AddPrefabPostInit(参数1,参数2)

    参数1:要修改的prefab的名字——字符串

    参数2:fn函数,预制件里修改的内容

  • 在modmain.lua文件里用AddPrefabPostInit()对Prefab进行修改

  • Component修改的是所用拥有这个组件的实体,Prefab修改的是单个实体

  • 修改长矛

    --修改长矛攻击
    local function modspear(inst)
    	inst.components.weapon:SetDamage(150)       --设置攻击力
    	inst.components.finiteuses:SetMaxUses(999)  --耐久上限
    	inst.components.finiteuses:SetUses(999)     --当前耐久,即制造出来时耐久
    	inst.components.SetRange(14,14+2)           --设置攻击范围和命中范围
    end
    
    AddPrefabPostInit("spear", modspear)
    

prefab的名字——字符串

参数2:fn函数,预制件里修改的内容

  • 在modmain.lua文件里用AddPrefabPostInit()对Prefab进行修改

  • Component修改的是所用拥有这个组件的实体,Prefab修改的是单个实体

  • 修改长矛

    --修改长矛攻击
    local function modspear(inst)
    	inst.components.weapon:SetDamage(150)       --设置攻击力
    	inst.components.finiteuses:SetMaxUses(999)  --耐久上限
    	inst.components.finiteuses:SetUses(999)     --当前耐久,即制造出来时耐久
    	inst.components.SetRange(14,14+2)           --设置攻击范围和命中范围
    end
    
    AddPrefabPostInit("spear", modspear)
    
Logo

技术共进,成长同行——讯飞AI开发者社区

更多推荐