在我们的项目过程中经常会遇到某个组件迭代的过程,那么在废弃旧组件,替换新组件的时候,就可以使用一个通用组件替换工具完成一键替换的功能。
设计图如下:

基类ReplaceComponentBase泛型类,将旧组件和新组件传递进去。
public abstract class ReplaceComponentBase<TOldComponent, TNewComponent>
where TOldComponent : Component
where TNewComponent : ComponentMakeFindFile方法是一个虚方法供派生类可重写自己的查找方式。默认从预制体中进行查找。
protected string[] _findFiles;
protected virtual void MakeFindFile()
{
//收集所有预制信息
var extensions = new List<string>() {".prefab"};
var files = Directory.GetFiles(Application.dataPath, "*.*", SearchOption.AllDirectories)
.Where(s => extensions.Contains(Path.GetExtension(s)?.ToLower())).ToArray();
_findFiles = Directory.GetFiles(Application.dataPath, "*.*", SearchOption.AllDirectories)
.Where(s => extensions.Contains(Path.GetExtension(s)?.ToLower())).ToArray();
}StartReplace方法传入数据上下文,并打开进度条进行查找。
protected virtual void StartReplace(ComponentDataContextBase dataContextBase)
{
_findComponentDict = new Dictionary<string, List<TOldComponent>>();
_dataContextBase = dataContextBase;
MakeFindFile();
EditorUtilityHelp.ShowUpdate("正在查找", _findFiles.Length, (index) => { FindInPrefab(_findFiles[index]); },
FindPrefabOver);
}ReplaceIng方法在替换过程中将旧的组件全部替换成新的组件,具体的数据操作交由ComponentDataContext子类实现。
protected virtual void ReplaceIng(TOldComponent oldComponent)
{
var gameObject = oldComponent.gameObject;
_dataContextBase.CopyComponent(oldComponent);
Object.DestroyImmediate(oldComponent, true);
var newComponent = gameObject.AddComponent<TNewComponent>();
_dataContextBase.PasteComponent(newComponent);
}ReplaceOver在替换完成时调用,通常打印相关的替换信息。
protected virtual void ReplaceOver()
{
foreach (var item in _findComponentDict)
{
GameObject prefab = LoadGameObjectByGuid(item.Key, out var prefabPath);
Debug.Log($"Replace Prefab {prefab.name} {prefabPath} ComponentsLength {item.Value.Count}", prefab);
}
}ComponentDataContextBase这个类提供两个抽象方法供子类重写,主要完成对数据的赋值和粘贴操作。
public abstract class ComponentDataContextBase
{
public abstract void CopyComponent<TOldComponent>(TOldComponent oldComponent) where TOldComponent : Component;
public abstract void PasteComponent<TNewComponent>(TNewComponent newComponent) where TNewComponent : Component;
}对于实际的应用类,例如我们需要将Test1换成Test2组件的话,testData和nameData为这两个脚本中公用的数据。那么对应的两个类分别为:
public class TestScriptComponentDataContext : ComponentDataContextBase
{
public object testData;
public object nameData;
private static BindingFlags _flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
public override void CopyComponent<TOldComponent>(TOldComponent oldComponent)
{
var test1Script = oldComponent as Test1;
testData = typeof(Test1).GetField("TestData1", _flags)?.GetValue(test1Script);
nameData = typeof(Test1).GetField("Name", _flags)?.GetValue(test1Script);
}
public override void PasteComponent<TNewComponent>(TNewComponent newComponent)
{
var test2Script = newComponent as Test2;
typeof(Test2).GetField("TestData1", _flags)?.SetValue(test2Script,testData);
typeof(Test2).GetField("Name", _flags)?.SetValue(test2Script,nameData);
}
} public class TestScriptReplaceComponent : ReplaceComponentBase<Test1,Test2>
{
public void StartReplaceTestScript()
{
StartReplace(new TestScriptComponentDataContext());
}
}版权声明:本文为dmk17771552304原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。