前言
在游戏制作用,UI的代码架构是固定的。为了快速开发,只需要获得一个完整的UI结构代码,然后编写对应的业务逻辑即可。所以,自动化生成模板代码是一件必不可少的事情。
环境
UI的架构通常使用MVC的结构,这次就演示V的生成,其他模板的生成流程其实也大同小异。代码就不加功能了,重点放到生成代码上面去。
思路
- 制作模板代码,设置标志位。
- 生成->得到组件,遍历模板,在标志位后添加组件处理。
更新->标志位范围的代码不保存,重新生成组件代码。 - 根据指定生成路径,生成代码。
View
public class TempletView
{
public const string Name = "TempletView";
public GameObject m_GameObject = null;
public Transform m_Transform = null;
public void OnInit(GameObject root)
{
m_GameObject = root;
m_Transform = m_GameObject.transform;
InitUI();
}
}
private void InitUI()
{
//Start
//End
}
创建代码
StringBuilder codeStringBuilder = new StringBuilder();
using(StreamReader reader = File.OpenText(TempletViewPath)
{
string lineReader = string.Empty;
while ((lineReader = reader.ReadLine()) != null)
{
if(lineReader .Contains("TempletView ")
{
lineReader = lineReader.replace("TempletView",prefabName);
}
codeStringBuilder. Append(lineReader);
if(lineReader.Contains("Transform m_Transform")
{
for(int index = 0;index<Components.count;index++)
{
codeStringBuilder.Append($"m_{Components[index].name}_{Components[index].getType().Name} = null;\n");
}
}
if(lineReader.Contains("Start")
{
for(int index = 0;index<Components.count;index++)
{
codeStringBuilder.Append($"m_{Components[index].name}_{Components[index].getType().Name} = m_Transform.Find("{Components[index].name}").gameobject.GetComponent<{Components[index].getType().Name}>();\n");
}
}
}
}
if(codeStringBuilder.Length>0)
{
StreamWriter writter = File.CreateText(UIFilePath);
writter.Write(codeStringBuilder.toString());
writter.Close();
}
更新代码
StringBuilder codeStringBuilder = new StringBuilder();
using(StreamReader reader = File.OpenText(UIFilePath)
{
string lineReader = string.Empty;
bool replace =false;
while ((lineReader = reader.ReadLine()) != null)
{
if(!replace)
{
codeStringBuilder. Append(lineReader);
}
if(lineReader.Contains("Start") || lineReader.Contains("Transform m_Transform"))
{
replace = true;
}
if(lineReader.Contains("void OnInit"))
{
replace = false;
for(int index = 0;index<Components.count;index++)
{
codeStringBuilder.Append($"m_{Components[index].name}_{Components[index].getType().Name} = null;\n");
}
codeStringBuilder.Append("\n\n");
codeStringBuilder.Append(lineReader);
}
if(lineReader.Contains("End")
{
replace = false;
for(int index = 0;index<Components.count;index++)
{
codeStringBuilder.Append($"m_{Components[index].name}_{Components[index].getType().Name} = m_Transform.Find("{Components[index].name}").gameobject.GetComponent<{Components[index].getType().Name}>();");
}
codeStringBuilder.Append(lineReader);
}
}
}
if(codeStringBuilder.Length>0)
{
StreamWriter writter = File.CreateText(UIFilePath);
writter.Write(codeStringBuilder.toString());
writter.Close();
}
注意点
- StreamWriter 打开了必须要关闭,否则该文件一直会处于使用状态。再运行就跑不了,只能重开UNITY。这也是为什么我放到最后统一搞,这样上面无论怎么崩溃都不会影响写入。
- File的使用要小心,看清楚是打开还是复写,否则异常中断时,文件内容可能就被清空了。。2.File的使用要小心,看清楚是打开还是复写,否则异常中断时,文件内容可能就被清空了。。
- 使用using命名空间,可以控制StreamReader的使用范围,免得被其他地方意外调用。
- 文档的更新需要依赖标志,如例子中的“Start‘和‘End’。这个标志需要是唯一的,而且不可被删除,否则就更新不了了。