Skip to content

Commit 6df4f0a

Browse files
RogPodgeSabinMGeorgekeveleigh
authored
Feature/back strafing steps (#9697)
* support for back strafing on slopes or steps. * Adding "requiresStrafeHeight" to inspector * style cleanup and minor code refactor * added tests for backstrafe, fixed compiler complaints * Address PR comments * Update Assets/MRTK/SDK/Features/UX/Scripts/Pointers/TeleportPointer.cs Co-authored-by: Kurtis <[email protected]> * pr comment addressal Co-authored-by: sabin george <[email protected]> Co-authored-by: Kurtis <[email protected]>
1 parent 70689b9 commit 6df4f0a

File tree

3 files changed

+132
-7
lines changed

3 files changed

+132
-7
lines changed

Assets/MRTK/SDK/Editor/Inspectors/UX/Pointers/TeleportPointerInspector.cs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ public class TeleportPointerInspector : LinePointerInspector
1818
private SerializedProperty rotationAmount;
1919
private SerializedProperty backStrafeActivationAngle;
2020
private SerializedProperty strafeAmount;
21+
private SerializedProperty checkForFloorOnStrafe;
22+
private SerializedProperty adjustHeightOnStrafe;
23+
private SerializedProperty maxHeightChangeOnStrafe;
2124
private SerializedProperty upDirectionThreshold;
2225
private SerializedProperty lineColorHotSpot;
2326
private SerializedProperty validLayers;
@@ -42,11 +45,13 @@ protected override void OnEnable()
4245
rotationAmount = serializedObject.FindProperty("rotationAmount");
4346
backStrafeActivationAngle = serializedObject.FindProperty("backStrafeActivationAngle");
4447
strafeAmount = serializedObject.FindProperty("strafeAmount");
48+
checkForFloorOnStrafe = serializedObject.FindProperty("checkForFloorOnStrafe");
49+
adjustHeightOnStrafe = serializedObject.FindProperty("adjustHeightOnStrafe");
50+
maxHeightChangeOnStrafe = serializedObject.FindProperty("maxHeightChangeOnStrafe");
4551
upDirectionThreshold = serializedObject.FindProperty("upDirectionThreshold");
4652
lineColorHotSpot = serializedObject.FindProperty("LineColorHotSpot");
4753
validLayers = serializedObject.FindProperty("ValidLayers");
4854
invalidLayers = serializedObject.FindProperty("InvalidLayers");
49-
5055
pointerAudioSource = serializedObject.FindProperty("pointerAudioSource");
5156
teleportRequestedClip = serializedObject.FindProperty("teleportRequestedClip");
5257
teleportCompletedClip = serializedObject.FindProperty("teleportCompletedClip");
@@ -71,6 +76,12 @@ public override void OnInspectorGUI()
7176
EditorGUILayout.PropertyField(rotationAmount);
7277
EditorGUILayout.PropertyField(backStrafeActivationAngle);
7378
EditorGUILayout.PropertyField(strafeAmount);
79+
EditorGUILayout.PropertyField(checkForFloorOnStrafe);
80+
if (checkForFloorOnStrafe.boolValue)
81+
{
82+
EditorGUILayout.PropertyField(adjustHeightOnStrafe);
83+
EditorGUILayout.PropertyField(maxHeightChangeOnStrafe);
84+
}
7485
EditorGUILayout.PropertyField(upDirectionThreshold);
7586
EditorGUILayout.PropertyField(lineColorHotSpot);
7687
EditorGUILayout.PropertyField(validLayers);

Assets/MRTK/SDK/Features/UX/Scripts/Pointers/TeleportPointer.cs

Lines changed: 69 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@
55
using Microsoft.MixedReality.Toolkit.Physics;
66
using Microsoft.MixedReality.Toolkit.Utilities;
77
using System;
8+
using System.Runtime.CompilerServices;
89
using Unity.Profiling;
910
using UnityEngine;
1011
using UnityPhysics = UnityEngine.Physics;
1112

13+
[assembly: InternalsVisibleTo("Microsoft.MixedReality.Toolkit.Tests.PlayModeTests")]
1214
namespace Microsoft.MixedReality.Toolkit.Teleport
1315
{
1416
/// <summary>
@@ -85,7 +87,20 @@ public bool TeleportHotSpotCursorVisibility
8587

8688
[SerializeField]
8789
[Tooltip("The distance to move the camera when the strafe is activated")]
88-
private float strafeAmount = 0.25f;
90+
internal float strafeAmount = 0.25f;
91+
92+
[SerializeField]
93+
[Tooltip("Whether or not a strafe checks that there is a floor beneath the user's origin on strafe")]
94+
internal bool checkForFloorOnStrafe = false;
95+
96+
[SerializeField]
97+
[Tooltip("Whether or not the user's y-position can move during a strafe")]
98+
internal bool adjustHeightOnStrafe = false;
99+
100+
101+
[SerializeField]
102+
[Tooltip("The detection range for a floor on strafe, as well as the max amount that a user's y-position can change on strafe")]
103+
internal float maxHeightChangeOnStrafe = 0.5f;
89104

90105
[SerializeField]
91106
[Range(0f, 1f)]
@@ -231,6 +246,58 @@ protected Gradient GetLineGradient(TeleportSurfaceResult targetResult)
231246
}
232247
}
233248

