饥荒联机版Mod开发——常用inst方法(八)

  • 前言
  • 生成实体
  • 监听/推送事件
  • 使用标签
  • 增删组件
    • 网络组件
  • 定时/阶段任务
  • 回调函数
  • 父子实体
  • 平台
  • 删除
  • 位置,角度
  • 显示/隐藏
  • 判断
  • 大脑
  • 状态图
  • 皮肤
  • 地图
  • 物理
  • 传送门

前言

在饥荒联机版Mod开发——Class, Prefab, component,debug(四)
中我们简单介绍了游戏实体(Entity)和组件的使用方法,在这一章里我们将学习Entity的常用方法,想了解更多也可以去看文中提到的源代码

生成实体

生成实体可分为两种情况,一种是控制台生成,另一种是代码里生成。前者是我们进游戏后调试用,后者是日常写代码时用。

控制台生成预设物实体

--consolecommands.lua
--在鼠标位置生成预设物实体,如猪人 "pigman"
function c_spawn(prefab, count=1) ... end
--给予玩家可放进物品栏的预设物实体,如树枝 "twigs"
function c_give(prefab, count=1) ... end

代码里生成预设物实体、实体

--mainfunctions.lua
--生成并返回预设物实体,一般只需要个name。如果creator没有对应皮肤,则显示默认皮肤
function SpawnPrefab(name, skin, skin_id, creator) ... end
--在原本的实体位置生成预设物实体,并删除原本的实体,一般只需要前两个参数
function ReplacePrefab(original_inst, name, skin, skin_id, creator) ... end--生成并返回实体,name可省,常见于各prefab的fn中
function CreateEntity(name)local ent = TheSim:CreateEntity()   --C层的Entity数据,存放在inst.entitylocal guid = ent:GetGUID()  --GUID独一无二的标志数字local scr = EntityScript(ent)   --entityscript.lua,这就是instif name ~= nil thenscr.name = nameendEnts[guid] = scr   --全部Entity都放到Ents这个全局表里(声明在main.lua)NumEnts = NumEnts + 1 --全部Entity的数量(声明在main.lua)return scr    --返回inst
end

CreateEntity中我们可以看成,常见的 inst:XXX() 实际调用的是entityscript.lua中的方法

此外mainfunctions.lua中还定义了其他的全局函数,如
获取时间的GetTick()、
游戏开始时的Start()、保存游戏SaveGame(…),关闭游戏Shutdown()、SaveAndShutdown()
游戏回调OnFocusLost()、OnFocusGained()、
Entity回调OnEntitySleep(),OnEntityWake,OnPhysicsWake,OnPhysicsSleep、
GUID处理函数GetEntityString等; inst.GUID

监听/推送事件

事件作为脚本中传递信息的重要途径,在降低代码复杂度,提供可扩展型上发挥着至关重要的作用。本质是把函数(fn)先存起来(ListenForEvent),在特定的时候(PushEvent)再传入参数(source, data)来调用函数(fn)。

--entityscript.lua--监听/取消监听事件
--event:string,独一无二的事件名,对应inst:PushEvent中的event
--fn:监听的函数,参数是 (source, data),source对应调用PushEvent的Entity,data对应PushEvent时的data,也可以print出来看看data是什么
--source:被监听的实体,默认监听自身
inst:ListenForEvent(event, fn, source=inst)
inst:RemoveEventCallback(event, fn, source=inst)
inst:RemoveAllEventCallbacks()--推送事件,运行fn
--event:string,独一无二的事件名,mod的event推荐加个前缀
--data:any,一般是个table
--如果inst有sg(stategraph状态图)且sg在监听这个事件,也会调用 inst.sg:PushEvent(event, data)
--如果inst有brain(大脑/AI)也会调用 inst.brain:PushEvent(event, data)
inst:PushEvent(event, data)--table的key可以是任意非nil值,通过table[key]来访问,key是字符串时可以写成table.key
--当前source被监听的事件列表 source.event_listeners[event][inst] = {fn1, fn2, ...}
--当前inst在监听的事件列表 inst.event_listening[event][source] = {fn1, fn2, ...}

