- Home /
Having issues with stacked rigidbody2D objects
Context: I'm making a small experimental 2D game in which you control a rectangle that moves horizontally and other rectangular blocks fall on top of the rectangle from the sky. These blocks are simply sprites with a rectangular Collider2D and a Rigidbody2D, such that they rely completely on the physics engine for their falling and "stacking" behavior. The idea here is that the blocks would just stack on top of eachother and you'd carry them across the stage in your little raft.
Issue: My problem is that when the blocks are stacked on top of each other (again, each block is a sprite with a rectangular Collider2D and a Rigidbody2D) they move tiny little distances (like 0.001 or 0.0001 units at a time) over time, such that eventually blocks that look like they should be safely stacked will fall off the side of the blocks under them. Furthermore, the blocks underneath them will slide in the opposite direction, causing a fairly unstable stacking scenario where it doesn't seem like there should be one.
After trying to modify basically all visible parameters for several hours (friction, linear/rotational drag, mass, etc) I tried to "dampen" these tiny changes in velocity myself via the Update script by setting the rigidbody2D.velocity to Vector2.zero if the absolute value of the velocity was within a tiny threshold, but this did not seem to have any effect whatsoever. I did something similar for rotation (by setting the rotation to zero if it's within a very tiny threshold), and that seemed to work correctly, but for some reason the same does not work for velocity. The one thing that seemed to make things work, strangely enough, was setting fixed angle to true, but I don't want to disable rotation since it'd be an essential part of this little game.
A few important things to note: 1) This happens regardless of the moving platform: the physics issue I'm having also occurs when blocks pile onto a static, unmoving platform that is set to IsKinematic = true. 2) There are no other components in the game such a animators or things like that. Yes, I did search and I did find those posts in this site.
Summary Of Question: I'm trying to figure out whether or not the Unity physics engine makes it possible to stack multiple rigidbody2D rectangular blocks on top of each other, since my (very frustrating) experience has been that these blocks, when stacked, move ever-so-gradually to the sides until they fall; I have been unsuccessful in "dampening" tiny changes in velocity via the Update method.
Any help would be nicely appreciated!
Getting a specific set of behaviors from the physics sim requires a great deal of tweaking and testing and trial and error. "several hours" might not be enough. ;)
Sounds like you've already gotten a taste of that. The physics sim also has a "preferred scale" at which interactions are most stable. How big are these objects, in unity units?
Have a look at this thread from a few days ago, see if anything there stands out: http://answers.unity3d.com/questions/949564/marble-rapidly-loses-momentum-after-rolling-down-r.html#comment-949886
Hey, thanks for your response! I guess I have more fine-tuning up ahead =).
The objects being stacked have a box collider with dimensions around 0.3x0.3 unity units, with a scale of around 11x2. Do you recommend a specific range of scales for this type of physics simulation?
It used to be recommended that you avoid scaling objects differently on different axes. Ins$$anonymous$$d, you were supposed to model any mesh such that the mesh's default (1,1,1) scale reflected the desired dimensions, only scale axes together (1,1,1...2,2,2...), and use a collider whose "size" property caused the collider to encompass the object.
I seem to recall this is supposedly no longer an issue, however.
I think 0.3 units is pretty darn small. I'm frankly not sure whether the collider being scaled by the owning object's transform matters in any way, since this rarely came up for me when following the aforementioned practice.
It is conceivable that this small size or unusual scaling is exacerbating the problem, though it may not be the source. The smallest bodies I ever worked with were ~0.25 units in diameter, but these were "decorative" objects so I never paid attention to their behavior in great detail or relied on their stability.
Friction settings on the phys material, especially the combine settings, might play a role in this issue. In real life, many materials' static friction is about ~2x dynamic friction; that might help settle things down. Have you tested this issue with very high friction coefficients to rule out friction as the culprit?
Enforcing this specific kind of behavior via scripting is usually not advisable, either, just so that gets said.
Having so many factors at play makes tracking such issues quite obnoxious, as I'm sure you'll come to appreciate as the hours go by. ;)
A video of the issue might help. And I don't think you've mentioned roughly how many bodies must be stacked before this issue manifests; if it's something crazy like 100's, that's just asking for a problem.
I'll post a video once I get home. I've seen this happen with as few as 2 blocks stacked over each other (that is, with only one block stacked over one block and no other blocks in the system), though more blocks seem to make it happen faster or more visibly.
I should make a few additional observations that here that I've since noticed:
1) This sliding is more noticeable as blocks are not "centered" over other blocks. That is, it occurs with less magnitude when blocks are aligned such that their centers align vertically (though it still occurs, which is the problem).
2) Setting the velocity and position iterations in the project's physics2D properties actually seems to improve things substantially (which I suppose should have been relatively obvious).
All that said, even with all these workarounds, this is still a problem that prevents my game's physics from being as playable as I'd like. Once I get home I will post a video, and then I'll try to see what'll happen if I increase the scale; maybe the shifts in distance become small enough, in relative terms, to be negligible, which may solve this problem.
One thing that I'd like to see the effect of (but have not been successful with) is to somehow totally eli$$anonymous$$ate tiny changes in position each frame (that is, if the position of a transform only changes by something like < 0.001 in an update cycle, I'd like for it to be ignored and maintain its exact position).
Thanks again for all the help =)
Answer by lordlycastle · Apr 22, 2015 at 11:25 PM
They had a similar problem in Halo with grenades, they kept moving and using resources. The hack they used was sleep the rigidbody when it’s velocity is less than some amount. You could try that; because it’s a simulation and getting it perfect would just take too much time and effort. You can also try setting the friction of the material to a high value, or the mass. It really depends on what kind of behaviour you want, but I don’t think you’ll ever be able to stop a rigidbody perfectly without using some kind of hack; most games do.
This sounds like what I was attempting to do (set the velocity to 0 if it's small enough), but I was not able to get it to work. Specifically, I checked if the absolute value of the x axis of the rigidbody2D's velocity was between 0 and some tiny number like 0.001 and I'd set the rigidbody2D's velocity to Vector2.zero in that case. However, I found that doing so did not stop the position of the object from changing by tiny amounts. Could it be that this position is not actually tied to velocity, but to some other calculation?
In your original question, you mentioned the object on which you're stacking these smaller objects will move; I assumed you only stopped this platform's movement for testing purposes. This "moving platform" requirement renders sleep enforcement nonsensical.
Forcing bodies to sleep earlier will only help if the platform is static and other objects aren't agitating the "stack". Changing the sleep threshold in the project physics settings is synonymous-to and cheaper-than attempting to enforce a zero velocity yourself, which would be redundant.
But again, in a stacking situation, it's nonsensical. If some bodies' velocities are forced to zero (or sleep earlier) in sequence during FixedUpdate, other bodies in the simulation will impart forces upon those bodies within the same or next moment and nullify the enforcement. See:
http://docs.unity3d.com/$$anonymous$$anual/ExecutionOrder.html
This phenomenon probably has a real name, but I call it "cross talk" - I believe your objects are having difficulty co$$anonymous$$g to rest, and the problem is exacerbated by each element in the stack influencing its neighbors ad infinitum. The suggestion to use a high coefficient of friction is the most sensible so far. Crank it all the way up to 1 with a "maximum" combine setting and see what happens.
@Flavioli The position is actually tied to the velocity, but as you said that boxes that are only partially on other boxes appear to gain velocity faster than those that aren’t. That’ because the gravity is working on them, so even if you set the velocity zero it’s gonna gain some due to gravity.
In real life there several force working to keep that movement from increasing, like friction. Getting similar values of friction is quite nearly impossible. You can however, try playing with the drag as it’ll be easier to get to a acceptable value.
After quite a bit of tweaking and playing around with settings based on the advice given here, I'm convinced that these movements are just the results of tiny interactions resulting from the physics engine (and its unfortunate-but-understandable lack of exactness); by messing with gravity it appears that the small displacements are likely due to the combination of all forces like gravity and friction causing small but non-zero changes in displacement.
The solution so far seems to be just accepting these quirks and modifying the environment to make them less obvious. The best "workaround" results thus far have been from adjusting the scale such that the tiny shifts in position are less discernible.
Either way, it doesn't seem like this simulation can be perfect, but it's good enough as it is, I think.
Thanks for the help everyone! =)
Answer by escagork · Jul 20, 2020 at 10:05 AM
becase of your rigidbody's Collision Detection set it from Discrete to Continuous.
Your answer
Follow this Question
Related Questions
How to rotate a Rigidbody2D faster than 4500 (degrees/s)? 0 Answers
2d character horizontal movement 1 Answer
Drag Object Script Problem 2 Answers
Weird behaviour after Collision? 0 Answers
Using child colliders with rigidbodies/joints in 2D 0 Answers