I'm in the process of upgrading our Interaction Engine integration, and I've run into the following failure cases:
- Adding an InteractionBehaviour component to an object at runtime. It causes a null ref in the event callback setup. Initializing _eventTable if it is null in InitUnityEvents() seems to solve the problem.
- Deleting an object while hovering. InteractionBehaviour.GetHoverDistance() will null ref when it tries accessing the missing colliders. In the foreach loop through the colliders, just continue if collider is null.
- Changing scenes while holding an object, if the InteractionManager is marked Don'tDestroyOnLoad. The hand controller will null ref in CheckContactEnd()
I first tried solving the changing scenes bug by forcing the object to un-grab before loading the next level. This led me to an interesting discovery. InteractionBehaviour.ReleaseFromGrasp() throws an InvalidOperationException, since calling controller.ReleaseGrasp() will modify the collection. You can work around it like this:
public bool ReleaseFromGrasp()
{
if (isGrasped)
{
InteractionController[] controllers = new InteractionController[graspingControllers.Count];
int insertIndex = 0;
foreach(var controller in graspingControllers)
{
controllers[insertIndex] = controller;
insertIndex++;
}
foreach (var controller in controllers)
{
controller.ReleaseGrasp();
}
return true;
}
return false;
}
This implementation is far from ideal, since it allocates & generates garbage, but it will get you around the immediate problem. Unfortunately, it doesn't actually solve the root problem I was trying to solve. I'd have realized this if I'd just analyzed the problem as soon as I encountered it instead of trying hunches but hey, that hunch-trying let me find the ReleaseGrasp bug. Anyways, the root problem was that when the scene was loaded, the InteractionBehaviour object I was holding onto got deleted, but it had an entry in the contact list (because holding it meant hand contact). When the next frame happened after scene load, the contact list was invalid. The fix is simple. In InteractionController.cs, change the Start() method to the following:
protected virtual void Start() {
if (manager == null) manager = InteractionManager.instance;
UnityEngine.SceneManagement.SceneManager.activeSceneChanged +=
(UnityEngine.SceneManagement.Scene oldscene, UnityEngine.SceneManagement.Scene newscene) =>
{
ClearHoverTracking();
ClearPrimaryHoverTracking();
ClearContactTracking();
};
}
That's it for now. If I run into any more common failure cases I'll report back here. I don't promise that my workarounds are ideal, but they should be enough to clear your work blockage.
Edit: Update, ran into another one: deleting an object while being touched/contacted. Workaround: when you want to 'delete' the object, set the gameobject to inactive, set the ignore grasp, contact & hover flags to true, then delete the object a fraction of a second later. Seems to work.