public bool OnLoadIKAnimData()
    {
        //设置默认动画为idle
        GetComponent <Animation>().clip = GetComponent <Animation>().GetClip("idle");

        //设置spider的ik信息
        //ground info and root bone
        LegController legController = GetComponent <LegController>();

        legController.groundPlaneHeight = 0.0f;
        legController.groundedPose      = GetComponent <Animation>().GetClip("idle");
        legController.rootBone          = transform.Find("Bone02");

        //legs info
        legController.legs = new LegInfo[4];

        LegInfo _legInfo = new LegInfo();

        _legInfo.hip          = RecursionFindTransform(transform, "Bone83");
        _legInfo.ankle        = RecursionFindTransform(transform, "Bone90");
        _legInfo.toe          = RecursionFindTransform(transform, "Bone90");
        _legInfo.footLength   = 0.5f;
        _legInfo.footWidth    = 0.5f;
        _legInfo.footOffset   = new Vector2(0.0f, 0.0f);
        legController.legs[0] = _legInfo;

        _legInfo              = new LegInfo();
        _legInfo.hip          = RecursionFindTransform(transform, "Bone43");
        _legInfo.ankle        = RecursionFindTransform(transform, "Bone50");
        _legInfo.toe          = RecursionFindTransform(transform, "Bone50");
        _legInfo.footLength   = 0.5f;
        _legInfo.footWidth    = 0.5f;
        _legInfo.footOffset   = new Vector2(0.0f, 0.0f);
        legController.legs[1] = _legInfo;

        _legInfo              = new LegInfo();
        _legInfo.hip          = RecursionFindTransform(transform, "Bone26");
        _legInfo.ankle        = RecursionFindTransform(transform, "Bone33");
        _legInfo.toe          = RecursionFindTransform(transform, "Bone33");
        _legInfo.footLength   = 0.5f;
        _legInfo.footWidth    = 0.5f;
        _legInfo.footOffset   = new Vector2(0.0f, 0.0f);
        legController.legs[2] = _legInfo;

        _legInfo              = new LegInfo();
        _legInfo.hip          = RecursionFindTransform(transform, "Bone34");
        _legInfo.ankle        = RecursionFindTransform(transform, "Bone41");
        _legInfo.toe          = RecursionFindTransform(transform, "Bone41");
        _legInfo.footLength   = 0.5f;
        _legInfo.footWidth    = 0.5f;
        _legInfo.footOffset   = new Vector2(0.0f, 0.0f);
        legController.legs[3] = _legInfo;


        return(true);
    }
Exemple #2
0
 protected void updateLegs(LegController[] group, bool planted)
 {
     foreach (LegController leg in group)
     {
         LegInfo info = getLegInfo(leg);
         leg.setPosition(getLegInfo(leg).foot);
         info.setPlanted(planted);
         info.setLastDefault();
     }
 }
Exemple #3
0
    protected LegInfo getLegInfo(LegController leg)
    {
        LegInfo info;

        if (!legInfo.TryGetValue(leg, out info))
        {
            info = new LegInfo(this, leg);
            legInfo.Add(leg, info);
        }
        return(info);
    }
        private void CheckFeetGrounded()
        {
            if (initalize == false)
            {
                if (legInfo.Length == 0 || legInfo == null)
                {
                    legInfo = new LegInfo[grounderIK.solver.legs.Length];
                    for (int i = 0; i < grounderIK.solver.legs.Length; i++)
                    {
                        legInfo[i] = new LegInfo(grounderIK.solver.legs[i].transform);
                    }
                }
                initalize = true;
            }

            if (grounderIK == null || m_controller == null || legInfo == null)
            {
                return;
            }


            if (m_controller.isMoving)
            {
                for (int i = 0; i < grounderIK.solver.legs.Length; i++)
                {
                    Grounding.Leg leg  = grounderIK.solver.legs[i];
                    LegInfo       info = legInfo[i];
                    if (leg.initiated)
                    {
                        info.isGrounded       = leg.isGrounded;
                        info.velocity         = leg.velocity;
                        info.IKPosition       = leg.IKPosition;
                        info.heightFromGround = leg.heightFromGround;
                        info.hit = leg.GetHitPoint;
                        //if(leg.IKPosition.y < 1 && leg.velocity.x < 1 && m_animator.pivotWeight <= 0.25f)

                        //if(i == 0 && info.isGrounded && m_animator.velocity.sqrMagnitude > 4) {
                        //    Debug.LogFormat("<b><color=yellow>[FOOT PLANTED]</color></b> {0} is grounded <color=blue>{3}</color>.  IK = <color=blue>{1}</color>, V = <color=blue>{2}</color>",
                        //        info.transform.name, info.IKPosition, info.velocity, m_animator.pivotWeight);
                        //    Debug.Break();
                        //}
                    }
                }
            }
        }