在监听世界(TheWorld)时,可以把source赋值为TheWorld。不过如果要监听世界的状态(worldstate)(时间,洞穴时间,月圆,天气,季节,温度,湿度,下雪,下雨等)
更推荐使用下面的函数

--entityscript.lua--TheWorld的预设物在prefabs/world.lua
--监听/取消监听世界TheWorld.state中的状态 (components/worldstate)
--var:components/worldstate.lua中 SetVariable(var, val, togglename)
--fn:一般参数为(inst, val),不过start或stop开头的var,只有inst。
inst:WatchWorldState(var, fn)
inst:StopWatchingWorldState(var, fn)
inst:StopAllWatchingWorldStates()--inst.worldstatewatching[var] = {fn1, fn2, ...}
--_watchers[var][inst] = { {fn, inst}, ... }--举个例子components/worldstate.lua中
--SetVariable(var, val, togglename)
--有第三个参数时,有start和stop开头var  (val and "start" or "stop")..togglename
SetVariable("cavephase", phase)
-->  var="cavephase",  fn的val=phase,洞穴白天到黄昏等时期变化时推送
SetVariable("iscaveday", phase == "day", "caveday")
--> var="iscaveday"    fn第二个参数val=(phase == "day"),一个boolean
--> var="startcaveday",val为true时推送,fn参数只有inst
--> var="stopcavaday",val为false时推送,fn参数只有inst

注:

  • TheWorld是Entity,赋值在prefabs/world.lua,负责管理世界、地图、时钟、玩家生成等。
  • 判断是否是地下世界,TheWorld:HasTag(“cave”)
  • The开头及Ents等全局变量(声明在main.lua),可以在游戏中直接访问到
  • 在modmain中也可以访问到main中的全局变量,不过直接访问时可能还没赋值,所以一般写在
    AddGamePostInit(fn()) --先
    AddSimPostInit(fn()) --后,和单机不同,fn没有参数,ThePlayer也没赋值
    如果需要访问ThePlayer,用下面函数
    AddPlayerPostInit(fn(player)) --在fn中用ThePlayer==player来判断是否当前玩家

使用标签

标签常用于Component判断Entity,也影响着生物的AI等。
_开头的标签比较特殊,在下面的组件部分介绍。
常见的tags如下:

  • NOCLICK:不可点击物体
  • FX:特效
  • lightningtarget:闪电目标(移除就不不会被雷劈)
  • electricdamageimmune:电伤害免疫(机器人免疫电伤害)
  • irreplaceable:无法替代,玩家离开世界自动掉落(眼骨等)
  • player、playerghost:玩家状态(也可以用inst.components.health:IsDead()来判断)
  • scarytoprey:吓跑小动物(移除就不会吓跑小动物)
--tag: string
inst:AddTag(tag)
inst:RemoveTag(tag)
inst:HasTag(tag)
--tags = {"tag1", "tag2", ...}
inst:HasTags(tags)  --拥有全部
inst:HasOneOfTags(tags) --拥有其中一个标签

增删组件

--name:string, 对应components中文件夹中的文件名,组件的使用看第四章
inst:AddComponent(name) --有_replica的同名组件会自动添加(服务器)
inst:RemoveComponent(name)--inst.components.name
--inst.repica.name

网络组件

以_replica的结尾同名组件 ,用网络变量(netvars.lua)进行服务器和客户端之间的通信,需要服务器和客户端都添加以_replica的结尾同名组件。
这里先讲下添加组件流程,具体使用以后出个网络通信相关的教程,感兴趣的也可以先去看
官方的netvars教程
注:动作的网络变量了entityscript.lua的AddNetwork(),其他的大部分在player_classified.lua

以玩家的health组件为例子(服务器修改血量,通知)

local inst = CreateEntity()
inst.entity:AddNetwork()    --网络通信当然要添加网络了
inst:AddTag("_health")    --添加网络组件标签
inst.entity:SetPristine()   --客户端根据添加的_开头的tag,添加xxx_replica组件
if not TheWorld.ismastersim then return inst end    --客户端返回,下面是仅服务器代码
inst:RemoveTag("_health") --移除网络组件标签,等AddComponent会再次加上。官方书写习惯,不删问题应该也不大
inst:AddComponent("health")   --服务器添加health和health_replica组件,和_health标签。
--注:客户端只需要知道玩家的血量,其他生物的血量并不需要知道,所以其他生物的预设物fn中
--并不会有inst:AddTag("_health") 和 inst:RemoveTag("_health") 这两句

