using System; using System.Collections; using System.Collections.Generic; using System.Linq; using UnityEngine; // Demolition support // Reset namespace RayFire { // Class to store animation cache [Serializable] public class RFCache { // Vars public string name; public List act; public List pos; public List rot; public Transform transform; // Constructor public RFCache (Transform parent, Transform tm) { act = new List(); pos = new List(); rot = new List(); transform = tm; name = tm.name; if (tm.parent != parent) { Transform lastParent = tm.parent; while (parent != lastParent) { name = name.Insert (0, "/"); name = name.Insert (0, lastParent.name); lastParent = lastParent.parent; } } } } [SelectionBase] [DisallowMultipleComponent] [AddComponentMenu ("RayFire/Rayfire Recorder")] [HelpURL ("https://rayfirestudios.com/unity-online-help/components/unity-recorder-component/")] public class RayfireRecorder : MonoBehaviour { public enum AnimatorType { Disabled = 0, Record = 2, Play = 8 } public AnimatorType mode = AnimatorType.Record; public bool recordOnStart = true; public string clipName; public float duration = 5f; public int rate = 15; public bool reduceKeys = true; public float threshold; public bool playOnStart; public AnimationClip animationClip; public RuntimeAnimatorController controller; public bool setToKinematic = true; public bool recorder; public float recordedTime; private int stateNameHash; private string assetFolder; private string clipFolder = "RayFireRecords/"; private float stepTime; private Animator animator; private List tmList; private List cacheList; private List timeList; /// ////////////////////////////////////////////////// /// Common /// ////////////////////////////////////////////////// // Awake void Awake() { // Set vars SetVariables(); } // Start void Start() { // Collect rigid SetRigid(); // Start ops if (mode == AnimatorType.Record && recordOnStart == true) StartRecord(); else if (mode == AnimatorType.Play && playOnStart == true) StartPlay(); } // Set rigid props void SetRigid() { if (mode == AnimatorType.Play) { List rigidList = gameObject.GetComponentsInChildren().ToList(); foreach (RayfireRigid rigid in rigidList) { if (rigid.physics.exclude == false) { rigid.physics.rec = true; // Check for kinematic state if (setToKinematic == true) if (rigid.simulationType != SimType.Static || rigid.simulationType == SimType.Kinematic) { rigid.simulationType = SimType.Kinematic; RFPhysic.SetSimulationType (rigid.physics.rigidBody, rigid.simulationType, rigid.objectType, rigid.physics.useGravity, rigid.physics.solverIterations); } } } } } // Set vars void SetVariables() { if (mode != AnimatorType.Disabled) { animator = GetComponent(); // Get list of cached transforms tmList = gameObject.GetComponentsInChildren (false).ToList(); tmList.Remove (transform); // No children if (tmList.Count == 0) { Debug.Log ("RayFire Record: " + gameObject.name + " Mode set to " + mode.ToString() + " but object has no children. Mode set to None.", gameObject); mode = AnimatorType.Disabled; return; } // Record set SetModeRecord(); // Play set SetModePlay(); } } // Record set void SetModeRecord() { if (mode == AnimatorType.Record) { // Null active controller if (animator != null) animator.runtimeAnimatorController = null; // Prepare cache list cacheList = new List(); if (tmList.Count > 0) for (int i = 0; i < tmList.Count; i++) cacheList.Add (new RFCache (transform, tmList[i])); // Time list timeList = new List(); // Set time step stepTime = 1f / rate; // Clip folder assetFolder = "Assets/" + clipFolder; } } // Play set void SetModePlay() { if (mode == AnimatorType.Play) { // Check for null controller if (controller == null) { Debug.Log ("RayFire Record: " + gameObject.name + " Mode set to " + mode.ToString() + " but controller is not defined. Mode set to None.", gameObject); mode = AnimatorType.Disabled; return; } // Check for null controller if (animationClip == null) { Debug.Log ("RayFire Record: " + gameObject.name + " Mode set to " + mode.ToString() + " but animation clip is not defined. Mode set to None.", gameObject); mode = AnimatorType.Disabled; return; } // Check for clip in controller bool hasClip = false; foreach (var anim in controller.animationClips) if (anim == animationClip) hasClip = true; if (hasClip == false) { Debug.Log ("RayFire Record: " + gameObject.name + " Mode set to " + mode.ToString() + " but animation clip is not defined in controller. Mode set to None.", gameObject); mode = AnimatorType.Disabled; return; } // Create animator if (animator == null) animator = gameObject.AddComponent(); animator.updateMode = AnimatorUpdateMode.AnimatePhysics; // Set defined controller animator.runtimeAnimatorController = controller; } } // Reset void Reset() { clipName = gameObject.name; } // ////////////////////////////////////////////////// // Record // ////////////////////////////////////////////////// // Start record public void StartRecord() { // Stop if (cacheList.Count == 0) return; // Start recording cor StartCoroutine (RecordCor()); } // Record tm every frame IEnumerator RecordCor() { recorder = true; while (recorder == true) { // Save data timeList.Add (recordedTime); for (int i = 0; i < tmList.Count; i++) { if (tmList[i] != null) { cacheList[i].act.Add (tmList[i].gameObject.activeSelf); cacheList[i].pos.Add (tmList[i].localPosition); cacheList[i].rot.Add (tmList[i].localRotation); } } // Set time recordedTime += stepTime; // Wait yield return new WaitForSeconds (stepTime); // Temp if (duration > 0 && recordedTime > duration) StopRecord(); } // Create clip #if UNITY_EDITOR RFRecorder.CreateAnimationClip (cacheList, timeList, threshold, rate, assetFolder, clipName, reduceKeys); #endif } // Stop record public void StopRecord() { recorder = false; } // ////////////////////////////////////////////////// // Play // ////////////////////////////////////////////////// // Start play public void StartPlay() { if (mode == AnimatorType.Play) animator.Play (animationClip.name); } } }