using UnityEngine; namespace Passer.CreatureControl { public class Creature : MonoBehaviour { /// The target bones rig /// The target bones rig contain the target pose of the creature /// The creature movements will try to move the creature such that the target pose is reached /// as closely as possible public Transform model; public TargetRig targetRig; public Vector3 targetToModelTranslation; public Quaternion targetToModelRotation; #region Init /// /// Ensure a target rig is available /// /// The name of the target rig resource /// True when the creature rig has been updated /// The parameter is used to instantiate a new target rig when none has been found. public bool CheckTargetRig(string targetRigResourceName) { if (this.targetRig == null) { // See if there is a target rig, but we just haven't found it this.targetRig = this.GetComponentInChildren(); if (this.targetRig == null) { GameObject targetsRigPrefab = Resources.Load(targetRigResourceName); GameObject targetRig = Instantiate(targetsRigPrefab); targetRig.name = "Target Rig"; targetRig.transform.SetPositionAndRotation(this.transform.position, this.transform.rotation); targetRig.transform.SetParent(this.transform); this.targetRig = targetRig.GetComponent(); } return true; } else return false; } public virtual bool CheckTargetRig() { return CheckTargetRig("TargetRig"); } /// /// Ensure that the creature rig is available /// /// True when the creature rig has been updated public bool CheckModel() { if (this.model == null) { SkinnedMeshRenderer[] skinnedMeshRenderers = this.GetComponentsInChildren(); foreach (SkinnedMeshRenderer skinnedMeshRenderer in skinnedMeshRenderers) { Transform rendererParent = skinnedMeshRenderer.transform.parent; if (this.model == null || this.model == rendererParent) this.model = rendererParent; else Debug.LogWarning("Unclear model root"); } return this.model != null; } else return false; } #endregion Init #region Start protected virtual void Start() { this.CheckTargetRig(); this.CheckModel(); this.targetRig.MatchTo(this); } #endregion Start #region Update public virtual void Update() { if (this.targetRig == null) return; UpdatePose(); // copy animator root motion to the humanoid this.transform.SetPositionAndRotation(targetRig.transform.position, targetRig.transform.rotation); // As target rig is probably a child of this.transform, // We need to restore the position/rotation of the targetsRig. targetRig.transform.SetPositionAndRotation(this.transform.position, this.transform.rotation); } public void UpdatePose() { if (this.targetRig == null) return; this.targetRig.PoseLimbs(); UpdateBones(); } public virtual void UpdateBones() { Vector3 newPosition = this.targetRig.transform.position + this.targetToModelTranslation; Quaternion newOrientation = this.targetRig.transform.rotation * this.targetToModelRotation; this.model.SetPositionAndRotation(newPosition, newOrientation); } #endregion Update void OnDrawGizmos() { // This ensures that the model is always following the target rig if (Application.isPlaying == false) { this.UpdatePose(); } } } }