定时/阶段任务

--entityscript.lua   scheduler.lua--下面4个函数的返回值都是Periodic  可通过 :Cancel() 取消任务
--定时任务,time秒后调用 fn(inst, ...)。仅调用一次,不需要手动取消
--注:inst:DoTaskInTime(0,...) 时会在下一帧调用; Sprite中是毫秒
inst:DoTaskInTime(time, fn, ...)    --阶段任务,initialdelay秒后调用fn(inst, ...),之后每隔time秒调用一次fn,需要手动取消
--一般都是 inst.task = inst:DoPeriodicTask(...),某个时候 inst.task:Cancel()
inst:DoPeriodicTask(time, fn, initialdelay=time, ...)  --和上面的类似,不过定时不受世界暂停时影响
inst:DoStaticTaskInTime(time, fn, ...)
inst:DoStaticPeriodicTask(time, fn, initialdelay, ...)  inst:CancelAllPendingTasks()    --取消上面所以的定时任务

回调函数

-------- entityscript.lua---------
Fn:对应函数 XXXCb:回调函数,非nil时调用
一般都是先调用ComponentCb,之后再调用EntityCb,除非是Pre开头的
EntityCb常规写法: inst.OnXXX = function(inst, …) … end
ComponentCb常规写法:function Cmpname:OnXXX(…) … end

  • refs:引用的Entity列表或nil,{Entity1, Entity2, …}
  • cmpdata:一般是个table,仅保存数值,不保存引用
  • newents:重新开服时生成的Entitys,一般用不上
  • builder:一般是玩家的Entity
  • dt:deltatime,距离上次更新的时间
Fn EntityCb ComponentCb
inst:GetPersistData() inst:OnSave(data) -> refs cmp:OnSave() -> cmpdata, refs
inst:SetPersistData(data, newents) inst:OnPreLoad(data, newents) inst:OnLoad(data, newents) cmp:OnLoad(cmpdata, newents)
inst:LoadPostPass(newents, savedata) inst:OnLoadPostPass(newents, savedata) cmp:LoadPostPass(newents, cmpdata)
inst:OnBuilt(builder) inst:OnBuiltFn(builder) cmp:OnBuilt(builder)
inst:Remove() inst:OnRemoveEntity() cmp:OnRemoveEntity()
inst:LongUpdate(dt) inst:OnLongUpdate(dt) cmp:LongUpdate(dt)

--------Update:update.lua--------
dt: deltatime,距离上次更新的时间

  • WallUpdate:墙壁更新
  • Update:日常更新
  • StaticUpdate:世界暂停时开始更新
  • LongUpdate:长时间间隔的更新,如进出洞穴,跳天数等
Fn EntityCb ComponentCb
WallUpdate(dt) - cmp:OnWallUpdate(dt)
Update(dt) - cmp:OnUpdate(dt)
StaticUpdate(dt) - cmp:OnStaticUpdate(0)
LongUpdate(dt, ignore_player) inst:OnLongUpdate(dt) cmp:LongUpdate(dt)

--------Player:player_common.lua-----------.
玩家特有回调
inst.OnNewSpawn = function() … end
inst.OnDespawn = function() … end

父子实体

--entityscript.lua
--child:Entity
inst:AddChild(child)
inst:RemoveChild(child)
--inst.children[child] = true
--child.parent = inst  child.platform = nil

平台

当前只用在船上,让玩家随船移动

--entityscript.lua
--child: Entity
inst:AddPlatformFollower(child)
inst:RemovePlatformFollower(child)
inst:GetPlatformFollowers()
inst:GetCurrentPlatform()--inst.platformfollowers[child] = true
--child.platform = inst        child.parent = nil

删除

--移除自身和子Entity,从父Entity的孩子中移除
--触发事件onremove,OnRemoveEntity回调
--移除所以监听、组件、定时和阶段任务
inst:Remove()
inst:IsValid()  --正常返true,被Remove返false

位置,角度

