获取unity中prefab的中文文本内容以及和prefab有关的问题
背景1:经常会在开发中遇到策划需要改某个界面,但是我们不知道那是什么界面,只看到一些关键字比如圣诞活动,那这样我就可以轻易找到这个预设了。另外还可以扩展就是收集项目中的所有中文文本然后归集到多语言表中,然后接入百度翻译api完成自动翻译。
背景2:经常需要批处理预设却发现好多missing脚本的情况导致无法保存预设。
背景3:每次自己构建的text或者image组件总是会带一个rayCasttarget= true的属性,如果不影响事件应该处理为false。我希望在双击进入预设和退出预设的时候对预设自动处理一些属性并保存。
背景1代码如下:我写了2个接口一个是获取\uxxxx的文本内容 一个是获取Text组件上文本内容,大家可以根据需要选用接口。我不打算用unity的api来做主要是想做一个外部工具,用unity的工具有它的局限性。
/// <summary>
/// 获取text组件上的文本
/// </summary>
/// <param name="prefabPath"></param>
/// <returns></returns>
static string GetTextsTextFormPrefab(string prefabPath)
{
string prefabContent = File.ReadAllText(prefabPath);
var listContent = Regex.Matches(prefabContent, @"m_Text:\s*""(\\u([0-9A-Fa-f]{4}))+""");
string chinsesPattern = @"(\\u[0-9a-fA-F]{4})+";
StringBuilder sb = new StringBuilder();
foreach (Match collect in listContent)
{
var subCollect = Regex.Matches(collect.Value, chinsesPattern);
foreach (Match sub in subCollect)
{
string pattern = @"\\u([0-9a-fA-F]{4})";
sb.Append(Regex.Replace(sub.Value, pattern, match =>
{
// 将匹配到的 Unicode 转义序列转换为对应的 Unicode 字符
string unicodeValue = match.Groups[1].Value;
int codePoint = Convert.ToInt32(unicodeValue, 16);
return char.ConvertFromUtf32(codePoint);
}));
}
}
return sb.ToString();
}
/// <summary>
/// 获取预设上的文本内容
/// </summary>
/// <param name="prefabPath"></param>
/// <returns></returns>
static string GetTextFromPrefab(string prefabPath)
{
string prefabContent = File.ReadAllText(prefabPath);
Regex regex = new Regex(@"(\\u([0-9A-Fa-f]{4}))+", RegexOptions.Multiline);
var listContent = regex.Matches(prefabContent);
string chinsesPattern = @"(\\u[0-9a-fA-F]{4})+";
StringBuilder sb = new StringBuilder();
foreach (Match collect in listContent)
{
var subCollect = Regex.Matches(collect.Value, chinsesPattern);
foreach (Match sub in subCollect)
{
string pattern = @"\\u([0-9a-fA-F]{4})";
sb.AppendLine(Regex.Replace(sub.Value, pattern, match =>
{
// 将匹配到的 Unicode 转义序列转换为对应的 Unicode 字符
string unicodeValue = match.Groups[1].Value;
int codePoint = Convert.ToInt32(unicodeValue, 16);
return char.ConvertFromUtf32(codePoint);
}));
}
}
return sb.ToString();
}
背景2代码如下:
[MenuItem("Tools/EasyUseEditorTool/Remove Missing Scripts")]
static void RemoveMissScriptInGame()
{
GameObject[] gos = Resources.FindObjectsOfTypeAll<GameObject>();
foreach (GameObject obj in gos)
{
var components = obj.GetComponents<Component>();
for (int j = 0; j < components.Length; j++)
{
if (components[j] == null)
{
GameObjectUtility.RemoveMonoBehavioursWithMissingScript(obj);
break;
}
}
}
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
}
如果不移除missing的脚本批处理脚本就太难做了。
背景3代码:这块代码每个项目因人而异,需要特别注意多做测试。比如我们项目中一个image可能没有挂button组件或者toggle组件但是挂了自定义的mono对象,内部做了事件那这种也不能去掉
rayCastTarget属性,所以因项目而异。小项目简单项目可以用
using UnityEditor;
using UnityEditor.SceneManagement;
using UnityEngine;
public class PrefabHelper
{
[InitializeOnLoadMethod]
public static void init()
{
Debug.Log("PrefabHelper.init");
PrefabStage.prefabStageClosing -= OnPrefabStageClosing;
PrefabStage.prefabStageClosing += OnPrefabStageClosing;
}
public static void OnPrefabStageClosing(PrefabStage ps)
{
var root = ps.prefabContentsRoot;
var window = root.transform.Find("Window");
if (window == null)
{
window = root.transform.Find("window");
}
var rawImage = root.transform.Find("pingui");
if(rawImage != null)
{
GameObject.DestroyImmediate(rawImage);
}
window.localScale = Vector3.zero;
SCGTool.RemoveNoUseRayCast(root);
Object prefabObj = PrefabUtility.SaveAsPrefabAsset(root, ps.assetPath,out bool success);
if(success)
{
Debug.Log("apply sucess " + ps.assetPath);
}
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
}
}
[InitializeOnLoad]
public class SCGTool
{
public static void RemoveNoUseRayCast(GameObject go)
{
var tys = new System.Type[]
{
typeof(Toggle),typeof(Button),
};
// 获取text或者rowImage或者image
var raws = go.GetComponentsInChildren<RawImage>(true);
for (int i = 0; i < raws.Length; i++)
{
bool isAllNUll = true;
foreach(var t in tys)
{
if ( raws[i].GetComponent(t) != null)
{
isAllNUll = false;
}
}
raws[i].raycastTarget = !isAllNUll ;
}
var images = go.GetComponentsInChildren<Image>(true);
for (int i = 0; i < images.Length; i++)
{
if (images[i].GetComponent<Button>() == null && images[i].GetComponent<Toggle>() == null
&& images[i].GetComponent<ScrollRect>() == null && images[i].GetComponent<TouchMove>() == null)
{
images[i].raycastTarget = false;
}
}
var texts = go.GetComponentsInChildren<Text>(true);
for (int i = 0; i < texts.Length; i++)
{
texts[i].raycastTarget = false;
}
//然后遍历所有button对于设定了
var allButtons = go.GetComponentsInChildren<Button>(true);
foreach (var button in allButtons)
{
if(button != null && button.targetGraphic != null)
{
var tmpImage = button.targetGraphic.GetComponent<Image>();
if (tmpImage != null)
{
tmpImage.raycastTarget = true;
continue;
}
var tmpRawImage = button.targetGraphic.GetComponent<RawImage>();
if (tmpRawImage != null)
{
tmpRawImage.raycastTarget = true;
continue;
}
var tmpText = button.targetGraphic.GetComponent<Text>();
if (tmpText != null)
{
tmpText.raycastTarget = true;
continue;
}
}
else if(button !=null)
{
var tmpImage = button.targetGraphic.GetComponent<Image>();
if (tmpImage != null)
{
tmpImage.raycastTarget = true;
continue;
}
var tmpRawImage = button.targetGraphic.GetComponent<RawImage>();
if (tmpRawImage != null)
{
tmpRawImage.raycastTarget = true;
continue;
}
var tmpText = button.targetGraphic.GetComponent<Text>();
if (tmpText != null)
{
tmpText.raycastTarget = true;
continue;
}
}
}
EditorUtility.SetDirty(go);
}
}