zoukankan      html  css  js  c++  java
  • Unity3D

    问题

    假设有2个Animator Controller,分别命名为TestControllerLhs.controller以及TestControllerRhs.controller。在TestControllerLhs.controller中设置状态如下:

    TestControllerLhs.controller

    当拷贝了包含Transitions并且该Transitions的Dst State不存在的Animator State到另一个Animator Controller时,就会出现游离依赖数据。以TestControllerLhs.controller为例,查看该文件能够发现,Attack01包含了Transitions数据:

    Attack01包含的Transition

    该Transition的Dst State为Attack02。如果我们拷贝Attack01但没有拷贝Attack02到TestControllerRhs.controller,那么就出现了游离依赖数据:

    TestControllerRhs.controller

    游离依赖数据

    出现依赖的原因是该Transition的Dst State,即Attack02,仍然位于TestControllerLhs.controller中,没有被拷贝过来。说该数据是游离的原因是在TestControllerRhs.controller中,我们完全看不见他,也无法删除它。

    在这里注意到这个问题的原因是,美术在制作Animator Controller时经常会使用拷贝、黏贴的操作,很容易在无意间产生游离依赖数据,而最关键也最严重的问题是循环依赖,即A.controller依赖B.controller,并且B.controller依赖A.controller。如果这两个Controller都是AssetBundle的话,就会产生无限依赖加载。

    解决方案

    通过之前的游离依赖数据分析可知他们的共性为m_DstState项包含了所依赖的.controller文件的guid,因此我们通过读取.controller文件将这些游离依赖数据删除。
    以下的代码包含了检测循环依赖,打印依赖的Animator Controller以及去除游离依赖数据的功能,开发版本为Unity 5.5.2f1:

      1 /******************************************************************************
      2  * DESCRIPTION: AnimatorController处理器
      3  * 
      4  *     Copyright (c) 2017, 谭伟俊 (TanWeijun)
      5  *     All rights reserved
      6  * 
      7  * COMPANY:
      8  * CREATED: 2017.09.20, 15:48, CST
      9 *******************************************************************************/
     10 
     11 using System.IO;
     12 using System.Collections.Generic;
     13 using UnityEngine;
     14 using UnityEditor;
     15 using UnityEditor.Animations;
     16 using GameFramework;
     17 
     18 public class AnimatorControllerProcessor
     19 {
     20     [MenuItem("Assets/Artist Tools/Animator Controller/Correct Data")]
     21     private static void CorrectData()
     22     {
     23         string block = null;
     24         bool isDependOtherAnimatorController = false;
     25         AnimatorController animatorController = Selection.activeObject as AnimatorController;
     26         string filePathName = Path.GetFullPath(AssetDatabase.GetAssetPath(animatorController));
     27         string tempFilePathName = Application.dataPath + "/" + System.DateTime.Now.Ticks.ToString() + ".controller";
     28         using (StreamWriter writer = File.CreateText(tempFilePathName))
     29         {
     30             using (StreamReader reader = File.OpenText(filePathName))
     31             {
     32                 string content;
     33                 while (null != (content = reader.ReadLine()))
     34                 {
     35                     if (content.StartsWith("--- !u"))
     36                     {
     37                         if (!string.IsNullOrEmpty(block))
     38                             writer.Write(block);
     39 
     40                         block = content + System.Environment.NewLine;
     41                         isDependOtherAnimatorController = false;
     42                     }
     43                     else
     44                     {
     45                         if (isDependOtherAnimatorController)
     46                             continue;
     47 
     48                         if (string.IsNullOrEmpty(block))
     49                             writer.WriteLine(content);
     50                         else
     51                         {
     52                             block += (content + System.Environment.NewLine);
     53 
     54                             // 检测是否依赖其他的Animator Controller
     55                             if (content.Contains("m_DstState:") && content.Contains("guid"))
     56                             {
     57                                 block = null;
     58                                 isDependOtherAnimatorController = true;
     59                             }
     60                         }
     61                     }
     62                 }
     63 
     64                 // 写入最后的数据
     65                 if (!string.IsNullOrEmpty(block))
     66                     writer.Write(block);
     67             }
     68         }
     69 
     70         FileUtil.ReplaceFile(tempFilePathName, filePathName);
     71         AssetDatabase.Refresh();
     72     }
     73 
     74     [MenuItem("Assets/Artist Tools/Animator Controller/Collect Animator Controller Dependencies")]
     75     private static void CollectAnimatorControllerDependencies()
     76     {
     77         AnimatorController animatorController = Selection.activeObject as AnimatorController;
     78         string[] dependencyArray = AssetDatabase.GetDependencies(AssetDatabase.GetAssetPath(animatorController));
     79 
     80         Log.Debug("************************* Animator Controller Dependencies (" + animatorController.name + ") *************************");
     81         foreach (string dependency in dependencyArray)
     82         {
     83             if (dependency.EndsWith(".controller"))
     84                 Log.Debug(dependency);
     85         }
     86         Log.Debug("************************************************* End *************************************************");
     87     }
     88 
     89     [MenuItem("ArtistTools/Check Animator Controller Dependencies")]
     90     private static void CheckAnimatorControllerDependencies()
     91     {
     92         List<string> dependencyCheckNameList = new List<string>();
     93         string[] filePathNameArray = Directory.GetFiles(Application.dataPath + "/BundleResources/Animator", "*.controller", SearchOption.TopDirectoryOnly);
     94         foreach (string filePathName in filePathNameArray)
     95         {
     96             string[] dependencyArray = AssetDatabase.GetDependencies(filePathName.Substring(filePathName.IndexOf("/Assets/") + 1));
     97             foreach (string dependency in dependencyArray)
     98             {
     99                 if (dependency.EndsWith(".controller"))
    100                 {
    101                     string assetName = Path.GetFileNameWithoutExtension(filePathName);
    102                     string dependencyName = Path.GetFileNameWithoutExtension(dependency);
    103 
    104                     // A依赖于B,如果"B_A"存在,表示B也依赖于A,则是循环依赖
    105                     string checkName = dependencyName + "_" + assetName;
    106                     if (dependencyCheckNameList.Contains(checkName))
    107                         Log.Debug(Path.GetFileName(filePathName) + " and " + Path.GetFileName(dependency) + " depend each other");
    108 
    109                     dependencyCheckNameList.Add(assetName + "_" + dependencyName);
    110                 }
    111             }
    112         }
    113     }
    114 
    115     [MenuItem("Assets/Artist Tools/Animator Controller/Correct Data", true)]
    116     [MenuItem("Assets/Artist Tools/Animator Controller/Collect Animator Controller Dependencies", true)]
    117     private static bool ValidateCorrectData()
    118     {
    119         return Selection.activeObject is AnimatorController;
    120     }
    121 }

    打印依赖的Animator Controller:

    TestControllerLhs依赖TestControllerRhs

    TestControllerRhs依赖TestControllerLhs

    检测循环依赖:

    循环依赖

    使用工具清理游离依赖数据后:

    除了自身不再依赖其他的Animator Controller

     

    本文固定链接: http://www.cnblogs.com/twjcnblog/p/7663048.html
    转载请注明: EnigmaJJ 2017年10月13日 于 cnblog 发表

  • 相关阅读:
    2018.9月总结
    L143 Seasonal 'Plague' Hits College Freshman
    2018.9.28 长难句2-非简单句
    Report: Disappearing Wetlands Put Planet Life at Risk
    PyQt(Python+Qt)学习随笔:QTableWidget的currentItem、rowCount、columnCount等部件状态属性访问方法
    PyQt(Python+Qt)学习随笔:QTableWidget的构造方法
    PyQt学习随笔:QTableWidgetItem项的setSizeHint()方法的作用
    PyQt(Python+Qt)学习随笔:QTableWidget中表格各列平均分配宽度的两种方法
    PyQt学习随笔:QTableWidget项sizeHint的作用以及与QHeadView的sectionResizeMode、ResizeToContents的关系
    PyQt(Python+Qt)学习随笔:QTableWidget表格部件中行高和列宽的计算方式
  • 原文地址:https://www.cnblogs.com/twjcnblog/p/7663048.html
Copyright © 2011-2022 走看看