249+
/// <summary>
250+
/// check if a backstrafe is possible on a valid platform regarding the possible strafe height given
251+
/// </summary>
252+
/// <param name="newPosition">the new position relative to backstrafe position</param>
253+
/// <param name="hitStrafePosition">actual position the strafe raycast hits</param>
254+
/// <returns>if there is a valid layer one can backstrafe on</returns>
255+
internal bool CheckPossibleBackStep(Vector3 newPosition, out Vector3 hitStrafePosition)
256+
{
257+
var raycastProvider = CoreServices.InputSystem.RaycastProvider;
258+
Vector3 strafeOrigin = new Vector3(newPosition.x, MixedRealityPlayspace.Position.y + maxHeightChangeOnStrafe, newPosition.z);
259+
Vector3 strafeTerminus = strafeOrigin + (Vector3.down * maxHeightChangeOnStrafe * 2f);
260+
261+
RayStep rayStep = new RayStep(strafeOrigin, strafeTerminus);
262+
LayerMask[] layerMasks = new LayerMask[] { ValidLayers };
263+
264+
// check are we hiting a floor plane or step above the current MixedRealityPlayspace.Position
265+
if (!raycastProvider.IsNull() && raycastProvider.Raycast(rayStep, layerMasks, false, out var hitInfo))
266+
{
267+
hitStrafePosition = hitInfo.point;
268+
return true;
269+
}
270+
271+
hitStrafePosition = Vector3.zero;
272+
return false;
273+
}
274+
275+
/// <summary>
276+
/// Performs a strafe in the opposite direction of the camera's forward direction
277+
/// </summary>
278+
internal void PerformStrafe()
279+
{
280+
canMove = false;
281+
var height = MixedRealityPlayspace.Position.y;
282+
var newPosition = -CameraCache.Main.transform.forward * strafeAmount + MixedRealityPlayspace.Position;
283+
284+
newPosition.y = height;
285+
bool isValidStrafe = true;
286+
if (checkForFloorOnStrafe)
287+
{
288+
isValidStrafe = CheckPossibleBackStep(newPosition, out var strafeHitPosition);
289+
if (adjustHeightOnStrafe)
290+
{
291+
newPosition = strafeHitPosition;
292+
}
293+
}
294+
295+
if (isValidStrafe)
296+
{
297+
MixedRealityPlayspace.Position = newPosition;
298+
}
299+
}
300+
234301
#region IMixedRealityPointer Implementation
235302

