-
Notifications
You must be signed in to change notification settings - Fork 2.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Refactor tap to place and fix a few issues #874
Conversation
Rework parent finding and validation. Extract interpolator code into method. Extract start and stop from HandlePlacement.
Move Utils.SetLayerRecursively into GameObjectsExtensions and set it obsolete.
…lkit-Unity into Refactor_TapToPlace
Siblings or the parent itself will still be able to hit by raycasts, constantly moving it into the user.
Also layer cache target name
@Zod-, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great!
Just a few comments.
using NUnit.Framework; | ||
using UnityEngine; | ||
|
||
namespace HoloToolkit.Unity.Tests |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is awesome. Just one suggestion is to move this into HoloToolkit-UnitTests/Utilities/Extensions
folder.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
They're technically integration tests since they interact with the unity engine and instantiate several game objects in the tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No worries, but that's where the other integration tests are located at the moment.
{ | ||
WorldAnchorManager.Instance.AttachAnchor(gameObject, SavedAnchorFriendlyName); | ||
} | ||
WorldAnchorManager.Instance.AttachAnchor(gameObject, SavedAnchorFriendlyName); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should probably still check to make sure WorldAnchorManager.Instance != null
. It's optional to have in the scene.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's implied by the else, here without diff bloat:
if (WorldAnchorManager.Instance == null)
{
Debug.LogError("This script expects that you have a WorldAnchorManager component in your scene.");
} else if (!IsBeingPlaced)
{
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In my PR addressing the updates to the WorldAnchorManager
I actually remove this line. The WorldAnchorManger
shouldn't be a required dependency.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually I did not. Looks like I also made the hard dependency. I think it would be nice if we didn't need to require it. The script should work as is.
{ | ||
if (!ParentGameObjectToPlace) | ||
{ | ||
Debug.LogWarning("No parent has been set or found."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we really want to spam log warnings if there isn't a parent intentionally setup on purpose?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good question. I actually had trouble keeping those log messages in from the old code, rather than just throwing them away.
//Removes existing world anchor if any exist. | ||
WorldAnchorManager.Instance.RemoveAnchor(gameObject); | ||
//Removes existing world anchor if any exist. | ||
WorldAnchorManager.Instance.RemoveAnchor(gameObject); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should check the instance here too. WorldAnchorManager
should be optional.
{ | ||
var layerCacheTarget = PlaceParentOnTap ? ParentGameObjectToPlace : gameObject; | ||
layerCacheTarget.SetLayerRecursively(IgnoreRaycastLayer, out layerCache); | ||
InputManager.Instance.PushModalInputHandler(gameObject); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is awesome. In fact, we probably don't even have to change the layers of the object or its children because of this change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Modal shouldn't exclude from raycasts if I understood it correctly, I'll give it a try.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As expected the object will just keep moving towards the player when not setting the layers.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for checking.
ParentGameObjectToPlace = gameObject.transform.parent.gameObject; | ||
} | ||
} | ||
SpatialMappingManager.Instance.DrawVisualMeshes = IsBeingPlaced && AllowMeshVisualizationControl; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SpatialMappingManager
is also optional. We should check if we have a valid instance.
/// <param name="headPosition"></param> | ||
/// <param name="gazeDirection"></param> | ||
/// <param name="defaultGazeDistance"></param> | ||
/// <returns></returns> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should probably add the descriptions of these parameters and what we're returning.
|
||
if (ignore.Contains(parent)) { continue; } | ||
|
||
foreach (Transform child in parent) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion: for loop instead of foreach
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For the inner loop?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For any loop if possible. Just a perf optimization.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess parent.GetChild(index)
? I won't be able to change the while loop as its dependent on the queue that constantly gets filled.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for (int i = 0; i < parent.childCount; i++)
{
parentsQueue.Enqueue(parent.GetChild(i));
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh I see, parent isn't a Transform
Component?
Partly why I avoid var
when types are not evident. No worries then.
@@ -10,14 +10,10 @@ namespace HoloToolkit.Unity | |||
/// </summary> | |||
public static class Utils | |||
{ | |||
[System.Obsolete("Use GameObjectExtensions.SetLayerRecursively(gameObject, layer) instead;")] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome. Does this PR also update the core MRTK scripts that use this obsolete reference?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did not find any references to this method.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are we not just deleting this class then?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure what the strategy is for making methods obsolete. This is in the public Utils class so people could potentially use it in their projects. Do we just straight up remove methods or set them obsolete and delete them in 1-2 releases?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Like your approach of making it obsolete! Let's use it for now and see how it pans out.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Zod- yup you're correct, generally we mark as obsolete and remove later after people get a chance to update their references.
Move attach/remove into separate methods.
Remove warnings about parents in TapToPlace Check SpatialMapper for null Added more docs to helper methods Renamed variables in IterateHierarchy Use for loop for children and move null check to the top of the loop with the other continue. Add a test for the null check
Is there any reason there are 2 extensions for getting the full path of an object in a hierarchy? There is: TransformExtensions.GetFullPath(this Transform transform, string delimiter = ".", string prefix = "/")
GameObjectExtensions.GetFullPath(this GameObject go) Each with different results and implementations. We could just link the |
|
||
objectToSet.gameObject.layer = IgnoreRaycastLayer; | ||
} | ||
spatialMapHit = new RaycastHit(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this not new and instead caller should check for null? So hitInfo.point does not fail?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Like on the physics raycast the caller checks for the return to be true. You can't set the hit info to null since it's non-nullable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah right!
I'm okay with removing one of them. |
foreach (var child in root.transform.EnumerateHierarchy()) | ||
{ | ||
int layer; | ||
if (!cache.TryGetValue(child.gameObject, out layer)) continue; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: braces
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Damn I keep forgetting about those
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changes look great. I like all the tests. Well done @Zod-
I've written some more tests in a branch based on this one that doesn't include any changes to classes in the main toolkit. |
FIrst I only wanted to do some cleanup but then found a few issues in the TapToPlace test scene:
IsBeingPlaced
. Fixed this by setting TapToPlace as Modal rather than just a global listener.PlaceParentOnTap
the parent or siblings can still get hit by ray cast because only the child itself gets theIgnoreRayCast
layer. Setting the parent recursively instead when it's used.I refactored quite a bit of the code as it was very cryptic what it was doing like that nested tertiary operator with a ray cast. I've split the
SetLayerRecursively
method into 2 parts to make it clear that it does cache and moved it intoGameObjectExtensions
. There was anotherSetLayerRecursively
inUtils
that I've also moved in there and set obsolete.I've separated the traverse of the transform hierarchy and moved it into
TransformExtensions
, using a queue instead of recursive method calls.The new extension methods are covered by several integration tests since we need some of those.
There are still a few methods that all use their own way of doing a recursive traverse, could probably clean those up too.
These 3 methods are still in TapToPlace but could be moved somewhere else, if so I wasn't sure where to put them.