-
Notifications
You must be signed in to change notification settings - Fork 38
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(Action): determine if surface position has had specified change
The SurfaceChangeAction digests SurfaceData and compares the current surface position and the previous surface position and checks to see if the distance between the two positions is within the specified threshold. This can be useful to capture SurfaceLocator events and only carry out actions if the surface difference is within the threshold. A good use case is only blink the camera if the surface difference is over a certain step size.
- Loading branch information
1 parent
1e17af6
commit 5974bca
Showing
4 changed files
with
190 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
namespace VRTK.Core.Action | ||
{ | ||
using UnityEngine; | ||
using VRTK.Core.Data.Type; | ||
using VRTK.Core.Extension; | ||
|
||
/// <summary> | ||
/// The SurfaceChangeAction emits an event when all given actions are in their active state. | ||
/// </summary> | ||
public class SurfaceChangeAction : BooleanAction | ||
{ | ||
[Tooltip("The distance between the current surface and previous surface to consider a valid change.")] | ||
public float changeDistance = 0.5f; | ||
[Tooltip("The axes to check for distance differences on.")] | ||
public Vector3State checkAxis = new Vector3State(true, true, true); | ||
|
||
/// <summary> | ||
/// The Receive method digests SurfaceData and compares the current surface to the previous surface to determine if a change has occured. | ||
/// </summary> | ||
/// <param name="surfaceData">The SurfaceData to check on.</param> | ||
/// <param name="sender">The sender of the action.</param> | ||
public virtual void Receive(SurfaceData surfaceData, object sender = null) | ||
{ | ||
if (ValidSurfaceData(surfaceData)) | ||
{ | ||
Vector3 generatedOrigin = GetCollisionPoint(surfaceData.PreviousCollisionData); | ||
Vector3 generatedTarget = GeneratePoint(surfaceData.Position); | ||
|
||
bool result = !generatedOrigin.Compare(generatedTarget, changeDistance); | ||
Receive(result, sender); | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// The ValidSurfaceData method checks to see if the given SurfaceData is valid. | ||
/// </summary> | ||
/// <param name="surfaceData">The SurfaceData to check on.</param> | ||
/// <returns>Returns `true` if the SurfaceData given is valid.</returns> | ||
protected virtual bool ValidSurfaceData(SurfaceData surfaceData) | ||
{ | ||
return (surfaceData != null && surfaceData.Valid); | ||
} | ||
|
||
/// <summary> | ||
/// The GetCollisionPoint method attempts to get the collision point for the given RaycastHit data. | ||
/// </summary> | ||
/// <param name="collisionData">The RaycastHit data to get the collision point from.</param> | ||
/// <returns>Returns a Vector3 of the collision point.</returns> | ||
protected virtual Vector3 GetCollisionPoint(RaycastHit collisionData) | ||
{ | ||
return (collisionData.transform != null ? GeneratePoint(collisionData.point) : Vector3.zero); | ||
} | ||
|
||
/// <summary> | ||
/// The GeneratePoint method creates a Vector3 based on the given point for the valid axes. | ||
/// </summary> | ||
/// <param name="point">The Point to generate the Vector3 from.</param> | ||
/// <returns>A Vector3 of the point only within the valid axes.</returns> | ||
protected virtual Vector3 GeneratePoint(Vector3 point) | ||
{ | ||
float resultX = (checkAxis.xState ? point.x : 0f); | ||
float resultY = (checkAxis.yState ? point.y : 0f); | ||
float resultZ = (checkAxis.zState ? point.z : 0f); | ||
return new Vector3(resultX, resultY, resultZ); | ||
} | ||
} | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
namespace VRTK.Core.Action | ||
{ | ||
using UnityEngine; | ||
using NUnit.Framework; | ||
using VRTK.Core.Utility.Mock; | ||
using VRTK.Core.Data.Type; | ||
|
||
public class SurfaceChangeActionTest | ||
{ | ||
private GameObject containingObject; | ||
private SurfaceChangeActionMock subject; | ||
|
||
[SetUp] | ||
public void SetUp() | ||
{ | ||
containingObject = new GameObject(); | ||
subject = containingObject.AddComponent<SurfaceChangeActionMock>(); | ||
} | ||
|
||
[TearDown] | ||
public void TearDown() | ||
{ | ||
Object.DestroyImmediate(subject); | ||
Object.DestroyImmediate(containingObject); | ||
} | ||
|
||
[Test] | ||
public void SurfaceChanged() | ||
{ | ||
UnityEventListenerMock activatedListenerMock = new UnityEventListenerMock(); | ||
subject.Activated.AddListener(activatedListenerMock.Listen); | ||
subject.changeDistance = 1f; | ||
subject.checkAxis = Vector3State.True; | ||
|
||
SurfaceData surfaceData = new SurfaceData(Vector3.one, Vector3.down); | ||
|
||
//set current surface to zero | ||
RaycastHit ray = new RaycastHit | ||
{ | ||
point = Vector3.zero | ||
}; | ||
surfaceData.CollisionData = ray; | ||
surfaceData.positionOverride = ray.point; | ||
//set surface to one so there is a change between surface positions | ||
ray = new RaycastHit | ||
{ | ||
point = Vector3.one | ||
}; | ||
surfaceData.CollisionData = ray; | ||
surfaceData.positionOverride = ray.point; | ||
|
||
subject.Receive(surfaceData, null); | ||
|
||
Assert.IsTrue(activatedListenerMock.Received); | ||
} | ||
|
||
[Test] | ||
public void SurfaceUnchanged() | ||
{ | ||
UnityEventListenerMock activatedListenerMock = new UnityEventListenerMock(); | ||
subject.Activated.AddListener(activatedListenerMock.Listen); | ||
subject.changeDistance = 1f; | ||
subject.checkAxis = new Vector3State(false, true, false); | ||
|
||
SurfaceData surfaceData = new SurfaceData(Vector3.one, Vector3.down); | ||
|
||
//set current surface to zero | ||
RaycastHit ray = new RaycastHit | ||
{ | ||
point = Vector3.zero | ||
}; | ||
surfaceData.CollisionData = ray; | ||
surfaceData.positionOverride = ray.point; | ||
//set surface to one so there is a change between surface positions | ||
ray = new RaycastHit | ||
{ | ||
point = Vector3.one | ||
}; | ||
surfaceData.CollisionData = ray; | ||
surfaceData.positionOverride = ray.point; | ||
|
||
subject.Receive(surfaceData, null); | ||
|
||
Assert.IsFalse(activatedListenerMock.Received); | ||
} | ||
} | ||
|
||
public class SurfaceChangeActionMock : SurfaceChangeAction | ||
{ | ||
//As The transform in the RaycastHit cannot be set without doing an actual raycast, just ignore that check for the test. | ||
protected override bool ValidSurfaceData(SurfaceData surfaceData) | ||
{ | ||
return true; | ||
} | ||
|
||
protected override Vector3 GetCollisionPoint(RaycastHit collisionData) | ||
{ | ||
return GeneratePoint(collisionData.point); | ||
} | ||
} | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.