Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Proper way to delete a (Obi)Rigidbody (if there is one)
#1
Hello!

I have the rope set up in such a way where one spawns after the player character fires a bow at the ceiling, and when the arrow hits the ceiling, a rope extends downward, so that the character can climb up it. When the arrow hits the ceiling, everything spawns (solver, updater, renderer, etc.), along with a weight at the bottom of the rope so that the rope is always calm and held down as it gradually extends towards the ground. Everything works great and looks really good. Also I can do this pretty much as many times as I want (i.e. fire a bunch of arrows at the ceiling, one after another, and all of them spawn their own ropes with their own solvers and their own weights, etc. - no errors whatsoever).

Now I'm trying to change it so that there's only 1 rope at a time. When the player character fires another arrow at the ceiling, I want it to destroy the previous rope and then just make a new one in the new location. I'm using Unity's standard Destroy() method to destroy the rope parent (which has the solver and updater attached to it, then the rope itself which is a child, and the weight which is a separate object that's a child of the rope). Deleting the object throws no errors by itself. However, when I then go to shoot a new arrow to spawn a new rope, Unity starts throwing endless errors, which pertain to the Rigidbody of the weight object.

I'm assuming from the errors that the Obi code somewhere is trying to access/update the rigidbody that was attached to the weight at the bottom of the original rope, which has since been destroyed and no longer exists. Is there something I need to call first before destroying the rope, solver, and rigidbody so I can spawn the new rope without errors?

If I delete the old rope except for the weight with the rigidbody, then there are no errors. It's only when I delete the weight that it throws errors when I try to spawn a new rope. I'm assuming Obi has an internal list of rigidbodies it's trying to update when the new rope tries to spawn and I'm destroying them improperly.

Thank you in advance for your assistance.

   
Reply
#2
(04-10-2023, 09:33 PM)Lazerpants Wrote: Hello!

I have the rope set up in such a way where one spawns after the player character fires a bow at the ceiling, and when the arrow hits the ceiling, a rope extends downward, so that the character can climb up it. When the arrow hits the ceiling, everything spawns (solver, updater, renderer, etc.), along with a weight at the bottom of the rope so that the rope is always calm and held down as it gradually extends towards the ground.

Hi!

Having one updater per rope will yield rather poor performance, since it forces all ropes in your scene to be simulated sequentially - instead of taking advantage of multithreading. Ideally you should have a single updater per scene, in charge of updating all your solvers. This is far more efficient. See:

http://obi.virtualmethodstudio.com/manua...aters.html
http://obi.virtualmethodstudio.com/manua...cture.html

Having one solver per rope is also very wasteful, unless each rope requires different global parameters (such as the reference frame, gravity, or constraint settings).

(04-10-2023, 09:33 PM)Lazerpants Wrote: Now I'm trying to change it so that there's only 1 rope at a time. When the player character fires another arrow at the ceiling, I want it to destroy the previous rope and then just make a new one in the new location. I'm using Unity's standard Destroy() method to destroy the rope parent (which has the solver and updater attached to it, then the rope itself which is a child, and the weight which is a separate object that's a child of the rope). Deleting the object throws no errors by itself. However, when I then go to shoot a new arrow to spawn a new rope, Unity starts throwing endless errors, which pertain to the Rigidbody of the weight object.

I'm assuming from the errors that the Obi code somewhere is trying to access/update the rigidbody that was attached to the weight at the bottom of the original rope, which has since been destroyed and no longer exists. Is there something I need to call first before destroying the rope, solver, and rigidbody so I can spawn the new rope without errors?

At which point in the frame are you calling Destroy() on the updater/solver/rope/rigidbody? I can only imagine this being an issue if you do it during the updater's update cycle, since it will prevent it from cleaning up data associated to destroyed rigidbodies.

kind regards,
Reply
#3
(05-10-2023, 06:42 AM)josemendez Wrote: Hi!

Having one updater per rope will yield rather poor performance, since it forces all ropes in your scene to be simulated sequentially  - instead of taking advantage of multithreading. Ideally you should have a single updater per scene, in charge of updating all your solvers. This is far more efficient. See:

http://obi.virtualmethodstudio.com/manua...aters.html
http://obi.virtualmethodstudio.com/manua...cture.html

Having one solver per rope is also very wasteful, unless each rope requires different global parameters (such as the reference frame, gravity, or constraint settings).


At which point in the frame are you calling Destroy() on the updater/solver/rope/rigidbody? I can only imagine this being an issue if you do it during the updater's update cycle, since it will prevent it from cleaning up data associated to destroyed rigidbodies.

kind regards,


Hello again!

I managed to figure out how to delete the rope and make a new one without any errors. It was tricky and took some trial and error, but it does seem to work fine.

I originally implemented Obi rope a while ago (maybe last year? Or earlier this year, something like that), and honestly I don't remember what I originally intended, but I made it so each rope has it's own updater and solver, with a script that disables both of those components the moment the rope stops being interacted with by the player character. In my use case each rope just hangs there perfectly still, unless the player character is climbing up one of them, in which case it gets enabled to react realistically while being climbed, and then when the player lets go, the rope falls straight again and the solver and updater are disabled almost immediately. I might have intended to just leave it that way until later when I further optimize everything, but for now that seemed to work fine. If there are 20 ropes, then there are 20 solvers and 20 updaters, but all of them are disabled, except for whichever rope is being climbed (if any). Thanks for reminding me that you can have multiple solvers with a single updater, because I definitely forgot that from when I first implemented it. When I go to further optimize later, I'll definitely keep that in mind.

So what I ended up doing to fix the errors, was to use GetComponent<ObiParticleAttachment>() to grab the particle attachment component that was referencing the rigidbody, then disabled it first before deleting the whole rope, THEN deleted the rope. This stopped the endless loop of rigidbody errors, but it created a new error in BurstColliderWorld.cs at line 61. It said I wasn't allowed to use DestroyImmediate(). I realized it was probably deleting something while it was in the middle of updating, so instead of just deleting the whole rope right away, I set up a timer in the script to delete the whole rope 5 physics frames after disabling the particle attachment. That fixed the error for DestroyImmediate(), but then created another "object reference not set to an instance of an object" error in ObiColliderWorld.cs in the UpdateColliders() method. For some reason, it didn't like referencing colliderHandles.Count in the for loop. So I changed it to this:

public void UpdateColliders()
        {

            int colliderHandlesCount = colliderHandles.Count;

            // update all colliders:
            for (int i = 0; i < colliderHandlesCount; ++i)
                colliderHandles[i].owner.UpdateIfNeeded();
        }


And poof, no more errors. Literally no idea why the for loop was throwing errors in the first place, though. I was using Debug.Log() to tell me if colliderHandles ever became null while I was experimenting and it never did. I'm thinking maybe it was some weird quirk of Visual Studio? Or perhaps something to do with the version of Unity I'm using. Or some combination thereof. But it works, and thought you might find it interesting how I did it. Also, I should mention I'm using Obi Rope 6.2. I don't know if that matters but that was the latest version when I first implemented it, and haven't updated since.


Anyway, thank you for your time and assistance! I appreciate you, sir. Gran sonrisa


PS: Oh you asked me at what point I was deleting the old rope originally. The process was: player presses up on the D pad which sets an animator controller trigger, which makes the character transition to an animation of him shooting the bow at the ceiling. In the animation itself, there's an event call, which calls method ShootRopeArrow(). In ShootRopeArrow(), it tests object reference ropeArrowRope to see if it's null. If it's null, then it just fires an arrow at the ceiling, which spawns a new rope (i.e. first rope created). If it's not null (a rope exists already), then it used Destroy() to get rid of it, then fired the arrow to create a new one. Now instead of that, it disables the particle component first and then deletes the rope 5 frames later.
Reply