• unity5之代码创建状态机,玩的666


    http://blog.csdn.net/litaog00/article/details/50483189

    最近做项目的时候用到了状态机,网上搜了一下帖子,大部分都是简单介绍使用方法的,讲解的详细的很少。作者

    好好研究了一番,感觉很有必要和大家分享一下。技术和灵感,来源于网络,共享于网络~

    好多个human模型有好多个动作片段,这些片段又分出若干大类和若干小类,一个主角可能会应用到所有的这些片

    段,当满足一定条件时从一类动作中随机取出一个播放,进游戏的时候有的动作条件满足有的不满足随着玩的进度

    又可能会满足#@#@#%@!!&*&,,,,略复杂,总之就是有好多动作(200个左右),有的能播,有的不能播

    ,作者(头硬)一心想用一个状态机来解决所有问题,所以就用代码创建吧,毕竟这么多动作,让策划去摆,费时

    费力还容易出错,特别在设置transition的条件时,呵呵,那就代码创建吧,既能体现情怀又能提高自己。


    首先网上搜了搜,只有雨松momo的一篇http://www.xuanyusong.com/archives/2811(冒犯引用一下),介绍了大

    概思想和用法,但是比较旧,要知道作者用的可是unity3d5.2.2版的,不同及需要注意的地方依次列出:

    1.AnimatorController所在的库由UnityEditorInternal变为UnityEditor.Animations


    2.AnimatorController里可以创建layer,每个layer有个statemachine(我们通常叫‘某个角色的状态机’好

    像不合适,应该叫‘某个角色的AnimatorController’

    [csharp] view plain copy
    1. //创建controller  
    2. AnimatorController controller=AnimatorController.CreateAnimatorControllerAtPath("Assets/Resources/CharacterAnim/Play2Controllor_2.controller");  
    3. AnimatorControllerLayer layer=controller.layers[0];  
    4. AnimatorStateMachine machine=layer.stateMachine;  
    这样取到了base layer的statemachine


    3.创建参数,

    [csharp] view plain copy
    1. controller.AddParameter("zhan->pa",AnimatorControllerParameterType.Trigger);  

    参数类型有4种:int、float、bool、trigger(作者之前用4.2版的时候还没有trigger,只有int、float

    、bool、vector)

    有了参数,就有判断条件了,判断条件的类型有

    [csharp] view plain copy
    1. AnimatorConditionMode.If;  
    2. AnimatorConditionMode.IfNot;  
    3. AnimatorConditionMode.Equals;  
    4. AnimatorConditionMode.NotEqual;  
    5. AnimatorConditionMode.Greater;  
    6. AnimatorConditionMode.Less;  
    其中if既可以来判断bool又可以判断trigger(其实trigger就是触发一下就重置了,可以理解为自动重置的bool)


    4.添加内容

    添加oneState

    [csharp] view plain copy
    1. oneState=machine.AddState(名字,位置)  
    添加anyState到oneState的transition
    [csharp] view plain copy
    1. AnimatorStateTransition defaultTransition=machine.AddAnyStateTransition(oneState);  

    
    创建二级子状态机
    
    [csharp] view plain copy
    1. AnimatorStateMachine sub2Machine=machine.AddStateMachine(名字,位置)  
    作者这里创建了三级子状态机,子状态机跟父状态机一样,都可以添加state、transition。有一点需要注意,
    [csharp] view plain copy
    1. AnimatorStateTransition transition1=machine.AddAnyStateTransition(oneState);  
    2. AnimatorStateTransition transition2=sub2Machine.AddAnyStateTransition(twoState);  
    
    

    transition1和transition2不是从同一个anyState出发的,而是从各自状态机的anyState出发的(子状态

    机也有个anyState,但是在controller编辑器里看不出来)

    5.雨松momo的帖子里有网友问到:如果fbx里有多个clip,用AssetDatabase.LoadAssetAtPath(xxx.fbx)

    如何取到呢?那么答案来了

    [csharp] view plain copy
    1. Object[] objects=AssetDatabase.LoadAllAssetsAtPath("Assets/Art/Animation/"+fbxName);  
    2. for(int m=0;m<objects.Length;m++)  
    3. {  
    4. <span style="white-space:pre">    </span>if(objects[m].GetType()==typeof(AnimationClip) && !objects[m].name.Contains("Take 001"))  
    5.     {  
    6.         AnimationClip clip=(AnimationClip)objects[m];  
    7.   
    8.         if(clip.name.Equals("chushidongzuo001"))  
    9.         {  
    10.             defaultState.motion=clip;  
    11.         }  
    12.         else  
    13.         {  
    14.             addAnimationClip(clip,actionDetails,machine,haveSub3);  
    15.         }  
    16.     }  
    17. }  

    注意到了吗?AssetDatabase.LoadAllAssetsAtPath可以把fbx里的所有信息取到,clip、骨骼节点、mesh。。。,

    然后过滤一下下。而AssetDatabase.LoadAssetAtPath<AnimationClip>("xxx.FBX")只能取到此fbx下第一个clip。



    好了,就写到这里,下面把整个代码贴出来,供大家参考~

    [csharp] view plain copy
    1. using UnityEngine;  
    2. using System.Collections.Generic;  
    3. using UnityEditor;  
    4. //using UnityEditorInternal;  
    5. using UnityEditor.Animations;  
    6. using System.IO;  
    7.   
    8. public class Play2ControllerGenerator : EditorWindow {  
    9.   
    10.     public enum ActionType:int  
    11.     {  
    12.         undefine=0,  
    13.         zhan,  
    14.         tang,  
    15.         cewo,  
    16.         pa,  
    17.         guodu,  
    18.         kaichang,  
    19.         jieshu,  
    20.         wu  
    21.     }  
    22.   
    23.     public enum ActionStyle:int  
    24.     {  
    25.         normal=0,  
    26.         qingchun,  
    27.         keai,  
    28.         gaoleng,  
    29.         yundong,  
    30.         chengshu,  
    31.         xinggan  
    32.     }  
    33.   
    34.     private static string[] sub2MachineNames=new string[]{"undefine","zhan","tang","cewo","pa","guodu","kaichang","jieshu","wu"};  
    35.     private static string[] sub3MachineNames=new string[]{"normal","qingchun","keai","gaoleng","yundong","chengshu","xinggan"};  
    36.   
    37.     private const string ParamNameTransitionAction="transitionAction";  
    38.     private const string ParamNameActionId="actionId";  
    39.   
    40.     private const float TransitionDuring=0.4f;  
    41.   
    42.     //  
    43.     [MenuItem("LoveLive/核心玩法2/生成状态机")]  
    44.     private static void addWindow()  
    45.     {  
    46.         Rect rect=new Rect(0,0,600,300);  
    47.   
    48.         Play2ControllerGenerator window=EditorWindow.GetWindowWithRect<Play2ControllerGenerator>(rect,true,"生成核心玩法状态机(省得策划自己摆了)");  
    49.         window.minSize=new Vector2(300,100);  
    50.         window.maxSize=new Vector2(600,300);  
    51.         window.Show();  
    52.     }  
    53.   
    54.   
    55.     void OnGUI()  
    56.     {  
    57.         EditorGUILayout.BeginVertical();  
    58.         EditorGUILayout.LabelField("需要"Assets/Resources/Config/action.txt"");  
    59.         EditorGUILayout.LabelField("需要"Assets/Art/Animation"下的动作文件");  
    60.         EditorGUILayout.EndVertical();  
    61.   
    62.         EditorGUILayout.Separator();  
    63.         EditorGUILayout.LabelField("生成的状态机在这个位置:"Assets/Resources/CharacterAnim/Play2Controllor_2.controller"");  
    64.   
    65.         EditorGUILayout.BeginHorizontal();  
    66.         if(GUILayout.Button("点击生成(需要一点时间)"))  
    67.         {  
    68.             generateStateMachine();  
    69.             this.ShowNotification(new GUIContent("创建完毕"));  
    70.         }  
    71.         EditorGUILayout.EndHorizontal();  
    72.     }  
    73.   
    74.     private void generateStateMachine()  
    75.     {  
    76.         //加载action文件  
    77.         Dictionary<string,ActionDetail> actionDetails=parseActionFile("Assets/Resources/Config/action.txt");  
    78.   
    79.         //创建controller  
    80.         AnimatorController controller=AnimatorController.CreateAnimatorControllerAtPath("Assets/Resources/CharacterAnim/Play2Controllor_2.controller");  
    81.         AnimatorControllerLayer layer=controller.layers[0];  
    82.         AnimatorStateMachine machine=layer.stateMachine;  
    83.   
    84.         //创建参数  
    85.         controller.AddParameter(ParamNameTransitionAction,AnimatorControllerParameterType.Trigger);  
    86.         controller.AddParameter(ParamNameActionId,AnimatorControllerParameterType.Int);  
    87.         controller.AddParameter("zhan->pa",AnimatorControllerParameterType.Trigger);  
    88.         controller.AddParameter("pa->cewo",AnimatorControllerParameterType.Trigger);  
    89.         controller.AddParameter("pa->tang",AnimatorControllerParameterType.Trigger);  
    90.         controller.AddParameter("tang->cewo",AnimatorControllerParameterType.Trigger);  
    91.         controller.AddParameter("cewo->tang",AnimatorControllerParameterType.Trigger);  
    92.         controller.AddParameter("default",AnimatorControllerParameterType.Trigger);  
    93.   
    94.         //创建默认state  
    95.         AnimatorState defaultState=machine.AddState("default",new Vector3(300,0,0));  
    96.         //defaultState.motion=  
    97.         machine.defaultState=defaultState;  
    98.         AnimatorStateTransition defaultTransition=machine.AddAnyStateTransition(defaultState);  
    99.         defaultTransition.AddCondition(AnimatorConditionMode.If,0,"default");  
    100.         defaultTransition.duration=TransitionDuring;  
    101.   
    102.         //3级状态机条件  
    103.         List<string> haveSub3=new List<string>();  
    104.         haveSub3.Add("zhan");  
    105.         haveSub3.Add("tang");  
    106.         haveSub3.Add("cewo");  
    107.         haveSub3.Add("pa");  
    108.   
    109.         //创建子状态机  
    110.         for(int k=1;k<sub2MachineNames.Length;k++)  
    111.         {  
    112.             AnimatorStateMachine sub2Machine=machine.AddStateMachine(sub2MachineNames[k],new Vector3(500,k*50,0));  
    113.             if(haveSub3.Contains(sub2MachineNames[k]))  
    114.             {  
    115.                 for(int m=0;m<sub3MachineNames.Length;m++)  
    116.                 {  
    117.                     AnimatorStateMachine sub3Machine=sub2Machine.AddStateMachine(sub3MachineNames[m],new Vector3(500,m*50,0));  
    118.                 }  
    119.             }  
    120.         }  
    121.   
    122.         //添加clip  
    123.         string[] fileNames=Directory.GetFiles(Application.dataPath+"/Art/Animation");  
    124.         for(int k=0;k<fileNames.Length;k++)  
    125.         {  
    126.             if(fileNames[k].EndsWith("fbx") || fileNames[k].EndsWith("FBX"))  
    127.             {  
    128.                 //获取fbx文件名  
    129.                 int index=fileNames[k].LastIndexOf("/");  
    130.                 string fbxName=fileNames[k].Substring(index+1,fileNames[k].Length-index-1);  
    131.   
    132.                 //读取fbx里的动作文件  
    133.                 Object[] objects=AssetDatabase.LoadAllAssetsAtPath("Assets/Art/Animation/"+fbxName);  
    134.                 for(int m=0;m<objects.Length;m++)  
    135.                 {  
    136.                     if(objects[m].GetType()==typeof(AnimationClip) && !objects[m].name.Contains("Take 001"))  
    137.                     {  
    138.                         AnimationClip clip=(AnimationClip)objects[m];  
    139.   
    140.                         if(clip.name.Equals("chushidongzuo001"))  
    141.                         {  
    142.                             defaultState.motion=clip;  
    143.                         }  
    144.                         else  
    145.                         {  
    146.                             addAnimationClip(clip,actionDetails,machine,haveSub3);  
    147.                         }  
    148.                     }  
    149.                 }  
    150.             }  
    151.         }  
    152.   
    153.   
    154.         //AnimationClip clip=AssetDatabase.LoadAssetAtPath<AnimationClip>("Assets/Art/Animation/guodudongzuo-001.FBX");  
    155.   
    156.     }  
    157.   
    158.     private static void addAnimationClip(AnimationClip clip,Dictionary<string,ActionDetail> actionDetails,AnimatorStateMachine machine,List<string> haveSub3)  
    159.     {  
    160.         if(actionDetails.ContainsKey(clip.name))  
    161.         {  
    162.             ActionDetail ad=actionDetails[clip.name];  
    163.   
    164.             foreach(ChildAnimatorStateMachine childMachine in machine.stateMachines)  
    165.             {  
    166.                 AnimatorStateMachine sub2Machine=childMachine.stateMachine;  
    167.   
    168.                 if(sub2MachineNames[ad.type]==sub2Machine.name)  
    169.                 {  
    170.                     //有3级状态机的加3级里,没有的加2级里  
    171.                     if(haveSub3.Contains(sub2Machine.name))  
    172.                     {  
    173.                         foreach(ChildAnimatorStateMachine childMachine3 in sub2Machine.stateMachines)  
    174.                         {  
    175.                             AnimatorStateMachine sub3Machine=childMachine3.stateMachine;  
    176.                             if(sub3MachineNames[ad.style]==sub3Machine.name)  
    177.                             {  
    178.                                 AnimatorState state=sub3Machine.AddState(clip.name,new Vector3(500,sub3Machine.states.Length*50,0));  
    179.                                 state.motion=clip;  
    180.                                 AnimatorStateTransition transition=machine.AddAnyStateTransition(state);  
    181.                                 transition.AddCondition(AnimatorConditionMode.If,0,ParamNameTransitionAction);  
    182.                                 transition.AddCondition(AnimatorConditionMode.Equals,ad.actionId,ParamNameActionId);  
    183.                                 transition.duration=TransitionDuring;  
    184.                             }  
    185.                         }  
    186.                     }  
    187.                     else  
    188.                     {  
    189.                         //过渡很特殊,这里写死  
    190.                         if(ad.type==(int)ActionType.guodu)  
    191.                         {  
    192.                             string stateName="";  
    193.                             float speed=1;  
    194.                             string condition="";  
    195.   
    196.                             int indexZhan=clip.name.IndexOf("zhan");  
    197.                             int indexPa=clip.name.IndexOf("pa");  
    198.                             int indexCewo=clip.name.IndexOf("cewo");  
    199.                             int indexTang=clip.name.IndexOf("tang");  
    200.                             //侧卧和躺之间有正向和反向片段  
    201.                             if(indexCewo>=0 && indexTang>=0)  
    202.                             {  
    203.                                 stateName+="cewo->tang";  
    204.                                 speed=(indexCewo<indexTang)?1:-1;  
    205.                                 condition="cewo->tang";  
    206.                                 if(!string.IsNullOrEmpty(condition))  
    207.                                 {  
    208.                                     AnimatorState state=sub2Machine.AddState(stateName,new Vector3(500,sub2Machine.states.Length*50,0));  
    209.                                     state.motion=clip;  
    210.                                     state.speed=speed;  
    211.                                     AnimatorStateTransition transition=machine.AddAnyStateTransition(state);  
    212.                                     transition.AddCondition(AnimatorConditionMode.If,0,condition);  
    213.                                     transition.duration=TransitionDuring;  
    214.                                 }  
    215.   
    216.   
    217.                                 stateName="guodu-tang->cewo";  
    218.                                 speed=(indexTang<indexCewo)?1:-1;  
    219.                                 condition="tang->cewo";  
    220.                                 if(!string.IsNullOrEmpty(condition))  
    221.                                 {  
    222.                                     AnimatorState state=sub2Machine.AddState(stateName,new Vector3(500,sub2Machine.states.Length*50,0));  
    223.                                     state.motion=clip;  
    224.                                     state.speed=speed;  
    225.                                     AnimatorStateTransition transition=machine.AddAnyStateTransition(state);  
    226.                                     transition.AddCondition(AnimatorConditionMode.If,0,condition);  
    227.                                     transition.duration=TransitionDuring;  
    228.                                 }  
    229.                             }  
    230.                             else  
    231.                             {  
    232.                                 if(indexZhan>=0 && indexPa>=0)  
    233.                                 {  
    234.                                     stateName="guodu-zhan->pa";  
    235.                                     speed=(indexZhan<indexPa)?1:-1;  
    236.                                     condition="zhan->pa";  
    237.                                 }  
    238.                                 else if(indexPa>=0 && indexCewo>=0)  
    239.                                 {  
    240.                                     stateName="guodu-pa->cewo";  
    241.                                     speed=(indexPa<indexCewo)?1:-1;  
    242.                                     condition="pa->cewo";  
    243.                                 }  
    244.                                 else if(indexPa>=0 && indexTang>=0)  
    245.                                 {  
    246.                                     stateName="guodu-pa->tang";  
    247.                                     speed=(indexPa<indexTang)?1:-1;  
    248.                                     condition="pa->tang";  
    249.                                 }  
    250.                                 if(!string.IsNullOrEmpty(condition))  
    251.                                 {  
    252.                                     AnimatorState state=sub2Machine.AddState(stateName,new Vector3(500,sub2Machine.states.Length*50,0));  
    253.                                     state.motion=clip;  
    254.                                     state.speed=speed;  
    255.                                     AnimatorStateTransition transition=machine.AddAnyStateTransition(state);  
    256.                                     transition.AddCondition(AnimatorConditionMode.If,0,condition);  
    257.                                     transition.duration=TransitionDuring;  
    258.                                 }  
    259.                             }  
    260.                         }  
    261.                         else  
    262.                         {  
    263.                             AnimatorState state=sub2Machine.AddState(clip.name,new Vector3(500,sub2Machine.states.Length*50,0));  
    264.                             state.motion=clip;  
    265.                             AnimatorStateTransition transition=machine.AddAnyStateTransition(state);  
    266.                             transition.AddCondition(AnimatorConditionMode.If,0,ParamNameTransitionAction);  
    267.                             transition.AddCondition(AnimatorConditionMode.Equals,ad.actionId,ParamNameActionId);  
    268.                             transition.duration=TransitionDuring;  
    269.                         }  
    270.                     }  
    271.                 }  
    272.             }  
    273.         }  
    274.     }  
    275.   
    276.     //解析动作文件  
    277.     private Dictionary<string,ActionDetail> parseActionFile(string actionFilePath)  
    278.     {  
    279.         Dictionary<string,ActionDetail> actionInfos=new Dictionary<string,ActionDetail>();  
    280.   
    281.         TextAsset ta=AssetDatabase.LoadAssetAtPath<TextAsset>(actionFilePath);  
    282.   
    283.         using(MemoryStream stream = new MemoryStream(ta.bytes))  
    284.         {  
    285.             using(StreamReader reader = new StreamReader(stream))  
    286.             {  
    287.                 //第一行是列名,跳过  
    288.                 int lineIdx = 0;  
    289.                 while (reader.Peek() >= 0)  
    290.                 {  
    291.                     lineIdx++;  
    292.                     string source = reader.ReadLine();  
    293.                     if (lineIdx != 1 && !string.IsNullOrEmpty(source))  
    294.                     {  
    295.                         ActionDetail ad=ActionDetail.create(source);  
    296.                         actionInfos.Add(ad.actionName,ad);  
    297.                     }  
    298.                 }  
    299.             }  
    300.         }  
    301.         Debug.Log("共需要获取"+actionInfos.Count+"个动作");  
    302.         return actionInfos;  
    303.     }  
    304.       
    305. }  
    306.   
    307. public class ActionDetail  
    308. {  
    309.     public int actionId;  
    310.     public string actionName;  
    311.     public int type;  
    312.     public int style;  
    313.   
    314.     public static ActionDetail create(string line)  
    315.     {  
    316.         string[] ss=line.Split(' ');  
    317.   
    318.         ActionDetail ad=new ActionDetail();  
    319.         ad.actionId=int.Parse(ss[0]);  
    320.         ad.actionName=ss[1];  
    321.         ad.type=int.Parse(ss[2]);  
    322.         ad.style=int.Parse(ss[3]);  
    323.   
    324.         return ad;  
    325.     }  
    326. }  

    参考文章:

    http://www.xuanyusong.com/archives/2811

    http://7dot9.com/2015/05/11/unity3d-mecanim%E5%8A%A8%E7%94%BBanimatortransitioninfo%E5%92%8Canimatorstateinfo%E5%9C%A8%E8%A7%92%E8%89%B2%E7%A7%BB%E5%8A%A8%E5%92%8C%E5%BE%85%E6%9C%BA%E5%B9%B3%E6%BB%91%E5%88%87%E6%8D%A2%E4%B8%AD/

  • 相关阅读:
    自制DEV皮肤
    网格系统,菜单、按钮及导航
    表单
    排版
    Bootstrap的HTML标准模板
    ecshop常用的修改内容
    删除ECSHOP后台左侧导航菜单
    dede 内容页文章标题显示不全的更改方法
    dede 鼠标移到标题处显示完整标题
    Artlist标签去掉table
  • 原文地址:https://www.cnblogs.com/nafio/p/9137372.html
Copyright © 2020-2023  润新知