< Summary

Class:XRKnob
Assembly:Test
File(s):E:/Unity/Unity Project/VR-Basics/Assets/_Course Library/Scripts/Core/XRKnob.cs
Covered lines:61
Uncovered lines:6
Coverable lines:67
Total lines:173
Line coverage:91% (61 of 67)
Covered branches:0
Total branches:0
Covered methods:15
Total methods:15
Method coverage:100% (15 of 15)

Coverage History

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
XRKnob()0%000100%
Start()0%000100%
OnEnable()0%000100%
OnDisable()0%000100%
StartTurn(...)0%000100%
EndTurn(...)0%000100%
ProcessInteractable(...)0%00053.85%
FindRotationValue()0%000100%
ApplyRotation(...)0%000100%
ClampAngle(...)0%000100%
SetValue(...)0%000100%

File(s)

E:/Unity/Unity Project/VR-Basics/Assets/_Course Library/Scripts/Core/XRKnob.cs

#LineLine coverage
 1using System;
 2using System.Diagnostics.CodeAnalysis;
 3using UnityEngine;
 4using UnityEngine.Events;
 5using UnityEngine.XR.Interaction.Toolkit;
 6using HenryLab;
 7
 8/// <summary>
 9/// An interactable knob that follows the rotation of the interactor
 10/// </summary>
 11public class XRKnob : XRBaseInteractable, ITransformableEntity
 12{
 13
 14
 15    [ExcludeFromCodeCoverage] public float TriggeringTime => 2.5f;
 16    [ExcludeFromCodeCoverage] public string Name => Str.Transformable;
 17
 18    [ExcludeFromCodeCoverage]
 19    public void Triggerring()
 20    {
 21        var obj = EntityManager.Instance.vrexplorerMono.gameObject;
 22        XRDirectInteractor interactor;
 23        if(!obj.TryGetComponent(out interactor))
 24        {
 25            interactor = obj.AddComponent<XRDirectInteractor>();
 26        }
 27        if(!obj.GetComponent<ActionBasedController>())
 28        {
 29            obj.AddComponent<ActionBasedController>();
 30        }
 31
 32        var e = new SelectEnterEventArgs() { interactorObject = interactor };
 33        StartTurn(e);
 34        selectEntered.Invoke(e);
 35    }
 36
 37    [ExcludeFromCodeCoverage]
 38    public void Triggerred()
 39    {
 40        var obj = EntityManager.Instance.vrexplorerMono.gameObject;
 41        XRDirectInteractor interactor;
 42        if(!obj.TryGetComponent(out interactor))
 43        {
 44            interactor = obj.AddComponent<XRDirectInteractor>();
 45        }
 46        if(!obj.GetComponent<ActionBasedController>())
 47        {
 48            obj.AddComponent<ActionBasedController>();
 49        }
 50
 51        OnValueChange.Invoke(DeltaRotation.y);
 52        Angle = FindRotationValue();
 53        float finalRotation = ApplyRotation(Angle);
 54
 55        SetValue(finalRotation);
 56        selectRotation = selectInteractor.transform.rotation;
 57        var e = new SelectExitEventArgs() { interactorObject = interactor };
 58        EndTurn(e);
 59        selectExited.Invoke(e);
 60    }
 61
 62    [ExcludeFromCodeCoverage] public Vector3 DeltaPosition => new Vector3(0, 0, 0);
 63
 64    [ExcludeFromCodeCoverage] public Vector3 DeltaRotation => new Vector3(0, 180, 0);
 65
 66    [ExcludeFromCodeCoverage] public Vector3 DeltaScale => new Vector3(0, 0, 0);
 67
 68    [Tooltip("The transform of the visual component of the knob")]
 269    public Transform knobTransform = null;
 70
 71    [Tooltip("The minimum range the knob can rotate")]
 272    [Range(-180, 0)] public float minimum = -90.0f;
 73
 74    [Tooltip("The maximum range the knob can rotate")]
 275    [Range(0, 180)] public float maximum = 90.0f;
 76
 77    [Tooltip("The initial value of the knob")]
 278    [Range(0, 1)] public float defaultValue = 0.0f;
 79
 80    [Serializable] public class ValueChangeEvent : UnityEvent<float> { }
 81
 82    // When the knobs's value changes
 283    public ValueChangeEvent OnValueChange = new ValueChangeEvent();
 84
 885    public float Value { get; private set; } = 0.0f;
 686    public float Angle { get; private set; } = 0.0f;
 87
 288    private IXRSelectInteractor selectInteractor = null;
 289    private Quaternion selectRotation = Quaternion.identity;
 90
 91    private void Start()
 192    {
 193        float defaultRotation = Mathf.Lerp(minimum, maximum, defaultValue);
 194        ApplyRotation(defaultRotation);
 195        SetValue(defaultRotation);
 196    }
 97
 98    protected override void OnEnable()
 199    {
 1100        base.OnEnable();
 1101        selectEntered.AddListener(StartTurn);
 1102        selectExited.AddListener(EndTurn);
 1103    }
 104
 105    protected override void OnDisable()
 1106    {
 1107        base.OnDisable();
 1108        selectEntered.RemoveListener(StartTurn);
 1109        selectExited.RemoveListener(EndTurn);
 1110    }
 111
 112    private void StartTurn(SelectEnterEventArgs eventArgs)
 4113    {
 4114        selectInteractor = eventArgs.interactorObject;
 4115        selectRotation = selectInteractor.transform.rotation;
 4116    }
 117
 118    private void EndTurn(SelectExitEventArgs eventArgs)
 4119    {
 4120        selectInteractor = null;
 4121        selectRotation = Quaternion.identity;
 4122    }
 123
 124    public override void ProcessInteractable(XRInteractionUpdateOrder.UpdatePhase updatePhase)
 5286125    {
 5286126        base.ProcessInteractable(updatePhase);
 127
 5286128        if (updatePhase == XRInteractionUpdateOrder.UpdatePhase.Dynamic)
 718129        {
 718130            if (isSelected)
 0131            {
 0132                Angle = FindRotationValue();
 0133                float finalRotation = ApplyRotation(Angle);
 134
 0135                SetValue(finalRotation);
 0136                selectRotation = selectInteractor.transform.rotation;
 0137            }
 718138        }
 5286139    }
 140
 141    private float FindRotationValue()
 2142    {
 2143        Quaternion rotationDifference = selectInteractor.transform.rotation * Quaternion.Inverse(selectRotation);
 2144        Vector3 rotatedForward = rotationDifference * knobTransform.forward;
 2145        return (Vector3.SignedAngle(knobTransform.forward, rotatedForward, transform.up));
 2146    }
 147
 148    private float ApplyRotation(float angle)
 3149    {
 3150        Quaternion newRotation = Quaternion.AngleAxis(angle, Vector3.up);
 3151        newRotation *= knobTransform.localRotation;
 152
 3153        Vector3 eulerRotation = newRotation.eulerAngles;
 3154        eulerRotation.y = ClampAngle(eulerRotation.y);
 155
 3156        knobTransform.localEulerAngles = eulerRotation;
 3157        return eulerRotation.y;
 3158    }
 159
 160    private float ClampAngle(float angle)
 3161    {
 3162        if (angle > 180)
 3163            angle -= 360;
 164
 3165        return (Mathf.Clamp(angle, minimum, maximum));
 3166    }
 167
 168    private void SetValue(float rotation)
 3169    {
 3170        Value = Mathf.InverseLerp(minimum, maximum, rotation);
 3171        OnValueChange.Invoke(Value);
 3172    }
 173}