Newer
Older
HoloAnatomy / Assets / HoloToolkit-Examples / MotionControllers-GrabMechanics / Scripts / BaseScalable.cs
SURFACEBOOK2\jackwynne on 25 May 2018 4 KB v1
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See LICENSE in the project root for license information.

using System.Collections;
using UnityEngine;

namespace HoloToolkit.Unity.InputModule.Examples.Grabbables
{
    /// <summary>
    /// class responsible for two hand scale. Objects with a child of this class attached 
    /// </summary>
    public abstract class BaseScalable : MonoBehaviour
    {
        [SerializeField]
        private bool scaleByDistance = true;

        [SerializeField]
        private BaseGrabbable grabbable;

        private bool readyToScale;
        private float snapShotOfScale;
        private int minScalarNumForScale = 2;
        private bool currentlyScaling;
        private float snapShotDistance;

        protected virtual void Awake()
        {
            if (grabbable == null)
            {
                grabbable = gameObject.GetComponent<BaseGrabbable>();
            }
        }

        /// <summary>
        /// scale needs to subscribe to grab events in order to add more scalars to the list of scalars
        /// </summary>
        protected virtual void OnEnable()
        {
            grabbable.OnGrabbed += OnGrabbed;
        }

        protected virtual void OnDisable()
        {
            grabbable.OnGrabbed -= OnGrabbed;
        }

        /// <summary>
        /// We have two options when we attempt to scale: the first is by velocity and the second is based on the distance between the 
        /// two+ grabbers
        /// </summary>
        public void AttemptScale()
        {
            Debug.Log("Attempt scale");
            BaseGrabber[] activeGrabbers = GetComponent<BaseGrabbable>().ActiveGrabbers;

            if (GetComponent<BaseGrabbable>().ActiveGrabbers.Length >= minScalarNumForScale)
            {
                // Distance
                // snapshot a standard distance that the controls are when the scalable object is engaged
                // That standard distance between controllers corresponds to the localScale * scaleMultiplier
                if (scaleByDistance)
                {
                    if (activeGrabbers.Length >= minScalarNumForScale)
                    {
                        //later this should be average distance between all controllers attached.
                        float dist = Vector3.Distance(activeGrabbers[0].GrabHandle.position, activeGrabbers[1].GrabHandle.position);
                        snapShotDistance = dist;
                        //TODO: scale should not be recorded from x axis alone
                        snapShotOfScale = transform.localScale.x;
                        currentlyScaling = true;
                        StartCoroutine(PerformScaling());
                    }
                }
            }
        }

        /// <summary>
        /// Adding a grabber object to the list of scalars means adding it to the list of scalars and always attempting a scale if there are enough scalars attached
        /// </summary>
        /// <param name="baseGrab"></param>
        public void OnGrabbed(BaseGrabbable baseGrab)
        {
            if (!currentlyScaling)
            {
                AttemptScale();
            }
        }

        /// <summary>
        /// scaling can be amplified by increasing the scaling multiplier 
        /// scaling functionality can also be modified by recording a distance from the user. 
        /// (For example, an object that is further away might scale up more because it is further away from the user)
        /// </summary>
        public virtual IEnumerator PerformScaling()
        {
            currentlyScaling = true;

            while (currentlyScaling)
            {
                //  let go
                if (grabbable.GrabState == GrabStateEnum.Inactive)
                {
                    currentlyScaling = false;
                    yield break;
                }

                BaseGrabber[] activeGrabbers = grabbable.ActiveGrabbers;

                // If enough grabbers have grabbed
                if (activeGrabbers.Length >= minScalarNumForScale)
                {
                    float currDistance = Vector3.Distance(activeGrabbers[0].GrabHandle.position, activeGrabbers[1].GrabHandle.position);
                    transform.localScale = Vector3.one * ((currDistance / snapShotDistance) * snapShotOfScale)  /*scaleMultiplier */ /* distFromUser*/;

                }

                yield return 0;
            }

            currentlyScaling = false;
        }
    }
}