问题

假设有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:

 /******************************************************************************
* DESCRIPTION: AnimatorController处理器
*
* Copyright (c) 2017, 谭伟俊 (TanWeijun)
* All rights reserved
*
* COMPANY:
* CREATED: 2017.09.20, 15:48, CST
*******************************************************************************/ using System.IO;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using UnityEditor.Animations;
using GameFramework; public class AnimatorControllerProcessor
{
[MenuItem("Assets/Artist Tools/Animator Controller/Correct Data")]
private static void CorrectData()
{
string block = null;
bool isDependOtherAnimatorController = false;
AnimatorController animatorController = Selection.activeObject as AnimatorController;
string filePathName = Path.GetFullPath(AssetDatabase.GetAssetPath(animatorController));
string tempFilePathName = Application.dataPath + "/" + System.DateTime.Now.Ticks.ToString() + ".controller";
using (StreamWriter writer = File.CreateText(tempFilePathName))
{
using (StreamReader reader = File.OpenText(filePathName))
{
string content;
while (null != (content = reader.ReadLine()))
{
if (content.StartsWith("--- !u"))
{
if (!string.IsNullOrEmpty(block))
writer.Write(block); block = content + System.Environment.NewLine;
isDependOtherAnimatorController = false;
}
else
{
if (isDependOtherAnimatorController)
continue; if (string.IsNullOrEmpty(block))
writer.WriteLine(content);
else
{
block += (content + System.Environment.NewLine); // 检测是否依赖其他的Animator Controller
if (content.Contains("m_DstState:") && content.Contains("guid"))
{
block = null;
isDependOtherAnimatorController = true;
}
}
}
} // 写入最后的数据
if (!string.IsNullOrEmpty(block))
writer.Write(block);
}
} FileUtil.ReplaceFile(tempFilePathName, filePathName);
AssetDatabase.Refresh();
} [MenuItem("Assets/Artist Tools/Animator Controller/Collect Animator Controller Dependencies")]
private static void CollectAnimatorControllerDependencies()
{
AnimatorController animatorController = Selection.activeObject as AnimatorController;
string[] dependencyArray = AssetDatabase.GetDependencies(AssetDatabase.GetAssetPath(animatorController)); Log.Debug("************************* Animator Controller Dependencies (" + animatorController.name + ") *************************");
foreach (string dependency in dependencyArray)
{
if (dependency.EndsWith(".controller"))
Log.Debug(dependency);
}
Log.Debug("************************************************* End *************************************************");
} [MenuItem("ArtistTools/Check Animator Controller Dependencies")]
private static void CheckAnimatorControllerDependencies()
{
List<string> dependencyCheckNameList = new List<string>();
string[] filePathNameArray = Directory.GetFiles(Application.dataPath + "/BundleResources/Animator", "*.controller", SearchOption.TopDirectoryOnly);
foreach (string filePathName in filePathNameArray)
{
string[] dependencyArray = AssetDatabase.GetDependencies(filePathName.Substring(filePathName.IndexOf("/Assets/") + ));
foreach (string dependency in dependencyArray)
{
if (dependency.EndsWith(".controller"))
{
string assetName = Path.GetFileNameWithoutExtension(filePathName);
string dependencyName = Path.GetFileNameWithoutExtension(dependency); // A依赖于B,如果"B_A"存在,表示B也依赖于A,则是循环依赖
string checkName = dependencyName + "_" + assetName;
if (dependencyCheckNameList.Contains(checkName))
Log.Debug(Path.GetFileName(filePathName) + " and " + Path.GetFileName(dependency) + " depend each other"); dependencyCheckNameList.Add(assetName + "_" + dependencyName);
}
}
}
} [MenuItem("Assets/Artist Tools/Animator Controller/Correct Data", true)]
[MenuItem("Assets/Artist Tools/Animator Controller/Collect Animator Controller Dependencies", true)]
private static bool ValidateCorrectData()
{
return Selection.activeObject is AnimatorController;
}
}

打印依赖的Animator Controller:

TestControllerLhs依赖TestControllerRhs

TestControllerRhs依赖TestControllerLhs

检测循环依赖:

循环依赖

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

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

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

