需求: 在实际项目中,往往我们需要在代码中引用一些子节点的GameObject或者Component,这些引用在代码中是写死的,然而在项目开发中美工人员需要在迭代的时候调整子节点的层级、顺序,这对程序来说代码将难以维护。 此时我们需要一个自动化工具,用于检查代码中使用子节点引用的代码,这些引用是否还可以正确引用,对于无法正确引用的组件、游戏物体进行警告提示。
实现思路: 基于上述需求,来进行分析
- 使用一个配置文件,将引用存入一个结构体
- 实现一个解析器,将配置文件中的结构体,通过键值的方式让键与具体的对应引用对应与,使用时使用解析器提供的方法,将键作为参数
- 实现一个Unity编译器拓展的方法,遍历全部的Prefab,并找到其对应的_prefab.lua的配置文件,遍历其中的结构体并进行解析,将无法引用的失效路径输出警告
1.解析器的实现 使用多态的特性,让不同的解析器继承一个基类
代码语言:javascript复制local parserBase = {}
function parserBase:Find()
print("parserBase Find")
end
function parserBase:New(o)
o = o or {}
self.__index = self
setmetatable(o, self)
return o
end
不同类型解析器的具体实现,这里列举一个按钮解析器。按钮解析器继承解析器基类,根据根节点和路径找到子物体,在查找是否有对应的UI.Button组件。最后将解析器(方法)添加进入parsers的表中。
代码语言:javascript复制local buttonParser = parserBase:New()
function buttonParser:Find(transform, path)
local child = transform:Find(path)
if child ~= nil then
local btn = child:GetComponent(UI.Button)
if btn ~= nil then
Debug.Log("Success Find Button")
return btn
else
Debug.LogWarning("Cant Find UI.Button Component: " .. gameObject.name .. "/" .. path)
end
else
Debug.LogWarning("Cant Find GameObject: " .. gameObject.name .. "/" .. path)
end
end
parsers["buttonParser"] = buttonParser.Find
2.配置文件的定义 配置文件中存放引用,键为一个自定义的名称,值为一个表,包括解析器使用哪个,子物体的路径。
代码语言:javascript复制local parsers = require "CustomParser"
local commonPanelTable = {
["expBarButton"] = {parser = parsers.buttonParser, path = "Viewport/Content/ExperienceBar/Button"},
["TitleBar"] = {parser = parsers.goParser , path = "Viewport/Content/TitleBar",subStruct = require "TitleBar_prefab"},
["TitleBar_Transform"] = {parser = parsers.goParser , path = "Viewport/Content/TitleBar"},
}
return commonPanelTable
在一个结构下面可能有嵌套的结构,嵌套的结构为一个表,此表的结构和正常的一样
代码语言:javascript复制local parsers = require "CustomParser"
local titleBarTable = {
["Text"] = {parser = parsers.textParser, path = "Text"},
}
return titleBarTable
3.通过解析器,解析一个配置文件,通过传入一个根节点和一个配置文件的table,得到一个可以直接通过索引直接使用的table
代码语言:javascript复制function PrefabLuaParserTable:Parser(transform, prefabTab)
local outputTab = {}
for k, subTab in pairs(prefabTab) do
local prefabSubTab = subTab
outputTab[k] = prefabSubTab:parser(transform, prefabSubTab.path)
if subTab.subStruct ~= nil then
local subTransform = outputTab[k]
outputTab[k] = self:Parser(subTransform, subTab.subStruct)
end
end
return outputTab
end
具体使用实例
代码语言:javascript复制local parserTab = self:Parser(commonPanel.transform, require "CommonPanel_prefab")
local cusText = parserTab["TitleBar"]["Text"]
4.编译器拓展,遍历全部的prefab,并找到其对应的_prefab.lua文件 调用上面的解析方法,来判断是否有引用已经无法使用了。
代码语言:javascript复制function PrefabLuaParserTable:TraversePrefab(relativePath)
local parserTool = LuaCallCSTool.StaticIT()
local files = parserTool:FindAllPatternFiles("t:Prefab")
for i = 1, #files do
local go = parserTool:LoadAssetToGameObject(files[i])
local parserTool = LuaCallCSTool.StaticIT()
local prefabLuaFileName = relativePath .. go.name .. "_prefab"
if io.open(prefabLuaFileName..".lua","r") then
local prefabTab = require(prefabLuaFileName)
if prefabTab ~= nil then
print(go.name)
local parserTab = self:Parser(go.transform, prefabTab)
end
end
end
end