🚧

改进 Prefab Center

之前已经初步实现了 Prefab Center 的基本功能,可以显示 Asset/Prefabs 路径下附带有 PrefabCenterItem 组件的 Prefab 并可以将其加入到场景中。现在进一步对其进行改进,借此讨论 EditorWindow 类下其它一些重要的方法。

资源自动更新

Assets/Tools/PrefabCenter/Editor/PrefabCenter.cs 中添加以下代码,从而新增或移除 Prefab 时,Prefab Center 也会有对应的更新。

private void OnProjectChange () {
		_prefabItems.Clear ();
		_prefabItems = GetPrefabsFromAssetDatabase ();
	
		Repaint ();
}

道理很简单,当 Project 视图发生变化(即路径下的 Prefab 发生修改时),清空并重新收集路径下的 Prefab 并重绘窗口。

复制和删除

复制指定的 Prefab:

private void DuplicatePrefab () {
		string newName = _shownItem.name;
		int count = 0;
	
		while (AssetDatabase.FindAssets (newName, new string [] { "Assets/Prefabs" }).Length > 0) {
				List<string> nameSlots = new List<string> (newName.Split (' '));
				string lastSlot = nameSlots [nameSlots.Count - 1];
		
				if (Regex.IsMatch (lastSlot, @"^-?\d+$")) {
						nameSlots.RemoveAt (nameSlots.Count - 1);
						count = int.Parse (lastSlot) + 1;
				} else {
						count++;
				}
				newName = string.Join (" ", nameSlots.ToArray ()) + " " + count.ToString ();
		}
		PrefabUtility.CreatePrefab (string.Format ("Assets/Prefabs/{0}.prefab", newName), _shownItem);
}

复制的操作由 PrefabUtility.CreatePrefab 实际完成,主要在新 Prefab 的命名上做了一些判断和操作。

删除指定的 Prefab:

private void DeletePrefab () {
		string path = AssetDatabase.GetAssetPath (_shownItem);
		if (EditorUtility.DisplayDialog (
				"Delete selected prefab?",
				"\t" + path + "\n\nYou cannot undo this action.",
				"Delete",
				"Cancel"
		)) {
				AssetDatabase.DeleteAsset (path);
				_showDetail = false;
		}
}

AssetDatabase.DeleteAsset 根据路径删除资源,代码添加了确认对话框。

在 Project 视图中找到对应 Prefab

private void OnDetailGUI (int id) {
	// ...
	
		if (GUI.Button (new Rect (5, 42, _detailPosition.width - 10, 17), "Show in project")) {
				EditorGUIUtility.PingObject (_shownItem);
				Selection.activeObject = _shownItem;
		}

	// ...
}

EditorGUIUtility.PingObject 产生高亮, Selection.activeObject 选中该 Prefab。

Unity 还提供了工具类如 EditorUtilityEditorGUIUtility,包含很多有用的方法,可以帮助开发者更好的扩展编辑器。例如前边用到的 EditorUtility.DisplayDialog 确认对话框、EditorGUIUtility.PingObject 产生高亮等等。