inst:GetPosition()   --> Point(inst.Transform:GetWorldPosition())  一个table
inst:GetRotation() --> inst.Transform:GetRotation()inst:FacePoint(x, y, z)   --> 面向某点
inst:ForceFacePoint(x, y, z)  --> 强制面向某点
inst:FaceAwayFromPoint(dest, force)--DistanceSq: 距离的平方,少了sqrt,减少计算量
inst:GetDistanceSqToInst(inst) --> 距离的平方
inst:IsNear(otherinst, dist) --> inst:GetDistanceSqToInst(otherinst) < dist*dist
inst:GetDistanceSqToPoint(x, y, z)  --> 距离的平方
inst:IsNearPlayer(range, isalive)   --> range半径内是否有玩家
inst:GetNearestPlayer(isalive)  --> 最近的玩家
inst:GetDistanceSqToClosestPlayer(isalive)  --> 距离最近的玩家的距离的平方

显示/隐藏

--显示/隐藏,仅改变显示
inst:Show()
inst:Hide()--显示到屏幕,常用于物品被移出物品栏
--IsInLimbo()->false inst:Show()
--开始brain,sg,Physics,Light,AnimState,DynamicShadow,MiniMapEntity
--inst:PushEvent("exitlimbo")
inst:ReturnToScene()--从屏幕隐藏中,常用物品被放进物品栏
--IsInLimbo()->true      inst:Hide()
--停止brain,sg,Physics,Light,AnimState,DynamicShadow,MiniMapEntity
--inst:PushEvent("enterlimbo")
inst::RemoveFromScene()

判断

inst:IsOnWater() --是否在水上,即没船且脚下是海
inst:IsInLimbo()    --是否在物品栏,仅在mastersim(服务器)有效,客户端用INLIMBO标签判断?
inst:GetIsWet()     --是否是湿的,服务器客户端都可以使用
inst:IsInLight()    --是否在光照内
inst:IsValid()      --正常返true,被Remove返false

大脑

--brainfn: require("brains/xxxbrain")
inst:SetBrain(brainfn)
inst:StopBrain()
inst:RestartBrain()

状态图

--name: "SGXXX"        stategraphs文件夹下的文件名
inst:SetStateGraph(name)
inst:ClearStateGraph()

皮肤

--entityscript.lua
inst:GetSkinBuild()
inst:GetSkinName()
--inst.AnimState:SetSkin(build_name, def_build)

地图

--entityscript.lua
--设置参数,具体应用在components/map.lua
inst:SetDeployExtraSpacing(spacing)
inst:SetTerraformExtraSpacing(spacing)
inst:SetGroundTargetBlockerRadius(radius)inst:IsOnValidGround() --是否在地面上
inst:IsOnOcean(allow_boats) --是否在海上
inst:IsOnPassablePoint(include_water, floating_platforms_are_not_passable)  --是否可通过某点inst:GetCurrentTileType()  --获得当前地皮,如果要获得有效地皮先判断inst:IsOnValidGround()

物理

设置物理的时候,一般用的是 standardcomponents.lua 里的 MakeXXXPhysics,不过偶尔有需要重新设置物理碰撞半径的时候

--entityscript.lua
inst:SetPhysicsRadiusOverride(radius)   --设置覆盖的物理碰撞半径
inst:GetPhysicsRadius(default)  --返回物理碰撞半径或default

传送门

→饥荒联机版Mod开发——制作栏(九)
←饥荒联机版Mod开发——制作可入锅,烹饪,凉干的食物(七)