Exemple #5
0
    protected float calculateStepPercent(LegController[] plantedGroup)
    {
        float offsetMagnitude = 0;

        foreach (LegController leg in plantedGroup)
        {
            LegInfo info = getLegInfo(leg);

            // maybe the following should be added back in?
            //if (info.planted)
            //	continue;

            Vector3 normalizedVelocity = info.getVelocity().normalized;
            Vector3 offset             = info.foot - leg.getDefaultPos();
            offsetMagnitude = Mathf.Max(offsetMagnitude, Vector3.Dot(offset / strideLength, -normalizedVelocity) + 1);
        }
        return(offsetMagnitude / 2);
    }
Exemple #6
0
    /// <summary>
    /// 리스트에서 각 아이템의 상세 능력치 딕셔너리로 가져오기 + dataManager에 있는 아이템 상세정보리스트에 정보 넣어주기
    /// </summary>
    public void GetCustomIteminfo(CatalogItem item)
    {
        Debug.Log("아이템 세부 정보 받기");
        var iteminfo = JsonConvert.DeserializeObject <Dictionary <string, string> >(item.CustomData);

        if (item.Tags[0] == "Weapon")
        {
            WeaponInfo info = new WeaponInfo();
            info.partName   = item.DisplayName; //이름 넣기
            info.partType   = item.Tags[0];     //무기인지 몸인지 다리인지 널기
            info.weapontype = iteminfo["type"]; //무기가 어깨형인지 탑형인지 팔형인지
            info.attack     = int.Parse(iteminfo["attack"]);
            info.weight     = int.Parse(iteminfo["weight"]);
            info.lange      = int.Parse(iteminfo["lange"]);
            DataManager.Instance.weaponInfo_List.Add(info);
            Debug.Log("무기 정보 추가");
        }
        else if (item.Tags[0] == "LowerBody")
        {
            LegInfo info = new LegInfo();
            Debug.Log(item.DisplayName + "의 이동속도: " + iteminfo["speed"]);
            Debug.Log(item.DisplayName + "의 총 하중: " + iteminfo["totalweight"]);
            Debug.Log(item.DisplayName + "의 방어력: " + iteminfo["amor"]);
            info.partName    = item.DisplayName;
            info.partType    = item.Tags[0];
            info.totalweight = int.Parse(iteminfo["totalweight"]);
            info.speed       = int.Parse(iteminfo["speed"]);
            info.amor        = int.Parse(iteminfo["amor"]);
            DataManager.Instance.legInfo_List.Add(info);
            Debug.Log("다리 정보 추가");
        }
        else
        {
            BodyInfo info = new BodyInfo();
            info.partName = item.DisplayName;              //이름 넣기
            info.partType = item.Tags[0];                  //무기인지 몸인지 다리인지 넣기
            info.bodytype = iteminfo["type"];              //몸통이 어깨인지 탑형인지 팔형인지
            info.weight   = int.Parse(iteminfo["weight"]); //무게
            info.hp       = int.Parse(iteminfo["hp"]);     //체력
            info.amor     = int.Parse(iteminfo["amor"]);   //방어력
            DataManager.Instance.bodyInfo_List.Add(info);
            Debug.Log("몸통 정보 추가");
        }
    }
