NGUI5.6与Unity2018.3 PrefabMode冲突问题解决方案

发表于2020-05-06
评论0 3.4k浏览

情景:

Unity在升级到2018.3版本后 新增了Prefab Mode系统,可以通过Open Prefab直接打开新的Scene对预设进行编辑。

NGUI的UI控件需要依附于UIRoot节点作为其顶级父节点,UIRoot主要是控制UI控件的变化和缩放。

 

问题:

Unity的Prefab Mode强制在对Prefab节点进行删除/移动时 需要在Prefab Mode系统中才能进行,因此若是在NGUI5.6升级Unity到2018.3 就会出现 在Scene场景中无法删、移预设,但是进入Prefab Mode会有导致NGUI控件报错的问题。

 

解决方法:

1,简单的解决方法是 每次进行预设编辑时 使用Unpack 进行预设的解引用,这样不需要进入Prefab Mode也可以进行预设的删、移,而缺点就是 每次修改之后需要进行预设的覆盖,带来操作成本,隐患则是进行Unpack会导致引用丢失,需要每次都重新拖引用,提高了操作失误率。

 

2,对NGUI 5.6 源码修改,在进入Prefab Mode时为其创建UIRoot,在寻找解决方案的时候发现了NGUI2018已经有相应的解决方法,这里将需要修改的代码整理出来:

 

1,实现配置环境 
UIRect.cs 
protected virtual void Awake () {  
#if UNITY_2018_3_OR_NEWER 
    NGUITools.CheckForPrefabStage (gameObject);  
#endif 

    mStarted = false; 
    mGo = gameObject; 
    mTrans = transform; 

static public void CheckForPrefabStage (GameObject gameObject) {  
#if UNITY_EDITOR && UNITY_2018_3_OR_NEWER 
    var prefabStage = UnityEditor.Experimental.SceneManagement.PrefabStageUtility.GetPrefabStage (gameObject); 
    if (prefabStage == null) 
        return; 

    var rootsInParents = gameObject.GetComponentsInParent<UIRoot> (true); 
    var panelsInParents = gameObject.GetComponentsInParent<UIPanel> (true); 

    bool missingRoot = rootsInParents.Length == 0; 
    bool missingPanel = panelsInParents.Length == 0; 

    if (!missingRoot && !missingPanel) 
        return; 

    // Since this function is called from Awake/OnEnable, utilities like PrefabStage.prefabContentsRoot 
    // or Scene.GetRootGameObjects () aren't available at this point 

    var instanceRoot = gameObject.transform; 
    while (instanceRoot.parent != null) 
        instanceRoot = instanceRoot.parent; 

    GameObject container = UnityEditor.EditorUtility.CreateGameObjectWithHideFlags ("UIRoot (Environment)", HideFlags.DontSave); 
    container.layer = instanceRoot.gameObject.layer; 

    if (missingRoot) 
        container.AddComponent<UIRoot> (); 

    if (missingPanel) 
        container.AddComponent<UIPanel> (); 

    UnityEngine.SceneManagement.SceneManager.MoveGameObjectToScene (container, prefabStage.scene); 
    instanceRoot.SetParent (container.transform, false); 
#endif 


2,实现在预设场景能够正确保存NGUI预设 
NGUITools.cs 
static public void SetDirty (UnityEngine.Object obj) 
{  
#if UNITY_EDITOR 
    if (obj) 
    {  
        if (UnityEditor.AssetDatabase.Contains(obj)) 
        {  
            UnityEditor.EditorUtility.SetDirty(obj); 
         } 
        else if (!Application.isPlaying) 
        {  
            if (obj is Component) 
            {  
                var component = (Component)obj; 
                UnityEditor.SceneManagement.EditorSceneManager.MarkSceneDirty(component.gameObject.scene); 
             } 
            else if (obj is UnityEditor.EditorWindow || obj is ScriptableObject) 
            {  
                UnityEditor.EditorUtility.SetDirty(obj); 
             } 
            else 
            {  
                UnityEditor.EditorUtility.SetDirty(obj); 
                UnityEditor.SceneManagement.EditorSceneManager.MarkAllScenesDirty(); 
             } 
         } 
     } 
    //if (obj) 
    //{  
    // //if (obj is Component) Debug.Log(NGUITools.GetHierarchy((obj as Component).gameObject), obj); 
    // //else if (obj is GameObject) Debug.Log(NGUITools.GetHierarchy(obj as GameObject), obj); 
    // //else Debug.Log("Hmm... " + obj.GetType(), obj); 
    // UnityEditor.EditorUtility.SetDirty(obj); 
    // } 
#endif 


3,实现渲染 
UIDrawCall 
static UIDrawCall Create (string name, UIPanel pan, Material mat, Texture tex, Shader shader) 
{  
    UIDrawCall dc = Create(name); 
    dc.gameObject.layer = pan.cachedGameObject.layer; 
    dc.baseMaterial = mat; 
    dc.mainTexture = tex; 
    dc.shader = shader; 
    dc.renderQueue = pan.startingRenderQueue; 
    dc.sortingOrder = pan.sortingOrder; 
    dc.manager = pan; 

#if UNITY_EDITOR && UNITY_2018_3_OR_NEWER 
    // We need to perform this check here and not in Create (string) to get to manager reference 
    var prefabStage = UnityEditor.Experimental.SceneManagement.PrefabStageUtility.GetCurrentPrefabStage (); 
    if (prefabStage != null && dc.manager != null) 
    {  
        // If prefab stage exists and new daw call 
        var stage = UnityEditor.SceneManagement.StageUtility.GetStageHandle (dc.manager.gameObject); 
        if (stage == prefabStage.stageHandle) 
            UnityEngine.SceneManagement.SceneManager.MoveGameObjectToScene (dc.gameObject, prefabStage.scene); 

#endif 
    return dc; 

 

剩下的是其他的修改,代码太多放不下

链接:https://pan.baidu.com/s/1LTdX-4ZjzyYTqxFh8UyAKQ 
提取码:7xdt

  • 允许他人重新传播作品,但他人重新传播时必须在所使用作品的正文开头的显著位置,注明用户的姓名、来源及其采用的知识共享协议,并与该作品在磨坊上的原发地址建立链接
  • 可对作品重新编排、修改、节选或者以作品为基础进行创作和发布
  • 不可将作品进行商业性使用

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引

标签: