Hi there!
If you are still looking for a solution I managed to make a workaround.
First let me explain what happened.
After debugging and stack-tracing the code, I found that snaps force unsnap immediately because OnTriggerExit is being called. Now, why is this happening? It turns out that in Unity 2019.3 (and higher I think), changing the isKinematic value triggers OnTriggerExit and OnTriggerEnter events, so that automatically calls the ForceUnsnap method.
My workaround consists in creating a bool variable called "inSnapProcess", and I set it to true at the start of UpdateTransformDimensions coroutine, and I set it back to false again at the end after waiting two frames (less delay won't work) and then add a validation with this value to the CheckCanUnsnap method and that's it.
Here is the code for UpdateTransformDimensions:
bool inSnapProcess;
protected virtual IEnumerator UpdateTransformDimensions(VRTK_InteractableObject ioCheck, GameObject endSettings, Vector3 endScale, float duration)
{
inSnapProcess = true;
float elapsedTime = 0f;
Transform ioTransform = ioCheck.transform;
Vector3 startPosition = ioTransform.position;
Quaternion startRotation = ioTransform.rotation;
Vector3 startScale = ioTransform.localScale;
bool storedKinematicState = ioCheck.isKinematic;
ioCheck.isKinematic = true;
while (elapsedTime <= duration)
{
elapsedTime += Time.deltaTime;
if (ioTransform != null && endSettings != null)
{
ioTransform.position = Vector3.Lerp(startPosition, endSettings.transform.position, (elapsedTime / duration));
ioTransform.rotation = Quaternion.Lerp(startRotation, endSettings.transform.rotation, (elapsedTime / duration));
ioTransform.localScale = Vector3.Lerp(startScale, endScale, (elapsedTime / duration));
}
yield return null;
}
if (ioTransform != null && endSettings != null)
{
//Force all to the last setting in case anything has moved during the transition
ioTransform.position = endSettings.transform.position;
ioTransform.rotation = endSettings.transform.rotation;
ioTransform.localScale = endScale;
}
ioCheck.isKinematic = storedKinematicState;
SetDropSnapType(ioCheck);
yield return null;
yield return null;
inSnapProcess = false;
}
Code for CheckCanUnsnap:
protected virtual void CheckCanUnsnap(VRTK_InteractableObject interactableObjectCheck)
{
if (interactableObjectCheck != null && currentValidSnapInteractableObjects.Contains(interactableObjectCheck) && ValidUnsnap(interactableObjectCheck) && !inSnapProcess)
{
if (isSnapped && currentSnappedObject == interactableObjectCheck)
{
ForceUnsnap();
}
RemoveCurrentValidSnapObject(interactableObjectCheck);
if (!ValidSnappableObjectIsHovering())
{
ToggleHighlight(interactableObjectCheck, false);
willSnap = false;
}
interactableObjectCheck.SetSnapDropZoneHover(this, false);
if (ValidSnapObject(interactableObjectCheck, true))
{
ToggleHighlightColor();
OnObjectExitedSnapDropZone(SetSnapDropZoneEvent(interactableObjectCheck.gameObject));
}
}
}
Hope it works for you guys!