Exemple #7
0
    protected void updateSteppingGroup(LegController[] steppingGroup, float stepPercent)
    {
        foreach (LegController leg in steppingGroup)
        {
            LegInfo info       = getLegInfo(leg);
            Vector3 stepOffset = leg.getDefaultPos() + info.getVelocity().normalized *strideLength;


            stepOffset.y += calculateAltitudeAdjustment(stepOffset, leg);
            Vector3 target = Vector3.Lerp(info.getLastPlanted(), stepOffset, stepPercent);

            target.y += Mathf.Min((1 - Mathf.Abs(stepPercent - 0.5f) * 2) * stepHeight, maxStepHeight);
            Vector3 diff = (target - info.foot);
            info.foot += diff.normalized * Mathf.Min(Mathf.Max(0.5f, diff.magnitude / 8), diff.magnitude);

#if UNITY_EDITOR
            if (debug)
            {
                drawPoint(info.foot, Color.blue, leg + "three");
            }
#endif
        }
    }
    void LegSectionGUI()
    {
        // Handle legs array

        if (lc.legs == null)
            lc.legs = new LegInfo[0];
        List<LegInfo> legs = new List<LegInfo>(lc.legs);
        if (legs.Count != legFoldouts.Count)
            legFoldouts = new List<bool>(new bool[legs.Count]);

        legsFoldout = EditorGUILayout.Foldout(legsFoldout, "Legs");
        if (legsFoldout) {
            int removeIndex = -1;
            for (int l=0; l<legs.Count; l++) {
                EditorGUIUtility.LookLikeControls(50);
                GUILayout.BeginHorizontal();
                string str = "Leg " + (l+1) + (legs[l].hip != null ? " (" + legs[l].hip.name + ")" : "");
                legFoldouts[l] = EditorGUILayout.Foldout(legFoldouts[l], str);
                if (GUILayout.Button("Remove", GUILayout.Width(80)))
                    removeIndex = l;
                GUILayout.EndHorizontal();

                if (legFoldouts[l]) {
                    GUI.changed = false;

                    EditorGUI.indentLevel++;

                    LegInfo li = legs[l];
                    li.hip = EditorGUILayout.ObjectField("Hip", li.hip, typeof(Transform), true) as Transform;
                    li.ankle = EditorGUILayout.ObjectField("Ankle", li.ankle, typeof(Transform), true) as Transform;
                    li.toe = EditorGUILayout.ObjectField("Toe", li.toe, typeof(Transform), true) as Transform;

                    GUILayout.BeginHorizontal();
                    EditorGUILayout.PrefixLabel("Foot");
                    EditorGUI.indentLevel--;
                    EditorGUIUtility.LookLikeControls(45, 0);
                    GUILayout.BeginVertical();
                    li.footWidth = EditorGUILayout.FloatField("Width", li.footWidth);
                    li.footLength = EditorGUILayout.FloatField("Length", li.footLength);
                    GUILayout.EndVertical();
                    GUILayout.BeginVertical();
                    li.footOffset.x = EditorGUILayout.FloatField("Offset", li.footOffset.x);
                    li.footOffset.y = EditorGUILayout.FloatField("Offset", li.footOffset.y);
                    GUILayout.EndVertical();
                    GUILayout.EndHorizontal();

                    if (GUI.changed) {
                        SceneView.RepaintAll();
                        lc.initialized = false;
                    }

                    EditorGUILayout.Space();
                }
            }

            // Not Used a leg?
            if (removeIndex >= 0) {
                legs.RemoveAt(removeIndex);
                lc.initialized = false;
                legFoldouts.RemoveAt(removeIndex);
            }

            // Add a leg?
            GUILayout.BeginHorizontal();
            GUILayout.Label("");
            if (GUILayout.Button("Add Leg", GUILayout.Width(80))) {
                LegInfo li = new LegInfo();
                if (legs.Count > 0) {
                    li.footWidth = legs[legs.Count-1].footWidth;
                    li.footLength = legs[legs.Count-1].footLength;
                    li.footOffset = legs[legs.Count-1].footOffset;
                }
                legs.Add(li);
                lc.initialized = false;
                legFoldouts.Add(true);
            }
            GUILayout.EndHorizontal();

            lc.legs = legs.ToArray();

            EditorGUIUtility.LookLikeControls(100);
        }

        EditorGUILayout.Space();
    }
	public override void OnInspectorGUI () {
		LegController lc = target as LegController;
		if (!lc)
			return;
		
		EditorGUIUtility.LookLikeControls();
		
		lc.groundPlaneHeight = EditorGUILayout.FloatField("Ground Height", lc.groundPlaneHeight);
		lc.groundedPose = EditorGUILayout.ObjectField("Grounded Pose", lc.groundedPose, typeof(AnimationClip), true) as AnimationClip;
		lc.rootBone = EditorGUILayout.ObjectField("Root Bone", lc.rootBone, typeof(Transform), true) as Transform;
		
		EditorGUILayout.Space();
		
		// Handle legs array
		
		List<LegInfo> legs = new List<LegInfo>(lc.legs);
		if (legs.Count != legFoldouts.Count)
			legFoldouts = new List<bool>(new bool[legs.Count]);
		
		legsFoldout = EditorGUILayout.Foldout(legsFoldout, "Legs");
		
		if (legsFoldout) {
			GUI.changed = false;
			
			int removeIndex = -1;
			for (int l=0; l<legs.Count; l++) {
				GUILayout.BeginHorizontal();
				string str = "Leg " + (l+1) + (legs[l].hip != null ? " (" + legs[l].hip.name + ")" : "");
				legFoldouts[l] = EditorGUILayout.Foldout(legFoldouts[l], str);
				if (GUILayout.Button("Remove", GUILayout.Width(80)))
					removeIndex = l;
				GUILayout.EndHorizontal();
				
				if (legFoldouts[l]) {
					EditorGUI.indentLevel++;
					
					LegInfo li = legs[l];
					li.hip = EditorGUILayout.ObjectField("Hip", li.hip, typeof(Transform), true) as Transform;
					li.ankle = EditorGUILayout.ObjectField("Ankle", li.ankle, typeof(Transform), true) as Transform;
					li.toe = EditorGUILayout.ObjectField("Toe", li.toe, typeof(Transform), true ) as Transform;
					
					GUILayout.BeginHorizontal();
					EditorGUILayout.PrefixLabel("Foot");
					GUILayout.BeginVertical();
					GUILayout.Label("Width", GUILayout.Width(40));
					GUILayout.Label("Length", GUILayout.Width(40));
					GUILayout.EndVertical();
					GUILayout.BeginVertical();
					li.footWidth = EditorGUILayout.FloatField(li.footWidth, GUILayout.Width(50));
					li.footLength = EditorGUILayout.FloatField(li.footLength, GUILayout.Width(50));
					GUILayout.EndVertical();
					GUILayout.BeginVertical();
					GUILayout.Label("Offset", GUILayout.Width(40));
					GUILayout.Label("Offset", GUILayout.Width(40));
					GUILayout.EndVertical();
					GUILayout.BeginVertical();
					li.footOffset.x = EditorGUILayout.FloatField(li.footOffset.x, GUILayout.Width(50));
					li.footOffset.y = EditorGUILayout.FloatField(li.footOffset.y, GUILayout.Width(50));
					GUILayout.EndVertical();
					GUILayout.EndHorizontal();
					
					EditorGUI.indentLevel--;
					
					EditorGUILayout.Space();
				}
			}
			
			// Remove a leg?
			if (removeIndex >= 0) {
				legs.RemoveAt(removeIndex);
				legFoldouts.RemoveAt(removeIndex);
			}
			
			// Add a leg?
			GUILayout.BeginHorizontal();
			GUILayout.Label("");
			if (GUILayout.Button("Add Leg", GUILayout.Width(80))) {
				LegInfo li = new LegInfo();
				if (legs.Count > 0) {
					li.footWidth = legs[legs.Count-1].footWidth;
					li.footLength = legs[legs.Count-1].footLength;
					li.footOffset = legs[legs.Count-1].footOffset;
				}
				legs.Add(li);
				legFoldouts.Add(true);
			}
			GUILayout.EndHorizontal();
			
			lc.legs = legs.ToArray();
		}
		
		EditorGUILayout.Space();
		
		// Handle animations array
		
		animsFoldout = EditorGUILayout.Foldout(animsFoldout, "Source Animations");
		
		if (animsFoldout) {
			GUI.changed = false;
			
			List<InspectorAnimationGroup> groups = new List<InspectorAnimationGroup>();
			groups.Add(new InspectorAnimationGroup(""));
			if (GUILayout.Button("Reset") || lc.sourceAnimations.Length == 0) {
				AnimationClip[] clips = AnimationUtility.GetAnimationClips(lc.GetComponent<Animation>());
				for (int c=0; c<clips.Length; c++) {
					MotionAnalyzer motion = new MotionAnalyzer();
					motion.animation = clips[c];
					//motion.motionGroup = "";
					groups[0].motions.Add(motion);
				}
				GUI.changed = true;
			}
			else {
				for (int m=0; m<lc.sourceAnimations.Length; m++) {
					MotionAnalyzer ma = lc.sourceAnimations[m];
					if (ma.motionGroup == null)
						ma.motionGroup = "";
					
					bool found = false;
					for (int g=0; g<groups.Count; g++) {
						if (ma.motionGroup == groups[g].name) {
							groups[g].motions.Add(ma);
							found = true;
						}
					}
					if (!found) {
						InspectorAnimationGroup group = new InspectorAnimationGroup(ma.motionGroup);
						group.motions.Add(ma);
						groups.Add(group);
					}
				}
			}
			groups.Add(new InspectorAnimationGroup("NewGroup"));
			groups.Add(new InspectorAnimationGroup("Remove"));
			
			string[] groupNames = new string[groups.Count];
			for (int g=0; g<groups.Count; g++) {
				groupNames[g] = groups[g].name;
			}
			groupNames[0] = "Ungrouped";
			
			for (int g=0; g<groups.Count-1; g++) {
				InspectorAnimationGroup group = groups[g];
				
				if (group.motions.Count == 0)
					continue;
				
				if (group.name == "") {
					GUILayout.Label("Ungrouped Animations");
				}
				else {
					GUILayout.BeginHorizontal();
					GUILayout.Label("Animation Group:", GUILayout.ExpandWidth(false));
					group.name = GUILayout.TextField(group.name, GUILayout.ExpandWidth(true));
					GUILayout.EndHorizontal();
				}
				
				for (int m=0; m<group.motions.Count; m++) {
					MotionAnalyzer ma = group.motions[m];
					
					GUILayout.BeginHorizontal();
					
					ma.animation = EditorGUILayout.ObjectField(ma.animation, typeof(AnimationClip), true) as AnimationClip;
					ma.motionType = (MotionType)EditorGUILayout.EnumPopup(ma.motionType, GUILayout.Width(70));
					
					//ma.alsoUseBackwards = GUILayout.Toggle(ma.alsoUseBackwards, "", GUILayout.Width(15));
					//ma.fixFootSkating = GUILayout.Toggle(ma.fixFootSkating, "", GUILayout.Width(15));
					int selectedGroup = EditorGUILayout.Popup(g, groupNames, GUILayout.Width(70));
					if (selectedGroup != g) {
						group.motions.Remove(ma);
						groups[selectedGroup].motions.Add(ma);
						GUI.changed = true;
					}
					
					GUILayout.Label(""+ma.nativeSpeed, GUILayout.Width(40));
					
					GUILayout.EndHorizontal();
				}
				
				if (GUILayout.Button("Add Animation to "+groupNames[g])) {
					MotionAnalyzer motion = new MotionAnalyzer();
					group.motions.Add(motion);
					GUI.changed = true;
				}
				
				EditorGUILayout.Space();
			}
			
			if (GUI.changed) {
				List<MotionAnalyzer> motions = new List<MotionAnalyzer>();
				for (int g=0; g<groups.Count-1; g++) {
					for (int m=0; m<groups[g].motions.Count; m++) {
						groups[g].motions[m].motionGroup = groups[g].name;
						motions.Add(groups[g].motions[m]);
					}
				}
				lc.sourceAnimations = motions.ToArray();
			}
		}
		
	}
    void LegSectionGUI()
    {
        // Handle legs array

        if (lc.legs == null)
        {
            lc.legs = new LegInfo[0];
        }
        List <LegInfo> legs = new List <LegInfo>(lc.legs);

        if (legs.Count != legFoldouts.Count)
        {
            legFoldouts = new List <bool>(new bool[legs.Count]);
        }

        legsFoldout = EditorGUILayout.Foldout(legsFoldout, "Legs");
        if (legsFoldout)
        {
            int removeIndex = -1;
            for (int l = 0; l < legs.Count; l++)
            {
                EditorGUIUtility.LookLikeControls(50);
                GUILayout.BeginHorizontal();
                string str = "Leg " + (l + 1) + (legs[l].hip != null ? " (" + legs[l].hip.name + ")" : "");
                legFoldouts[l] = EditorGUILayout.Foldout(legFoldouts[l], str);
                if (GUILayout.Button("Remove", GUILayout.Width(80)))
                {
                    removeIndex = l;
                }
                GUILayout.EndHorizontal();

                if (legFoldouts[l])
                {
                    GUI.changed = false;

                    EditorGUI.indentLevel++;

                    LegInfo li = legs[l];
                    li.hip   = EditorGUILayout.ObjectField("Hip", li.hip, typeof(Transform)) as Transform;
                    li.ankle = EditorGUILayout.ObjectField("Ankle", li.ankle, typeof(Transform)) as Transform;
                    li.toe   = EditorGUILayout.ObjectField("Toe", li.toe, typeof(Transform)) as Transform;

                    GUILayout.BeginHorizontal();
                    EditorGUILayout.PrefixLabel("Foot");
                    EditorGUI.indentLevel--;
                    EditorGUIUtility.LookLikeControls(45, 0);
                    GUILayout.BeginVertical();
                    li.footWidth  = EditorGUILayout.FloatField("Width", li.footWidth);
                    li.footLength = EditorGUILayout.FloatField("Length", li.footLength);
                    GUILayout.EndVertical();
                    GUILayout.BeginVertical();
                    li.footOffset.x = EditorGUILayout.FloatField("Offset", li.footOffset.x);
                    li.footOffset.y = EditorGUILayout.FloatField("Offset", li.footOffset.y);
                    GUILayout.EndVertical();
                    GUILayout.EndHorizontal();

                    if (GUI.changed)
                    {
                        SceneView.RepaintAll();
                        lc.initialized = false;
                    }

                    EditorGUILayout.Space();
                }
            }

            // Not Used a leg?
            if (removeIndex >= 0)
            {
                legs.RemoveAt(removeIndex);
                lc.initialized = false;
                legFoldouts.RemoveAt(removeIndex);
            }

            // Add a leg?
            GUILayout.BeginHorizontal();
            GUILayout.Label("");
            if (GUILayout.Button("Add Leg", GUILayout.Width(80)))
            {
                LegInfo li = new LegInfo();
                if (legs.Count > 0)
                {
                    li.footWidth  = legs[legs.Count - 1].footWidth;
                    li.footLength = legs[legs.Count - 1].footLength;
                    li.footOffset = legs[legs.Count - 1].footOffset;
                }
                legs.Add(li);
                lc.initialized = false;
                legFoldouts.Add(true);
            }
            GUILayout.EndHorizontal();

            lc.legs = legs.ToArray();

            EditorGUIUtility.LookLikeControls(100);
        }

        EditorGUILayout.Space();
    }