236303
/// <inheritdoc />
@@ -469,11 +536,7 @@ public override void OnInputChanged(InputEventData<Vector2> eventData)
469536
// Check to make sure we're still under our activation threshold.
470537
if (offsetStrafeAngle > 0 && offsetStrafeAngle <= backStrafeActivationAngle)
471538
{
472-
canMove = false;
473-
var height = MixedRealityPlayspace.Position.y;
474-
var newPosition = -CameraCache.Main.transform.forward * strafeAmount + MixedRealityPlayspace.Position;
475-
newPosition.y = height;
476-
MixedRealityPlayspace.Position = newPosition;
539+
PerformStrafe();
477540
}
478541
}
479542
}

Assets/MRTK/Tests/PlayModeTests/PointerBehaviorTests.cs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,57 @@ public IEnumerator TestTeleportLayers()
357357

358358
}
359359

360+
/// <summary>
361+
/// Tests strafing with the teleport pointer
362+
/// </summary>
363+
[UnityTest]
364+
public IEnumerator TestTeleportStrafe()
365+
{
366+
var iss = PlayModeTestUtilities.GetInputSimulationService();
367+
368+
// Create a floor and make sure it's below the camera
369+
var floor = GameObject.CreatePrimitive(PrimitiveType.Cube);
370+
floor.transform.position = -0.5f * Vector3.up;
371+
372+
// Bring out the right hand and set it to the teleport gesture
373+
TestUtilities.PlayspaceToOriginLookingForward();
374+
Vector3 initialPosition = MixedRealityPlayspace.Position;
375+
376+
TestHand rightHand = new TestHand(Handedness.Right);
377+
378+
// Make sure the hand is in front of the camera
379+
yield return rightHand.Show(Vector3.forward * 0.6f);
380+
rightHand.SetRotation(Quaternion.identity);
381+
382+
TeleportPointer teleportPointer = rightHand.GetPointer<TeleportPointer>();
383+
teleportPointer.PerformStrafe();
384+
TestUtilities.AssertAboutEqual(MixedRealityPlayspace.Position, initialPosition - Vector3.forward * teleportPointer.strafeAmount, "Did not strafe to the expected position");
385+
386+
teleportPointer.checkForFloorOnStrafe = true;
387+
teleportPointer.adjustHeightOnStrafe = true;
388+
teleportPointer.strafeAmount = 1.0f;
389+
teleportPointer.maxHeightChangeOnStrafe = 0.5f;
390+
391+
TestUtilities.PlayspaceToOriginLookingForward();
392+
teleportPointer.PerformStrafe();
393+
TestUtilities.AssertAboutEqual(MixedRealityPlayspace.Position, initialPosition, "Performed an invalid strafe");
394+
395+
var floor2 = GameObject.CreatePrimitive(PrimitiveType.Cube);
396+
floor2.transform.position = new Vector3(0,-0.25f,-1.0f);
397+
yield return PlayModeTestUtilities.WaitForInputSystemUpdate();
398+
399+
TestUtilities.PlayspaceToOriginLookingForward();
400+
teleportPointer.PerformStrafe();
401+
TestUtilities.AssertAboutEqual(MixedRealityPlayspace.Position, initialPosition + new Vector3(0, 0.25f, -teleportPointer.strafeAmount), "Height did not change on strafe");
402+
403+
floor2.transform.position = new Vector3(0, -0.75f, -1.0f);
404+
yield return PlayModeTestUtilities.WaitForInputSystemUpdate();
405+
406+
TestUtilities.PlayspaceToOriginLookingForward();
407+
teleportPointer.PerformStrafe();
408+
TestUtilities.AssertAboutEqual(MixedRealityPlayspace.Position, initialPosition + new Vector3(0, -0.25f, -teleportPointer.strafeAmount), "Height did not change on strafe");
409+
}
410+
360411
/// <summary>
361412
/// Tests that rays can be turned on and off
362413
/// </summary>

0 commit comments

Comments
 (0)