饥荒联机版Mod开发——常用inst方法(八)相关推荐

  1. 饥荒联机版Mod开发——制作可入锅,烹饪,凉干的食物(七)

    饥荒联机版Mod开发--制作可入锅,烹饪,凉干的食物(七) 可入锅 可烹饪 可凉干 传送门 可入锅 参考:cooking.lua 先来看一下官方代码 --names:{"prefab1&qu ...

  2. 饥荒联机版Mod开发——Class, Prefab, component,debug(四)

    饥荒联机版Mod开发--class, prefab, component,debug(四) Class的使用方法 Prefab component Entity Component Normal Co ...

  3. 饥荒联机版Mod开发——modmain(五)

    饥荒联机版Mod开发--modmain(五) 前言 modmain环境 常用方法 设置环境具体流程 mods.lua modutil.lua 传送门 前言 在modmain中我们可以通过 Prefab ...

  4. 饥荒联机版Mod开发——衣服(十一)

    饥荒联机版Mod开发--衣服(十一) 前言 总览与下载 modmain prefab 动画 前言 饥荒里面装备栏有三个地方,手,身体,头.上一期我们讲了戴头上的帽子,这期我们讲讲穿在身上的衣服.事实上 ...

  5. 饥荒联机版Mod开发——配置代码环境(二)

    饥荒联机版Mod开发--配置代码环境(二) 前言 下载VS Code和Lua插件 建立工作区 配置Lua插件 Git和GitHub(可选) 排除多余文件 删除scripts里多余文件 VS Code快 ...

  6. 饥荒联机版Mod开发——准备工具(一)

    饥荒联机版Mod开发--准备工具 前言 工具下载 工具功能和使用 动画 c_start:反解压动画 Sprite:制作动画 打包工具:把动画再打包回去 贴图 TEXTool:查找/反解压tex tex ...

  7. 饥荒联机版Mod开发——两种帽子(十)

    饥荒联机版Mod开发--两种帽子(十) 前言 总览与下载 动画 代码 modmain 露头类帽子 基本的预设物框架 穿戴 可交易 腐烂及可放冰箱 总的代码 不露头类帽子 差异 基本代码 耐久 其他功能 ...

  8. 饥荒联机版Mod开发——制作烹饪锅食物(六)

    饥荒联机版Mod开发--制作烹饪锅食物(六) 前言 准备工作 编写菜谱 制作预设物 添加菜谱 传送门 前言 核心组件及其流程如下: 材料 -> 烹饪锅(stewer) -> 食物(吃edi ...

  9. 饥荒联机版服务器mod模组在哪个文件夹,饥荒联机版MOD使用图文教程_饥荒联机版MOD怎么用_牛游戏网...

    饥荒联机版相信大家都玩得不亦乐乎,在饥荒中使用MOD也是一大乐趣,不少萌新可能还不知道饥荒联机版怎么使用MOD,饥荒联机版MOD要怎么安装使用呢,下面小编就为大家带来了饥荒联机版MOD使用图文教程,给 ...

最新文章

  1. 基于OpenCV的透视图转化为不同平面
  2. 怎样才能高效的在家办公或者远程办公呢?
  3. redis命令操作(1)
  4. 论图书营销中的“托”
  5. 编程竞赛控制系统(PC2)使用说明书
  6. 用XSLT和XML改进Struts
  7. 微信图片显示定位服务器,姚晓雷:通过一张微信图片定位对方具体位置的方法...
  8. 如何运用舆情分析系统分析网络舆情数据?
  9. POJ-Bound Found | 尺取法+绝对值特性
  10. [BZOJ3772]精神污染(主席树)
  11. 3、管理员添加内容的实现
  12. linux sh文件执行情况,Linux下SH执行
  13. 失业找不到工作,很焦虑怎么办?
  14. Android开发k歌软件,安卓电视k歌软件哪个好?
  15. C语言中strlen函数功能及用法
  16. 成都玖益科技:店铺流量怎么提升
  17. 西行漫记(5):关于故事的故事
  18. cf: Ehab and Path-etic MEXs
  19. 写一本书作者到底能拿到多少稿酬?
  20. 局域网IP地址的分配、管理和设置(图)

热门文章

  1. python 爬取 mm131 图片
  2. 弹性力学——一些知识
  3. 西安交通大学本科毕业论文答辩和论文选题PPT模板
  4. 2017word计算机操作题,2017职称计算机考试Word操作试题及答案
  5. 2.45GHz天线初始尺寸设定
  6. 英文期刊名中常见的单词缩写 (个人整理不全面),后续还会整理。。。。
  7. 气相色谱仪常用的色谱定量方法
  8. python语言训练教程_Houdini中Python编程语言核心技能训练视频教程
  9. ANSYS stl文件导入(SpaceClaim)
  10. Tensorflow+YOLO V4框架使用教程+YOLO V4获取识别框高度+基于相似三角形算法的物体距离测量