VR4Medical/ICI/Library/PackageCache/com.unity.xr.interaction.toolkit@42ef3600567b/Tests/Runtime/NearFarInteractorTests.cs
2025-07-29 13:45:50 +03:00

750 lines
35 KiB
C#

using System.Collections;
using System.Collections.Generic;
using NUnit.Framework;
using UnityEngine.TestTools;
using UnityEngine.TestTools.Utils;
using UnityEngine.XR.Interaction.Toolkit.Attachment;
using UnityEngine.XR.Interaction.Toolkit.Interactables;
using UnityEngine.XR.Interaction.Toolkit.Interactors;
using UnityEngine.XR.Interaction.Toolkit.Interactors.Casters;
using UnityEngine.XR.Interaction.Toolkit.Interactors.Visuals;
using UnityEngine.XR.Interaction.Toolkit.Filtering;
namespace UnityEngine.XR.Interaction.Toolkit.Tests
{
[TestFixture]
class NearFarInteractorTests
{
static readonly bool[] s_BooleanValues = { false, true };
static readonly int[] s_NumSegmentValues = { 1, 2, 5, 25 };
static readonly CurveInteractionCaster.HitDetectionType[] s_HitDetectionTypes =
{
CurveInteractionCaster.HitDetectionType.Raycast,
CurveInteractionCaster.HitDetectionType.ConeCast,
CurveInteractionCaster.HitDetectionType.SphereCast
};
static readonly (InteractorFarAttachMode interactorFarAttachMode, InteractableFarAttachMode interactableFarAttachMode)[] s_FarAttachModeArgs =
{
(InteractorFarAttachMode.Near, InteractableFarAttachMode.DeferToInteractor),
(InteractorFarAttachMode.Near, InteractableFarAttachMode.Near),
(InteractorFarAttachMode.Near, InteractableFarAttachMode.Far),
(InteractorFarAttachMode.Far, InteractableFarAttachMode.DeferToInteractor),
(InteractorFarAttachMode.Far, InteractableFarAttachMode.Near),
(InteractorFarAttachMode.Far, InteractableFarAttachMode.Far),
};
[TearDown]
public void TearDown()
{
TestUtilities.DestroyAllSceneObjects();
}
[UnityTest]
public IEnumerator TestEnableNearCasting([ValueSource(nameof(s_BooleanValues))] bool enableNearCasting)
{
TestUtilities.CreateInteractionManager();
var interactor = TestUtilities.CreateNearFarInteractor();
interactor.enableNearCasting = enableNearCasting;
interactor.enableFarCasting = false;
var interactable = TestUtilities.CreateGrabInteractable();
yield return new WaitForFixedUpdate();
yield return null;
Assert.That(interactor.enableNearCasting, Is.EqualTo(enableNearCasting));
var controllerRecorder = TestUtilities.CreateControllerRecorder(interactor, (recording) =>
{
recording.AddRecordingFrameNonAlloc(new XRControllerState(0.0f, Vector3.zero, Quaternion.identity, InputTrackingState.All, true,
false, false, false));
recording.AddRecordingFrameNonAlloc(new XRControllerState(0.1f, Vector3.zero, Quaternion.identity, InputTrackingState.All, true,
true, false, false));
recording.AddRecordingFrameNonAlloc(new XRControllerState(float.MaxValue, Vector3.zero, Quaternion.identity, InputTrackingState.All, true,
true, false, false));
});
controllerRecorder.isPlaying = true;
controllerRecorder.visitEachFrame = true;
yield return new WaitForSeconds(0.1f);
Assert.That(interactable.isSelected, Is.EqualTo(enableNearCasting));
Assert.That(interactor.interactablesSelected, enableNearCasting ? Is.EqualTo(new[] { interactable }) : Is.Empty);
}
[UnityTest]
public IEnumerator TestEnableFarCasting([ValueSource(nameof(s_BooleanValues))] bool enableFarCasting)
{
var manager = TestUtilities.CreateInteractionManager();
var interactor = TestUtilities.CreateNearFarInteractor();
interactor.enableNearCasting = false;
interactor.enableFarCasting = enableFarCasting;
interactor.transform.position = Vector3.zero;
interactor.transform.forward = Vector3.forward;
var interactable = TestUtilities.CreateGrabInteractable();
interactable.transform.position = interactor.transform.position + interactor.transform.forward * 5.0f;
// Wait for Physics update for hit
yield return new WaitForFixedUpdate();
yield return null;
var validTargets = new List<IXRInteractable>();
manager.GetValidTargets(interactor, validTargets);
Assert.That(validTargets, enableFarCasting ? Is.EqualTo(new[] { interactable }) : Is.Empty);
Assert.That(interactable.isSelected, Is.False);
Assert.That(interactor.interactablesSelected, Is.Empty);
var controllerRecorder = TestUtilities.CreateControllerRecorder(interactor, (recording) =>
{
recording.AddRecordingFrameNonAlloc(new XRControllerState(0.0f, Vector3.zero, Quaternion.identity, InputTrackingState.All, true,
false, false, false));
recording.AddRecordingFrameNonAlloc(new XRControllerState(0.1f, Vector3.zero, Quaternion.identity, InputTrackingState.All, true,
true, false, false));
recording.AddRecordingFrameNonAlloc(new XRControllerState(float.MaxValue, Vector3.zero, Quaternion.identity, InputTrackingState.All, true,
true, false, false));
});
controllerRecorder.isPlaying = true;
controllerRecorder.visitEachFrame = true;
yield return new WaitForSeconds(0.1f);
Assert.That(interactable.isSelected, Is.EqualTo(enableFarCasting));
Assert.That(interactor.interactablesSelected, enableFarCasting ? Is.EqualTo(new[] { interactable }) : Is.Empty);
}
[UnityTest]
public IEnumerator TestObstructedFarCasting()
{
var manager = TestUtilities.CreateInteractionManager();
var interactor = TestUtilities.CreateNearFarInteractor();
interactor.enableNearCasting = false;
interactor.enableFarCasting = true;
interactor.transform.position = Vector3.zero;
interactor.transform.forward = Vector3.forward;
var interactable = TestUtilities.CreateGrabInteractable();
interactable.transform.position = interactor.transform.position + interactor.transform.forward * 5.0f;
// Wait for Physics update for hit
yield return new WaitForFixedUpdate();
yield return null;
var validTargets = new List<IXRInteractable>();
manager.GetValidTargets(interactor, validTargets);
Assert.That(validTargets, Is.EqualTo(new[] { interactable }));
Assert.That(interactable.isSelected, Is.False);
Assert.That(interactor.interactablesSelected, Is.Empty);
// Create cube to obstruct far interaction
GameObject cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
cube.transform.position = interactor.transform.position + interactor.transform.forward * 3.0f;
cube.transform.localScale = new Vector3(0.5f, 0.5f, 0.5f);
// Wait for Physics update for hit
yield return new WaitForFixedUpdate();
yield return null;
validTargets.Clear();
manager.GetValidTargets(interactor, validTargets);
Assert.That(validTargets, Is.Empty);
}
[UnityTest]
public IEnumerator TestFarCastingTargetFilterWithMultiColliderInteractable()
{
var manager = TestUtilities.CreateInteractionManager();
var interactor = TestUtilities.CreateNearFarInteractor();
interactor.enableNearCasting = false;
interactor.enableFarCasting = true;
// Setup target filter
var targetFilter = interactor.gameObject.AddComponent<XRTargetFilter>();
interactor.targetFilter = targetFilter;
interactor.transform.position = Vector3.zero;
interactor.transform.forward = Vector3.forward;
// Setup interactable with multiple colliders
GameObject interactableGO = new GameObject("Grab Interactable");
TestUtilities.CreateGOSphereCollider(interactableGO, false);
TestUtilities.CreateGOBoxCollider(interactableGO, false);
XRGrabInteractable interactable = interactableGO.AddComponent<XRGrabInteractable>();
var rigidBody = interactableGO.GetComponent<Rigidbody>();
rigidBody.useGravity = false;
rigidBody.isKinematic = true;
interactable.transform.position = interactor.transform.position + interactor.transform.forward * 5.0f;
// Setup interactable with multiple colliders
GameObject secondaryGameObject = new GameObject("Secondary Grab Interactable");
TestUtilities.CreateGOSphereCollider(secondaryGameObject, false);
TestUtilities.CreateGOBoxCollider(secondaryGameObject, false);
XRGrabInteractable secondaryInteractable = secondaryGameObject.AddComponent<XRGrabInteractable>();
rigidBody = secondaryGameObject.GetComponent<Rigidbody>();
rigidBody.useGravity = false;
rigidBody.isKinematic = true;
secondaryInteractable.transform.position = interactor.transform.position + interactor.transform.forward * 6.0f;
// Wait for Physics update for hit
yield return new WaitForFixedUpdate();
yield return null;
var validTargets = new List<IXRInteractable>();
manager.GetValidTargets(interactor, validTargets);
Assert.That(validTargets, Is.EqualTo(new[] { interactable }));
Assert.That(interactable.isSelected, Is.False);
Assert.That(interactor.interactablesSelected, Is.Empty);
var controllerRecorder = TestUtilities.CreateControllerRecorder(interactor, (recording) =>
{
recording.AddRecordingFrameNonAlloc(new XRControllerState(0.0f, Vector3.zero, Quaternion.identity, InputTrackingState.All, true,
false, false, false));
recording.AddRecordingFrameNonAlloc(new XRControllerState(0.1f, Vector3.zero, Quaternion.identity, InputTrackingState.All, true,
true, false, false));
recording.AddRecordingFrameNonAlloc(new XRControllerState(float.MaxValue, Vector3.zero, Quaternion.identity, InputTrackingState.All, true,
true, false, false));
});
controllerRecorder.isPlaying = true;
controllerRecorder.visitEachFrame = true;
yield return new WaitForSeconds(0.1f);
Assert.That(interactable.isSelected, Is.True);
Assert.That(interactor.interactablesSelected, Is.EqualTo(new[] { interactable }));
}
[UnityTest]
public IEnumerator TestEnableUIInteraction([ValueSource(nameof(s_BooleanValues))] bool enableUIInteraction)
{
var manager = TestUtilities.CreateInteractionManager();
var interactor = TestUtilities.CreateNearFarInteractorWithXROrigin(out var camera);
interactor.enableUIInteraction = enableUIInteraction;
interactor.enableNearCasting = false;
interactor.enableFarCasting = true;
interactor.transform.position = Vector3.zero;
interactor.transform.forward = Vector3.forward;
var interactable = TestUtilities.CreateGrabInteractable();
interactable.transform.position = interactor.transform.position + interactor.transform.forward * 5.0f;
// Place UI closer than interactable
var uiCanvas = TestUtilities.CreateUICanvas(camera);
uiCanvas.transform.position = interactor.transform.position + interactor.transform.forward * 2.5f;
// Wait for Physics update for hit
yield return new WaitForFixedUpdate();
yield return null;
var validTargets = new List<IXRInteractable>();
manager.GetValidTargets(interactor, validTargets);
Assert.That(validTargets, enableUIInteraction ? Is.Empty : Is.EqualTo(new[] { interactable }));
Assert.That(interactable.isSelected, Is.False);
Assert.That(interactor.interactablesSelected, Is.Empty);
yield return new WaitForSeconds(0.1f);
// Wait for Physics update for hit
yield return new WaitForFixedUpdate();
yield return null;
var endPointType = interactor.TryGetCurveEndPoint(out var endPoint);
Assert.That(endPointType, Is.EqualTo(enableUIInteraction ? EndPointType.UI : EndPointType.ValidCastHit));
}
[UnityTest]
public IEnumerator TestBlockUIOnInteractableSelection([ValueSource(nameof(s_BooleanValues))] bool blockUIOnInteractableSelection)
{
var manager = TestUtilities.CreateInteractionManager();
var interactor = TestUtilities.CreateNearFarInteractorWithXROrigin(out var camera);
interactor.enableNearCasting = false;
interactor.enableFarCasting = true;
interactor.enableUIInteraction = true;
interactor.blockUIOnInteractableSelection = blockUIOnInteractableSelection;
interactor.transform.position = Vector3.zero;
interactor.transform.forward = Vector3.forward;
// Place interactable closer than UI
var interactable = TestUtilities.CreateGrabInteractable();
interactable.transform.position = interactor.transform.position + interactor.transform.forward * 2.5f;
var uiCanvas = TestUtilities.CreateUICanvas(camera);
uiCanvas.transform.position = interactor.transform.position + interactor.transform.forward * 5f;
// Wait for Physics update for hit
yield return new WaitForFixedUpdate();
yield return null;
var validTargets = new List<IXRInteractable>();
manager.GetValidTargets(interactor, validTargets);
Assert.That(validTargets, Is.EqualTo(new[] { interactable }));
Assert.That(interactable.isSelected, Is.False);
Assert.That(interactor.interactablesSelected, Is.Empty);
var controllerRecorder = TestUtilities.CreateControllerRecorder(interactor, (recording) =>
{
recording.AddRecordingFrameNonAlloc(new XRControllerState(0.0f, Vector3.zero, Quaternion.identity, InputTrackingState.All, true,
false, false, false));
recording.AddRecordingFrameNonAlloc(new XRControllerState(0.1f, Vector3.zero, Quaternion.identity, InputTrackingState.All, true,
true, false, false));
recording.AddRecordingFrameNonAlloc(new XRControllerState(float.MaxValue, Vector3.zero, Quaternion.identity, InputTrackingState.All, true,
true, false, false));
});
controllerRecorder.isPlaying = true;
controllerRecorder.visitEachFrame = true;
yield return new WaitForSeconds(0.1f);
// Move interactable further out than UI
interactor.interactionAttachController.MoveTo(interactor.transform.position + interactor.transform.forward * 10f);
yield return new WaitForSeconds(0.1f);
// Wait for Physics update for hit
yield return new WaitForFixedUpdate();
yield return null;
Assert.That(interactable.isSelected, Is.True);
Assert.That(interactor.interactablesSelected, Is.EqualTo(new[] { interactable }));
var endPointType = interactor.TryGetCurveEndPoint(out var endPoint);
Assert.That(endPointType, Is.EqualTo(blockUIOnInteractableSelection ? EndPointType.ValidCastHit : EndPointType.UI));
}
[UnityTest]
public IEnumerator TestNearCasterSortingStrategy()
{
var manager = TestUtilities.CreateInteractionManager();
var interactor = TestUtilities.CreateNearFarInteractor();
interactor.nearCasterSortingStrategy = NearFarInteractor.NearCasterSortingStrategy.SquareDistance;
interactor.enableNearCasting = true;
interactor.enableFarCasting = true;
interactor.transform.position = Vector3.zero;
interactor.transform.forward = Vector3.forward;
var interactable = TestUtilities.CreateGrabInteractable();
interactable.transform.position = new Vector3(0f, 0.05f, 0.0f);
// Place second interactable above first, within range of near interaction
var interactable2 = TestUtilities.CreateGrabInteractable();
interactable2.transform.position = new Vector3(0f, 0.055f, 0.0f);
// Wait for Physics update for hit
yield return new WaitForFixedUpdate();
yield return null;
var validTargets = new List<IXRInteractable>();
manager.GetValidTargets(interactor, validTargets);
Assert.That(validTargets, Is.EqualTo(new[] { interactable }));
Assert.That(interactable.isSelected, Is.False);
Assert.That(interactor.interactablesSelected, Is.Empty);
var controllerRecorder = TestUtilities.CreateControllerRecorder(interactor, (recording) =>
{
recording.AddRecordingFrameNonAlloc(new XRControllerState(0.0f, Vector3.zero, Quaternion.identity, InputTrackingState.All, true,
false, false, false));
recording.AddRecordingFrameNonAlloc(new XRControllerState(0.1f, Vector3.zero, Quaternion.identity, InputTrackingState.All, true,
true, false, false));
recording.AddRecordingFrameNonAlloc(new XRControllerState(float.MaxValue, Vector3.zero, Quaternion.identity, InputTrackingState.All, true,
true, false, false));
});
controllerRecorder.isPlaying = true;
controllerRecorder.visitEachFrame = true;
yield return new WaitForSeconds(0.1f);
Assert.That(interactable.isSelected, Is.True);
Assert.That(interactor.interactablesSelected, Is.EqualTo(new[] { interactable }));
}
[UnityTest]
public IEnumerator TestFarInteractionAttachMode([ValueSource(nameof(s_FarAttachModeArgs))] (InteractorFarAttachMode interactorFarAttachMode, InteractableFarAttachMode interactableFarAttachMode) args)
{
var effectiveNear = args.interactableFarAttachMode == InteractableFarAttachMode.DeferToInteractor && args.interactorFarAttachMode == InteractorFarAttachMode.Near ||
args.interactableFarAttachMode == InteractableFarAttachMode.Near;
var manager = TestUtilities.CreateInteractionManager();
var interactor = TestUtilities.CreateNearFarInteractor();
interactor.enableNearCasting = true;
interactor.enableFarCasting = true;
interactor.farAttachMode = args.interactorFarAttachMode;
interactor.transform.position = Vector3.zero;
interactor.transform.forward = Vector3.forward;
var interactable = TestUtilities.CreateGrabInteractable();
interactable.farAttachMode = args.interactableFarAttachMode;
interactable.useDynamicAttach = !effectiveNear;
interactable.snapToColliderVolume = false;
interactable.reinitializeDynamicAttachEverySingleGrab = true;
var initialInteractablePosition = interactor.transform.position + interactor.transform.forward * 5.0f;
interactable.transform.position = initialInteractablePosition;
// Wait for Physics update for hit
yield return new WaitForFixedUpdate();
yield return null;
var validTargets = new List<IXRInteractable>();
manager.GetValidTargets(interactor, validTargets);
Assert.That(validTargets, Is.EqualTo(new[] { interactable }));
Assert.That(interactable.isSelected, Is.False);
Assert.That(interactor.interactablesSelected, Is.Empty);
var controllerRecorder = TestUtilities.CreateControllerRecorder(interactor, (recording) =>
{
recording.AddRecordingFrameNonAlloc(new XRControllerState(0.0f, Vector3.zero, Quaternion.identity, InputTrackingState.All, true,
false, false, false));
recording.AddRecordingFrameNonAlloc(new XRControllerState(0.1f, Vector3.zero, Quaternion.identity, InputTrackingState.All, true,
true, false, false));
recording.AddRecordingFrameNonAlloc(new XRControllerState(float.MaxValue, Vector3.zero, Quaternion.identity, InputTrackingState.All, true,
true, false, false));
});
controllerRecorder.isPlaying = true;
controllerRecorder.visitEachFrame = true;
yield return new WaitForSeconds(0.1f);
// Wait for Physics update for hit
yield return new WaitForFixedUpdate();
yield return null;
Assert.That(interactable.isSelected, Is.True);
Assert.That(interactor.interactablesSelected, Is.EqualTo(new[] { interactable }));
if (effectiveNear)
Assert.That(interactable.transform.position, Is.EqualTo(interactor.transform.position).Using(Vector3ComparerWithEqualsOperator.Instance));
else
Assert.That(interactable.transform.position, Is.EqualTo(initialInteractablePosition).Using(Vector3ComparerWithEqualsOperator.Instance));
}
[UnityTest]
public IEnumerator TestDetermineSelectionRegion()
{
var manager = TestUtilities.CreateInteractionManager();
var interactor = TestUtilities.CreateNearFarInteractor();
interactor.enableNearCasting = false;
interactor.enableFarCasting = true;
interactor.transform.position = Vector3.zero;
interactor.transform.forward = Vector3.forward;
var interactable = TestUtilities.CreateGrabInteractable();
interactable.transform.position = interactor.transform.position + interactor.transform.forward * 5.0f;
NearFarInteractor.Region? invokedSelectionRegion = null;
interactor.selectionRegion.Subscribe(OnNearFarSelectionRegionChanged);
// Wait for Physics update for hit
yield return new WaitForFixedUpdate();
yield return null;
var validTargets = new List<IXRInteractable>();
manager.GetValidTargets(interactor, validTargets);
Assert.That(validTargets, Is.EqualTo(new[] { interactable }));
Assert.That(interactable.isSelected, Is.False);
Assert.That(interactor.interactablesSelected, Is.Empty);
var controllerRecorder = TestUtilities.CreateControllerRecorder(interactor, (recording) =>
{
recording.AddRecordingFrameNonAlloc(new XRControllerState(0.0f, Vector3.zero, Quaternion.identity, InputTrackingState.All, true,
false, false, false));
recording.AddRecordingFrameNonAlloc(new XRControllerState(0.1f, Vector3.zero, Quaternion.identity, InputTrackingState.All, true,
true, false, false));
recording.AddRecordingFrameNonAlloc(new XRControllerState(float.MaxValue, Vector3.zero, Quaternion.identity, InputTrackingState.All, true,
true, false, false));
});
controllerRecorder.isPlaying = true;
controllerRecorder.visitEachFrame = true;
yield return new WaitForSeconds(0.1f);
Assert.That(interactable.isSelected, Is.True);
Assert.That(interactor.interactablesSelected, Is.EqualTo(new[] { interactable }));
Assert.That(interactor.selectionRegion.Value, Is.EqualTo(NearFarInteractor.Region.Far));
Assert.That(invokedSelectionRegion.HasValue, Is.True);
Assert.That(invokedSelectionRegion.Value, Is.EqualTo(NearFarInteractor.Region.Far));
invokedSelectionRegion = null;
interactor.interactionAttachController.MoveTo(interactor.transform.position);
yield return new WaitForFixedUpdate();
yield return null;
Assert.That(interactor.selectionRegion.Value, Is.EqualTo(NearFarInteractor.Region.Near));
Assert.That(invokedSelectionRegion.HasValue, Is.True);
Assert.That(invokedSelectionRegion.Value, Is.EqualTo(NearFarInteractor.Region.Near));
invokedSelectionRegion = null;
manager.SelectExit((IXRSelectInteractor)interactor, interactable);
Assert.That(interactable.isSelected, Is.False);
Assert.That(interactor.interactablesSelected, Is.Empty);
Assert.That(interactor.selectionRegion.Value, Is.EqualTo(NearFarInteractor.Region.None));
Assert.That(invokedSelectionRegion.HasValue, Is.True);
Assert.That(invokedSelectionRegion.Value, Is.EqualTo(NearFarInteractor.Region.None));
void OnNearFarSelectionRegionChanged(NearFarInteractor.Region selectionRegion)
{
invokedSelectionRegion = selectionRegion;
}
}
[UnityTest]
public IEnumerator TestEvaluateNearInteractionPriority()
{
var manager = TestUtilities.CreateInteractionManager();
var interactor = TestUtilities.CreateNearFarInteractor();
interactor.enableNearCasting = true;
interactor.enableFarCasting = true;
interactor.transform.position = Vector3.zero;
interactor.transform.forward = Vector3.forward;
var interactable = TestUtilities.CreateGrabInteractable();
interactable.transform.position = Vector3.zero;
var interactable2 = TestUtilities.CreateGrabInteractable();
interactable2.transform.position = interactor.transform.position + interactor.transform.forward * 5.0f;
// Wait for Physics update for hit
yield return new WaitForFixedUpdate();
yield return null;
var validTargets = new List<IXRInteractable>();
manager.GetValidTargets(interactor, validTargets);
Assert.That(validTargets, Is.EqualTo(new[] { interactable }));
Assert.That(interactable.isSelected, Is.False);
Assert.That(interactor.interactablesSelected, Is.Empty);
var controllerRecorder = TestUtilities.CreateControllerRecorder(interactor, (recording) =>
{
recording.AddRecordingFrameNonAlloc(new XRControllerState(0.0f, Vector3.zero, Quaternion.identity, InputTrackingState.All, true,
false, false, false));
recording.AddRecordingFrameNonAlloc(new XRControllerState(0.1f, Vector3.zero, Quaternion.identity, InputTrackingState.All, true,
true, false, false));
recording.AddRecordingFrameNonAlloc(new XRControllerState(float.MaxValue, Vector3.zero, Quaternion.identity, InputTrackingState.All, true,
true, false, false));
});
controllerRecorder.isPlaying = true;
controllerRecorder.visitEachFrame = true;
yield return new WaitForSeconds(0.1f);
Assert.That(interactable.isSelected, Is.True);
Assert.That(interactor.interactablesSelected, Is.EqualTo(new[] { interactable }));
}
[UnityTest]
public IEnumerator TestNearFarInteractorManualSelection()
{
TestUtilities.CreateInteractionManager();
var interactor = TestUtilities.CreateNearFarInteractor();
interactor.transform.position = Vector3.zero;
interactor.transform.forward = Vector3.forward;
var interactable = TestUtilities.CreateGrabInteractable();
interactable.transform.position = interactor.transform.position + interactor.transform.right * 5.0f;
yield return new WaitForFixedUpdate();
yield return null;
Assert.That(interactor.interactablesSelected, Is.Empty);
interactor.StartManualInteraction((IXRSelectInteractable)interactable);
yield return new WaitForFixedUpdate();
yield return null;
Assert.That(interactor.interactablesSelected, Is.EqualTo(new[] { interactable }));
interactor.EndManualInteraction();
yield return new WaitForFixedUpdate();
yield return null;
Assert.That(interactor.interactablesSelected, Is.Empty);
}
[UnityTest]
public IEnumerator TestNearFarInteractorCanSelectInteractorWithSnapVolume()
{
TestUtilities.CreateInteractionManager();
var interactor = TestUtilities.CreateNearFarInteractor();
interactor.transform.position = Vector3.zero;
interactor.transform.forward = Vector3.forward;
var interactable = TestUtilities.CreateGrabInteractable();
interactable.transform.position = interactor.transform.position + interactor.transform.forward * 5.0f;
var snapVolume = TestUtilities.CreateSnapVolume();
snapVolume.interactable = interactable;
snapVolume.snapToCollider = interactable.colliders[0];
snapVolume.transform.position = interactable.transform.position;
yield return new WaitForFixedUpdate();
yield return null;
var controllerRecorder = TestUtilities.CreateControllerRecorder(interactor, (recording) =>
{
recording.AddRecordingFrameNonAlloc(new XRControllerState(0.0f, Vector3.zero, Quaternion.identity, InputTrackingState.All, true,
false, false, false));
recording.AddRecordingFrameNonAlloc(new XRControllerState(0.1f, Vector3.zero, Quaternion.identity, InputTrackingState.All, true,
true, false, false));
recording.AddRecordingFrameNonAlloc(new XRControllerState(float.MaxValue, Vector3.zero, Quaternion.identity, InputTrackingState.All, true,
true, false, false));
});
controllerRecorder.isPlaying = true;
controllerRecorder.visitEachFrame = true;
yield return new WaitForSeconds(0.1f);
Assert.That(interactor.interactablesSelected, Is.EqualTo(new[] { interactable }));
}
[UnityTest]
public IEnumerator TestNearFarInteractorCurveInteractionCaster([ValueSource(nameof(s_HitDetectionTypes))] CurveInteractionCaster.HitDetectionType hitDetectionType, [ValueSource(nameof(s_NumSegmentValues))] int numSegments)
{
var manager = TestUtilities.CreateInteractionManager();
var interactor = TestUtilities.CreateNearFarInteractor();
interactor.transform.position = Vector3.zero;
interactor.transform.forward = Vector3.forward;
var curveInteractionCaster = interactor.farInteractionCaster as CurveInteractionCaster;
Assert.That(curveInteractionCaster, Is.Not.Null);
curveInteractionCaster.hitDetectionType = hitDetectionType;
curveInteractionCaster.targetNumCurveSegments = numSegments;
var interactable = TestUtilities.CreateGrabInteractable();
interactable.transform.position = interactor.transform.position + interactor.transform.forward * 5.0f;
yield return new WaitForSeconds(0.1f);
var validTargets = new List<IXRInteractable>();
manager.GetValidTargets(interactor, validTargets);
Assert.That(validTargets, Is.EqualTo(new[] { interactable }));
interactor.StartManualInteraction((IXRSelectInteractable)interactable);
yield return new WaitForFixedUpdate();
yield return null;
Assert.That(interactor.interactablesSelected, Is.EqualTo(new[] { interactable }));
interactor.EndManualInteraction();
yield return new WaitForFixedUpdate();
yield return null;
Assert.That(interactor.interactablesSelected, Is.Empty);
}
[UnityTest]
public IEnumerator TestNearFarInteractorCurveInteractionCasterBlocked([ValueSource(nameof(s_HitDetectionTypes))] CurveInteractionCaster.HitDetectionType hitDetectionType, [ValueSource(nameof(s_NumSegmentValues))] int numSegments)
{
var manager = TestUtilities.CreateInteractionManager();
var interactor = TestUtilities.CreateNearFarInteractor();
interactor.transform.position = Vector3.zero;
interactor.transform.forward = Vector3.forward;
var curveInteractionCaster = interactor.farInteractionCaster as CurveInteractionCaster;
Assert.That(curveInteractionCaster, Is.Not.Null);
curveInteractionCaster.hitDetectionType = hitDetectionType;
curveInteractionCaster.targetNumCurveSegments = numSegments;
var interactable = TestUtilities.CreateGrabInteractable();
interactable.transform.position = interactor.transform.position + interactor.transform.forward * 5f;
yield return new WaitForSeconds(0.1f);
var validTargets = new List<IXRInteractable>();
manager.GetValidTargets(interactor, validTargets);
Assert.That(validTargets, Is.EqualTo(new[] { interactable }));
var blocker = TestUtilities.CreateCubeGameObject();
blocker.transform.position = interactor.transform.position + interactor.transform.forward * 2f;
yield return new WaitForFixedUpdate();
yield return null;
manager.GetValidTargets(interactor, validTargets);
Assert.That(validTargets, Is.Empty);
}
[UnityTest]
public IEnumerator TestNearFarInteractorCurveInteractionCasterBlockedUI([ValueSource(nameof(s_HitDetectionTypes))] CurveInteractionCaster.HitDetectionType hitDetectionType, [ValueSource(nameof(s_NumSegmentValues))] int numSegments)
{
var manager = TestUtilities.CreateInteractionManager();
var interactor = TestUtilities.CreateNearFarInteractorWithXROrigin(out var camera);
interactor.transform.position = Vector3.zero;
interactor.transform.forward = Vector3.forward;
interactor.blockUIOnInteractableSelection = false;
var curveInteractionCaster = interactor.farInteractionCaster as CurveInteractionCaster;
Assert.That(curveInteractionCaster, Is.Not.Null);
curveInteractionCaster.hitDetectionType = hitDetectionType;
curveInteractionCaster.targetNumCurveSegments = numSegments;
var interactable = TestUtilities.CreateGrabInteractable();
interactable.transform.position = interactor.transform.position + interactor.transform.forward * 2f;
var blocker = TestUtilities.CreateUICanvas(camera);
blocker.transform.position = interactor.transform.position + interactor.transform.forward * 5f;
yield return new WaitForFixedUpdate();
yield return null;
var validTargets = new List<IXRInteractable>();
manager.GetValidTargets(interactor, validTargets);
Assert.That(validTargets, Is.EqualTo(new[] { interactable }));
yield return new WaitForFixedUpdate();
yield return null;
interactable.transform.position = interactor.transform.position + interactor.transform.forward * 8f;
yield return new WaitForFixedUpdate();
yield return null;
manager.GetValidTargets(interactor, validTargets);
Assert.That(validTargets, Is.Empty);
}
}
}