//This script is for demo purposes only and is not required for the animations to work. //Human Basic Motions //Kevin Iglesias //www.keviniglesias.com using UnityEngine; using UnityEngine.UI; using System.Collections.Generic; #if UNITY_EDITOR using UnityEditor; #endif namespace KevinIglesias { [System.Serializable] public class AnimationEntry { public string displayName; public string folderName; public string folderPath; public int folderLevel; public AnimationClip clip; public GameObject[] prop; public bool disableSpineProxy; [HideInInspector] public Button animationButton; } [System.Serializable] public class CharacterEntry { public GameObject characterObject; public Transform characterTransform; public Animator animator; public Transform leftFoot; public Transform rightFoot; [HideInInspector] public Transform spineProxyBone; [HideInInspector] public Button characterButton; } public class HumanBasicMotionsDemo : MonoBehaviour { [Header("Camera")] [SerializeField] private Transform cameraPivot; [SerializeField] private Camera targetCamera; [SerializeField] private float zoomStep = 5f; [SerializeField] private float minFOV = 35f; [SerializeField] private float maxFOV = 75f; [SerializeField] private float rotationSpeed = 120f; private float rotationInput = 0f; [Header("Base")] [SerializeField] private Transform baseT; [SerializeField] private Material baseMaterial; [SerializeField] private float baseTreadmillMultiplier = 0.5f; private float baseOffsetX; private float baseOffsetY; private float baseUVRotation; [Header("Shadow")] [SerializeField] private Transform shadowT; [SerializeField] private SpriteRenderer shadowSprite; [SerializeField] private float shadowFloorY = 0.001f; [SerializeField] private float groundedScale = 0.6f; [SerializeField] private float groundedAlpha = 0.78f; [SerializeField] private float maxJumpHeight = 1f; [SerializeField] private float airScale = 1f; [SerializeField] private float airAlpha = 0.05f; private Transform currentLeftFoot; private Transform currentRightFoot; [SerializeField] private float shadowFootPadding = 0.35f; [SerializeField] private float shadowMinScale = 0.75f; [SerializeField] private float shadowMaxScale = 2.25f; [Header("Background")] [SerializeField] private Material backgroundMaterial; [SerializeField] private Vector3 backgroundLightDir = new Vector3(0f, -0.1f, 1f); [Header("UI")] [SerializeField] private Transform zoomIn; [SerializeField] private Transform zoomOut; [SerializeField] private Transform leftArrow; [SerializeField] private Transform rightArrow; [SerializeField] private Color normalButtonColor = Color.white; [SerializeField] private Color selectedButtonColor = Color.black; [SerializeField] private Color normalTextColor = Color.black; [SerializeField] private Color selectedTextColor = Color.white; [SerializeField] private Vector3 normalScale = Vector3.one; [SerializeField] private Vector3 pressedScale = Vector3.one * 0.85f; [Header("Characters")] [SerializeField] private CharacterEntry[] availableCharacters; [SerializeField] private int currentCharacterIndex = 0; [SerializeField] private GameObject characterUIPrefab; [SerializeField] private Transform charactersUIRoot; [SerializeField] private Transform character; [SerializeField] private Animator animator; private Button currentSelectedCharacterButton; private bool characterInitialized = false; [Header("Animations")] [SerializeField] private AnimationEntry[] availableAnimations; [SerializeField] private Text currentAnimationText; [SerializeField] private Text currentAnimationFolderText; [SerializeField] private Transform animationsUIRoot; [SerializeField] private GameObject folderButtonPrefab; [SerializeField] private GameObject animationUIPrefab; [SerializeField] private string currentAnimationName; [SerializeField] private string currentUpperAnimationName; private int baseAnimationToPlay = 0; private int upperAnimationToPlay = -1; private AnimatorOverrideController overrideController; private string currentFolder = ""; private Button currentSelectedAnimationButton; private GameObject[] currentBaseProps; private GameObject[] currentUpperProps; [SerializeField] private int animationType = 0; [SerializeField] private Button baseTypeButton; [SerializeField] private Button upperTypeButton; ///UNITY DEFAULT FUNCTIONS private void Start() { ResetBase(); CreateAnimationButtons(); CreateCharacterButtons(); if(availableCharacters != null && availableCharacters.Length > 0) { overrideController = new AnimatorOverrideController(availableCharacters[0].animator.runtimeAnimatorController); } for(int i = 0; i < availableCharacters.Length; i++) { if(availableCharacters[i].characterObject != null) { availableCharacters[i].characterObject.SetActive(false); Transform[] transforms = availableCharacters[i].characterObject.GetComponentsInChildren(true); foreach(Transform t in transforms) { if (t.name == "B-spineProxy") { availableCharacters[i].spineProxyBone = t; break; } } } } SelectCharacter(currentCharacterIndex); SelectCharacterButton(availableCharacters[currentCharacterIndex].characterButton); int defaultIndex = FindAnimationIndex("HumanM@Idle01"); if(defaultIndex >= 0) { PlayAnimation(defaultIndex, 0); if(defaultIndex < availableAnimations.Length) { SelectAnimationButton(availableAnimations[defaultIndex].animationButton); } } SetButtonSelected(baseTypeButton, true); } private void Update() { baseT.position = new Vector3(character.position.x, 0, character.position.z); UpdateBlobShadowFromFeet(); UpdateBaseMaterialOffset(); Vector3 correctedLightDir = cameraPivot.rotation * backgroundLightDir; backgroundMaterial.SetVector("_LightDir", new Vector4(correctedLightDir.x, correctedLightDir.y, correctedLightDir.z, 0f)); if(rotationInput != 0f) { cameraPivot.Rotate(new Vector3(0f, rotationInput * rotationSpeed * Time.deltaTime, 0f), Space.World); } character.position = new Vector3(0, character.position.y, 0); } private void FixedUpdate() { Vector3 correctedLightDir = cameraPivot.rotation * backgroundLightDir; backgroundMaterial.SetVector("_LightDir", new Vector4(correctedLightDir.x, correctedLightDir.y, correctedLightDir.z, 0f)); } private void LateUpdate() { Vector3 correctedLightDir = cameraPivot.rotation * backgroundLightDir; backgroundMaterial.SetVector("_LightDir", new Vector4(correctedLightDir.x, correctedLightDir.y, correctedLightDir.z, 0f)); } private void OnDisable() { ResetBase(); } /// ///CHARACTER SELECTION public void SelectCharacter(int index) { if(availableCharacters == null || index < 0 || index >= availableCharacters.Length) { return; } if(characterInitialized && index == currentCharacterIndex) { return; } characterInitialized = true; currentCharacterIndex = index; for(int i = 0; i < availableCharacters.Length; i++) { CharacterEntry entry = availableCharacters[i]; bool selected = i == index; if(entry.animator != null) { entry.animator.runtimeAnimatorController = selected ? overrideController : null; } if(entry.characterObject != null) { entry.characterObject.SetActive(selected); } } CharacterEntry selectedEntry = availableCharacters[index]; character = selectedEntry.characterTransform; animator = selectedEntry.animator; currentLeftFoot = selectedEntry.leftFoot; currentRightFoot = selectedEntry.rightFoot; if(animator != null) { animator.Rebind(); animator.Update(0f); } ResetProps(); ResetBase(); string equivalentAnimationName = currentAnimationName; if(index == 1) { equivalentAnimationName = currentAnimationName.Replace("HumanM@", "HumanF@"); }else{ equivalentAnimationName = currentAnimationName.Replace("HumanF@", "HumanM@"); } int equivalentAnimation = FindAnimationIndex(equivalentAnimationName); if(equivalentAnimation >= 0) { PlayAnimation(equivalentAnimation, 0); }else{ PlayAnimation(baseAnimationToPlay, 0); } string equivalentUpperAnimationName = currentUpperAnimationName; if(index == 1) { equivalentUpperAnimationName = currentUpperAnimationName.Replace("HumanM@", "HumanF@"); }else{ equivalentUpperAnimationName = currentUpperAnimationName.Replace("HumanF@", "HumanM@"); } int equivalentUpperAnimation = FindAnimationIndex(equivalentUpperAnimationName); if(equivalentUpperAnimation >= 0) { PlayAnimation(equivalentUpperAnimation, 1); }else{ if(upperAnimationToPlay >= 0) { PlayAnimation(upperAnimationToPlay, 1); }else{ ClearUpperAnimation(); } } string newFolder = currentFolder; if(index == 1) { newFolder = currentFolder.Replace("Male", "Female"); }else{ newFolder = currentFolder.Replace("Female", "Male"); } ShowFolder(newFolder); SelectCurrentAnimationButtonInOpenFolder(); } private void CreateCharacterButtons() { if(characterUIPrefab == null || charactersUIRoot == null || availableCharacters == null) { return; } for(int i = 0; i < availableCharacters.Length; i++) { int index = i; GameObject buttonGO = Instantiate(characterUIPrefab, charactersUIRoot); Button button = buttonGO.GetComponent