Unity3D - Animator Controller循环依赖的更多相关文章

  1. Unity3D之Mecanim动画系统学习笔记(五):Animator Controller

    简介 Animator Controller在Unity中是作为一种单独的配置文件存在的文件类型,其后缀为controller,Animator Controller包含了以下几种功能: 可以对多个动 ...

  2. Animator Controller 继承关系

    准备知识 对于Animator Controller中蜘蛛网一样的几十条连线,后续如果靠人工维护,那成本将是很大. AnimatorOverrideController组件的文档:https://do ...

  3. Spring基础系列-Spring事务不生效的问题与循环依赖问题

    原创作品,可以转载,但是请标注出处地址:https://www.cnblogs.com/V1haoge/p/9476550.html 一.提出问题 不知道你是否遇到过这样的情况,在ssm框架中开发we ...

  4. service层代码相互调用, 导致spring循环依赖,设计上的优化

    管理员创建用户需要发送激活邮件, 而发送激活邮件的时候需要判断发件人是不是合法的用户, 因此设计到一个循环依赖的问题 //UserService @Service class UserService{ ...

  5. Spring Cloud杜绝循环依赖

    前言 大家在开发中有没有遇到过因循环依赖导致项目启动失败?在排查循环依赖的过程中有没困难?如何避免写出循环依赖的代码? 我没写过循环依赖的代码,作为稳定性负责人,我排查过多次. 有些逻辑简单的代码,循 ...

  6. .netcore ioc 循环依赖问题及其相关思考之DispatchProxy

    .netcore引入了ioc机制让开发人员逐步习惯从过去的各种new对象变成通过IOC框架来管理对象的生命周期.这样当我们需要某个对象的时候,我们一般在构造函数里申明该对象的接口,即可通过ioc容器创 ...

  7. SpringBoot项目意外出现 循环依赖和注入的对象意外是Null的问题 Requested bean is currently in creation: Is there an unresolvable circular reference? 或 nested exception is java.lang.NullPointerException

    1.Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name ...

  8. kmdjs和循环依赖

    循环依赖 循环依赖是非常必要的,有的程序写着写着就循环依赖了,可以提取出一个对象来共同依赖解决循环依赖,但是有时会破坏程序的逻辑自封闭和高内聚.所以没解决好循环依赖的模块化库.框架.编译器都不是一个好 ...

  9. spring3 循环依赖

    循环依赖就是循环引用,就是两个或多个Bean相互之间的持有对方,比如CircleA引用CircleB,CircleB引用CircleC,CircleC引用CircleA,则它们最终反映为一个环.此处不 ...

随机推荐

  1. OSI与TCP/IP网络模型分层

      学习linux的人,都会接触到一些网络方面的知识.作为一个linux方面的萌新,今天,小编就接触了OSI模型和TCP/IP协议栈,那么什么是OSI模型呢?     OSI模型,开放式系统互联通信参 ...

  2. 关于SCSI/SATA/IDE硬盘的比较

    看linux的书时,发现许多地方提到SCSI/SATA/IDE这几种硬盘接口,对这些硬盘的概念和区别感到很模糊.所以特意查了一些资料,基本上算是弄懂了他们的区别. 目前硬盘最要分为3种.也即:IDE. ...

  3. webarchive文件转换成htm文…

    原文地址:webarchive文件转换成htm文件作者:xhbaxf Mac OS X系统带有文件转换功能,可以把webarchive文件变成html文件.方法是:   Step 1: 建立一个文件夹 ...

  4. 团队作业4——第一次项目冲刺(Alpha版本) Day5

    首先和助教及老师表示抱歉,博客确实当时就写了,但是一直不算写好,因为这几天卡住了,预计实现的功能实现不了,进度跟不上,现在也在寻求解决方法. 1.站立式会议: 2. Leangoo任务分解图: 3.任 ...

  5. 201521123076 《Java程序设计》第8周学习总结

    1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结集合与泛型相关内容. 1.2 选做:收集你认为有用的代码片段 2. 书面作业 1.List中指定元素的删除(题目4-1) 1.1 实 ...

  6. 201521123079《java程序设计》第5周学习总结

    1. 本周学习总结 1.1 尝试使用思维导图总结有关多态与接口的知识点. 2. 书面作业 1.代码阅读:Child压缩包内源代码 1.1 com.parent包中Child.java文件能否编译通过? ...

  7. Ubuntu下PHP MySQL环境搭建-upcoming-ChinaUnix博客

    编程语言选择php5 , web服务器选择Apache2 ,后台数据库选择MySQL首先安装编译工具, 打开终端 sudo apt-get install build-essential autoco ...

  8. php使用ZipArchive压缩文件的心得

    $zip=new ZipArchive; if($zip->open('test.zip',ZipArchive::CREATE)===TRUE){ $zip->addFile('imag ...

  9. Linux-exec命令试验驱动(12)

    对于做驱动经常会使用exec来试验驱动,通过exec将-sh进程下的描述符指向我们的驱动,来实现调试 -sh进程常用描述符号: 0:标准输入 1:标准输出 2:错误信息 5:中断服务 exec命令使用 ...

  10. Ansible系列(六):循环和条件判断

    本文目录:1. 循环 1.1 with_items迭代列表 1.2 with_dict迭代字典项 1.3 with_fileglob迭代文件 1.4 with_lines迭代行 1.5 with_ne ...