Exemple #11
0
        // Find the closest leg to a given point on a course. The leg might be None/None if the course has no legs.
        public static LegInfo FindClosestLeg(EventDB eventDB, CourseDesignator courseDesignator, PointF pt)
        {
            LegInfo closestLegSoFar = new LegInfo();
            float closestSoFar = 1E10F;

            foreach (LegInfo leg in EnumLegs(eventDB, courseDesignator)) {
                PointF temp;
                SymPath legPath = GetLegPath(eventDB, eventDB.GetCourseControl(leg.courseControlId1).control, eventDB.GetCourseControl(leg.courseControlId2).control);
                float distance = legPath.DistanceFromPoint(pt, out temp);
                if (distance < closestSoFar) {
                    closestSoFar = distance;
                    closestLegSoFar = leg;
                }
                else if (distance == closestSoFar) {
                    // Distances are equal. Use leg with the largest angle between the end points.
                    SymPath closestLegPath = GetLegPath(eventDB, eventDB.GetCourseControl(closestLegSoFar.courseControlId1).control, eventDB.GetCourseControl(closestLegSoFar.courseControlId2).control);
                    if (Geometry.Angle(legPath.FirstPoint, pt, legPath.LastPoint) >  Geometry.Angle(closestLegPath.FirstPoint, pt, closestLegPath.LastPoint)) {
                        closestSoFar = distance;
                        closestLegSoFar = leg;
                    }
                }
            }

            return closestLegSoFar;
        }
 public void Init()
 {
     instance = new LegInfo();
 }
	protected LegInfo getLegInfo(LegController leg) {
		LegInfo info;
		if (!legInfo.TryGetValue(leg, out info)) {
			info = new LegInfo(this, leg);
			legInfo.Add(leg, info);
		}
		return info;
	}
    public override void OnInspectorGUI()
    {
        LegController lc = target as LegController;

        if (!lc)
        {
            return;
        }

        EditorGUIUtility.LookLikeControls();

        lc.groundPlaneHeight = EditorGUILayout.FloatField("Ground Height", lc.groundPlaneHeight);
        lc.groundedPose      = EditorGUILayout.ObjectField("Grounded Pose", lc.groundedPose, typeof(AnimationClip)) as AnimationClip;
        lc.rootBone          = EditorGUILayout.ObjectField("Root Bone", lc.rootBone, typeof(Transform)) as Transform;

        EditorGUILayout.Space();

        // Handle legs array

        List <LegInfo> legs = new List <LegInfo>(lc.legs);

        if (legs.Count != legFoldouts.Count)
        {
            legFoldouts = new List <bool>(new bool[legs.Count]);
        }

        legsFoldout = EditorGUILayout.Foldout(legsFoldout, "Legs");

        if (legsFoldout)
        {
            GUI.changed = false;

            int removeIndex = -1;
            for (int l = 0; l < legs.Count; l++)
            {
                GUILayout.BeginHorizontal();
                string str = "Leg " + (l + 1) + (legs[l].hip != null ? " (" + legs[l].hip.name + ")" : "");
                legFoldouts[l] = EditorGUILayout.Foldout(legFoldouts[l], str);
                if (GUILayout.Button("Remove", GUILayout.Width(80)))
                {
                    removeIndex = l;
                }
                GUILayout.EndHorizontal();

                if (legFoldouts[l])
                {
                    EditorGUI.indentLevel++;

                    LegInfo li = legs[l];
                    li.hip   = EditorGUILayout.ObjectField("Hip", li.hip, typeof(Transform)) as Transform;
                    li.ankle = EditorGUILayout.ObjectField("Ankle", li.ankle, typeof(Transform)) as Transform;
                    li.toe   = EditorGUILayout.ObjectField("Toe", li.toe, typeof(Transform)) as Transform;

                    GUILayout.BeginHorizontal();
                    EditorGUILayout.PrefixLabel("Foot");
                    GUILayout.BeginVertical();
                    GUILayout.Label("Width", GUILayout.Width(40));
                    GUILayout.Label("Length", GUILayout.Width(40));
                    GUILayout.EndVertical();
                    GUILayout.BeginVertical();
                    li.footWidth  = EditorGUILayout.FloatField(li.footWidth, GUILayout.Width(50));
                    li.footLength = EditorGUILayout.FloatField(li.footLength, GUILayout.Width(50));
                    GUILayout.EndVertical();
                    GUILayout.BeginVertical();
                    GUILayout.Label("Offset", GUILayout.Width(40));
                    GUILayout.Label("Offset", GUILayout.Width(40));
                    GUILayout.EndVertical();
                    GUILayout.BeginVertical();
                    li.footOffset.x = EditorGUILayout.FloatField(li.footOffset.x, GUILayout.Width(50));
                    li.footOffset.y = EditorGUILayout.FloatField(li.footOffset.y, GUILayout.Width(50));
                    GUILayout.EndVertical();
                    GUILayout.EndHorizontal();

                    EditorGUI.indentLevel--;

                    EditorGUILayout.Space();
                }
            }

            // Remove a leg?
            if (removeIndex >= 0)
            {
                legs.RemoveAt(removeIndex);
                legFoldouts.RemoveAt(removeIndex);
            }

            // Add a leg?
            GUILayout.BeginHorizontal();
            GUILayout.Label("");
            if (GUILayout.Button("Add Leg", GUILayout.Width(80)))
            {
                LegInfo li = new LegInfo();
                if (legs.Count > 0)
                {
                    li.footWidth  = legs[legs.Count - 1].footWidth;
                    li.footLength = legs[legs.Count - 1].footLength;
                    li.footOffset = legs[legs.Count - 1].footOffset;
                }
                legs.Add(li);
                legFoldouts.Add(true);
            }
            GUILayout.EndHorizontal();

            lc.legs = legs.ToArray();
        }

        EditorGUILayout.Space();

        // Handle animations array

        animsFoldout = EditorGUILayout.Foldout(animsFoldout, "Source Animations");

        if (animsFoldout)
        {
            GUI.changed = false;

            List <InspectorAnimationGroup> groups = new List <InspectorAnimationGroup>();
            groups.Add(new InspectorAnimationGroup(""));
            if (GUILayout.Button("Reset") || lc.sourceAnimations.Length == 0)
            {
                AnimationClip[] clips = AnimationUtility.GetAnimationClips(lc.animation);
                for (int c = 0; c < clips.Length; c++)
                {
                    MotionAnalyzer motion = new MotionAnalyzer();
                    motion.animation = clips[c];
                    //motion.motionGroup = "";
                    groups[0].motions.Add(motion);
                }
                GUI.changed = true;
            }
            else
            {
                for (int m = 0; m < lc.sourceAnimations.Length; m++)
                {
                    MotionAnalyzer ma = lc.sourceAnimations[m];
                    if (ma.motionGroup == null)
                    {
                        ma.motionGroup = "";
                    }

                    bool found = false;
                    for (int g = 0; g < groups.Count; g++)
                    {
                        if (ma.motionGroup == groups[g].name)
                        {
                            groups[g].motions.Add(ma);
                            found = true;
                        }
                    }
                    if (!found)
                    {
                        InspectorAnimationGroup group = new InspectorAnimationGroup(ma.motionGroup);
                        group.motions.Add(ma);
                        groups.Add(group);
                    }
                }
            }
            groups.Add(new InspectorAnimationGroup("NewGroup"));
            groups.Add(new InspectorAnimationGroup("Remove"));

            string[] groupNames = new string[groups.Count];
            for (int g = 0; g < groups.Count; g++)
            {
                groupNames[g] = groups[g].name;
            }
            groupNames[0] = "Ungrouped";

            for (int g = 0; g < groups.Count - 1; g++)
            {
                InspectorAnimationGroup group = groups[g];

                if (group.motions.Count == 0)
                {
                    continue;
                }

                if (group.name == "")
                {
                    GUILayout.Label("Ungrouped Animations");
                }
                else
                {
                    GUILayout.BeginHorizontal();
                    GUILayout.Label("Animation Group:", GUILayout.ExpandWidth(false));
                    group.name = GUILayout.TextField(group.name, GUILayout.ExpandWidth(true));
                    GUILayout.EndHorizontal();
                }

                for (int m = 0; m < group.motions.Count; m++)
                {
                    MotionAnalyzer ma = group.motions[m];

                    GUILayout.BeginHorizontal();

                    ma.animation  = EditorGUILayout.ObjectField(ma.animation, typeof(AnimationClip)) as AnimationClip;
                    ma.motionType = (MotionType)EditorGUILayout.EnumPopup(ma.motionType, GUILayout.Width(70));

                    //ma.alsoUseBackwards = GUILayout.Toggle(ma.alsoUseBackwards, "", GUILayout.Width(15));
                    //ma.fixFootSkating = GUILayout.Toggle(ma.fixFootSkating, "", GUILayout.Width(15));
                    int selectedGroup = EditorGUILayout.Popup(g, groupNames, GUILayout.Width(70));
                    if (selectedGroup != g)
                    {
                        group.motions.Remove(ma);
                        groups[selectedGroup].motions.Add(ma);
                        GUI.changed = true;
                    }

                    GUILayout.Label("" + ma.nativeSpeed, GUILayout.Width(40));

                    GUILayout.EndHorizontal();
                }

                if (GUILayout.Button("Add Animation to " + groupNames[g]))
                {
                    MotionAnalyzer motion = new MotionAnalyzer();
                    group.motions.Add(motion);
                    GUI.changed = true;
                }

                EditorGUILayout.Space();
            }

            if (GUI.changed)
            {
                List <MotionAnalyzer> motions = new List <MotionAnalyzer>();
                for (int g = 0; g < groups.Count - 1; g++)
                {
                    for (int m = 0; m < groups[g].motions.Count; m++)
                    {
                        groups[g].motions[m].motionGroup = groups[g].name;
                        motions.Add(groups[g].motions[m]);
                    }
                }
                lc.sourceAnimations = motions.ToArray();
            }
        }
    }