forked from cgvr/DeltaVR
		
	
		
			
				
	
	
		
			119 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			119 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
using System;
 | 
						|
using System.Collections.Generic;
 | 
						|
using UnityEngine.Events;
 | 
						|
 | 
						|
namespace UnityEngine.XR.Content.Interaction
 | 
						|
{
 | 
						|
    /// <summary>
 | 
						|
    /// Rewinds positional changes made this object and its children to restore it back to a 'complete' object
 | 
						|
    /// </summary>
 | 
						|
    public class Unbreakable : MonoBehaviour
 | 
						|
    {
 | 
						|
        [Serializable] public class RestoreEvent : UnityEvent<GameObject> { }
 | 
						|
 | 
						|
        [SerializeField]
 | 
						|
        [Tooltip("How long to wait before rewinding the object's motion.")]
 | 
						|
        float m_RestTime = 1.0f;
 | 
						|
 | 
						|
        [SerializeField]
 | 
						|
        [Tooltip("How long to spend restoring the object.")]
 | 
						|
        float m_RestoreTime = 2.0f;
 | 
						|
 | 
						|
        [SerializeField]
 | 
						|
        [Tooltip("A 'non broken' object to replace this object with when motion rewinding is complete.")]
 | 
						|
        GameObject m_RestoredVersion;
 | 
						|
 | 
						|
        [SerializeField]
 | 
						|
        [Tooltip("Events to fire when the 'non broken' object is restored.")]
 | 
						|
        RestoreEvent m_OnRestore = new RestoreEvent();
 | 
						|
 | 
						|
        bool m_Resting = true;
 | 
						|
        float m_Timer = 0.0f;
 | 
						|
        bool m_Restored = false;
 | 
						|
 | 
						|
        struct ChildPoses
 | 
						|
        {
 | 
						|
            internal Pose m_StartPose;
 | 
						|
            internal Pose m_EndPose;
 | 
						|
        }
 | 
						|
 | 
						|
        Dictionary<Transform, ChildPoses> m_ChildPoses = new Dictionary<Transform, ChildPoses>();
 | 
						|
        List<Transform> m_ChildTransforms = new List<Transform>();
 | 
						|
 | 
						|
        /// <summary>
 | 
						|
        /// Events to fire when the 'non broken' object is restored.
 | 
						|
        /// </summary>
 | 
						|
        public RestoreEvent onRestore => m_OnRestore;
 | 
						|
 | 
						|
        void Start()
 | 
						|
        {
 | 
						|
            // Go through all children
 | 
						|
            GetComponentsInChildren(m_ChildTransforms);
 | 
						|
 | 
						|
            // Cache their start positions
 | 
						|
            foreach (var child in m_ChildTransforms)
 | 
						|
            {
 | 
						|
                m_ChildPoses.Add(child, new ChildPoses { m_StartPose = new Pose(child.position, child.rotation) });
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        void Update()
 | 
						|
        {
 | 
						|
            if (m_Restored)
 | 
						|
                return;
 | 
						|
 | 
						|
            // Phase 1 - wait to rewind
 | 
						|
            // Phase 2 - rewind all positions, using a an inverse quadratic curve
 | 
						|
            // Phase 3 - replace object, destroy this one
 | 
						|
 | 
						|
            m_Timer += Time.deltaTime;
 | 
						|
 | 
						|
            if (m_Resting)
 | 
						|
            {
 | 
						|
                if (m_Timer > m_RestTime)
 | 
						|
                {
 | 
						|
                    m_Timer = 0.0f;
 | 
						|
                    m_Resting = false;
 | 
						|
 | 
						|
                    foreach (var child in m_ChildTransforms)
 | 
						|
                    {
 | 
						|
                        if (child == null)
 | 
						|
                            continue;
 | 
						|
 | 
						|
                        var poses = m_ChildPoses[child];
 | 
						|
                        poses.m_EndPose = new Pose(child.position, child.rotation);
 | 
						|
                        m_ChildPoses[child] = poses;
 | 
						|
                    }
 | 
						|
                }
 | 
						|
            }
 | 
						|
            else
 | 
						|
            {
 | 
						|
                var timePercent = m_Timer / m_RestoreTime;
 | 
						|
                if (timePercent > 1.0f)
 | 
						|
                {
 | 
						|
                    m_Restored = true;
 | 
						|
                    var restoredVersion = Instantiate(m_RestoredVersion, transform.position, transform.rotation);
 | 
						|
                    m_OnRestore.Invoke(restoredVersion);
 | 
						|
                    Destroy(gameObject);
 | 
						|
                }
 | 
						|
                else
 | 
						|
                {
 | 
						|
                    timePercent = 1.0f - ((1.0f - timePercent) * (1.0f - timePercent));
 | 
						|
 | 
						|
                    foreach (var child in m_ChildTransforms)
 | 
						|
                    {
 | 
						|
                        if (child == null)
 | 
						|
                            continue;
 | 
						|
 | 
						|
                        var poses = m_ChildPoses[child];
 | 
						|
                        var lerpedPosition = Vector3.Lerp(poses.m_EndPose.position, poses.m_StartPose.position, timePercent);
 | 
						|
                        var lerpedRotation = Quaternion.Slerp(poses.m_EndPose.rotation, poses.m_StartPose.rotation, timePercent);
 | 
						|
                        child.position = lerpedPosition;
 | 
						|
                        child.rotation = lerpedRotation;
 | 
						|
                    }
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 |