OVR Oculus, Hands issue, cant delete held objects
I'm not sure if this is a bug with unity or Oculus integration. Let me try to explain.
I am trying to destroy an object while the user is holding the object but it returns an error.
MissingReferenceException: The object of type 'BoxCollider' has been destroyed but you are still trying to access it.
A little background on my game. I spawn a prefab object and the user can pick it up and move it to another location, at this point the user can add it to another object and the object needs to be destroyed. When it is destroyed the error doesn't show straight away, only when I go back to grab another re-spawned object and then press the grip on the other controller.
I understand what the error is saying, but the box collider on that object has already been assigned in the prefab (I have checked this in the editor). The conclusion I have come to is that maybe the Oculus script, OVRGrabber is storing the grab information and when it deletes, it gets confusing since the user didn't let go of the grip button. But I have looked everywhere and I have even tried to change that script but doesn't let me change anything since it is protected. At the moment kind of ripping my hair out. If any more info is needed please ask. Hopefully, someone can help and I appreciate any help given.
Have you figured out how to solve this? I'm having the same exact problem, posted here. I found a workaround by ins$$anonymous$$d destroying only the $$anonymous$$eshRenderer of the object and making it not kinematic, so that it becomes invisible and drops to the bottom of of the scene. The only problem (for me) is that the object still exists and causes performance issues.
I found 1 work around, but it may not work for every game. The way i did it is to check if the hand is colliding with the object, and i changed the mechanic so that it says release grip to add that object, and once the user has released, then destroy the object and do what you need to do. For me this works but Its not really a fix its just a work around. If you want to do it my way, just make a script and check if that tagged obj is being held by the player, and then check if the player wants to destroy and only destroy if the player is not holding the obj.
Answer by roman_sedition · Sep 10, 2020 at 06:40 AM
You need a null check in the OVRGrabber. The OVRGrabber is storing references to objects, but it doesn't know if they've been destroyed since it only removes the reference in OnTriggerExit.
There is a Foreach loop at the top of GrabBegin, add the null check there.
i.e
protected virtual void GrabBegin()
{
float closestMagSq = float.MaxValue;
OVRGrabbable closestGrabbable = null;
Collider closestGrabbableCollider = null;
// Iterate grab candidates and find the closest grabbable candidate
foreach (OVRGrabbable grabbable in m_grabCandidates.Keys)
{
if(grabbable == null)
{
continue;
}
etc..
@roman_sedition that worked for me, thank you so much! :D Had the problem that I was deleting objects that were colliding with the Hand (which had a grabber attached to it). After that the grabber would not work anymore. With your solution everything works now. $$anonymous$$uch appreciated!
Answer by BenHowick · Feb 13, 2021 at 03:06 AM
This may be a solved issue but I thought I would add this in case anyone finds this and needs it :)
The answer by @roman_sedition worked for me and is a great method and helped me work out what was going wrong but I didn't really like the nulls still being in the list. Along with I don't like editing the imported code as it is less reusable for other projects as you have to edit the code again to be able to use the fix after every import.
This method may be clunky but I'm happy with it. I'm not saying the current answer is wrong, I am purely trying to give options :) Any improvements are appreciated.
This override function can be added into a class being derived from the OVRGrabber class meaning the original file doesn't need to be editted.
public class CustomGrabberScript : OVRGrabber //Custom script/class derives from OVRGrabber
{
protected override void GrabBegin() //Gets called instead of actual GrabBegin()
{
List<OVRGrabbable> ToRemove = new List<OVRGrabbable>(); //creates empty list for items
foreach (OVRGrabbable grabbable in m_grabCandidates.Keys) //loops through each item
{
if (grabbable == null) //If has been deleted but not removed from list (null reference)
{
ToRemove.Add(grabbable); //Adds object to the list of keys that need to be removed
}
}
for (int i = 0; i < ToRemove.Count; i++) //Loops through items that need to be removed
{
m_grabCandidates.Remove(ToRemove[i]); //Removes them from dictionary
}
base.GrabBegin(); //Calls original function
}
}
As far as I'm aware, It had to be done this way or similar as dictionaries can't be edited while being looped over. Along with dictionaries not being accessible using a for i=..... loop.
Sorry for all the spiel. I hope this helps someone :)
Answer by DemonGamesLab · May 02, 2019 at 03:54 PM
I found 1 work around, but it may not work for every game. The way i did it is to check if the hand is colliding with the object, and i changed the mechanic so that it says release grip to add that object, and once the user has released, then destroy the object and do what you need to do. For me this works but Its not really a fix its just a work around. If you want to do it my way, just make a script and check if that tagged obj is being held by the player, and then check if the player wants to destroy and only destroy if the player is not holding the obj.