- Home /
2D Bounce gains energy each time
I want to create a bouncy ball in unity 2D that will bounce infinitely without losing/gaining energy with each bounce. My setup is: a ball sprite with circle collider and rigidbody2D set to dynamic, and a floor sprite with a box collider.
I have already found a lot of questions like this one and the answer is always:
1. Create a Physics2D material with friction = 0 and bounciness = 1.
2. Set the ball's rigidBody2D to have 0 drag ad attach the new physics material to it.
3. Set the rigidbody2D to have discrete collision detection.
Problem is I already have done all of the above but the ball bounces higher and higher every time. Is it a bug in unity 2019.4.2f1 or am I missing something?
This is a hunch, but try setting the bounciness of your physics material to match the value of gravity in Project Settings>Physics. So if your gravity is -9.81, then try your bounciness at 0.981.
If that works, then I guess bounciness is an absolute value, rather than a relative value (i.e. bounce back at 100% of the inco$$anonymous$$g speed).
Just tried it, but that's not the solution unfortunately. I believe bounciness is a relative value since 0.99 gives me a bounce that loses very little energy so the ball will take a lot of time to stop, but eventually will. But then why would 1 not work? Still looking for a solution...
I agree that bounciness of 1 sounds like it should give a perfect bounce when all drag and friction is set to 0. But when I tried it, it gave a significant boost as you pointed out. Another option might be to detect the collision and set the velocity of the rigidbody to be the reflection of the pre-collision velocity vector.
Answer by Riki9811 · Aug 17, 2020 at 09:08 AM
I managed to get what I wanted (it's not perfect elastic bounce but for my project will do just fine). Thanks to @davidcox70 for the tip.
Here is my setup: I removed the physics material from the rigidbody and left it to null. All the other settings for the rigidbody remain untouched. Then I created a script and attached it to the ball. The script has:
[RequireComponent(typeof(Rigidbody2D))]
public class BallController : MonoBehaviour
{
private Vector2 preHitVelocity;
private Rigidbody2D rb;
void Start()
{
rb = GetComponent<Rigidbody2D>();
}
void Update()
{
preHitVelocity = rb.velocity;
}
void OnCollisionStay2D(Collision2D other)
{
Vector2 avgNormal = Vector2.zero;
for (int i = 0; i < other.contactCount; i++)
{
avgNormal += other.GetContact(i).normal;
}
avgNormal /= other.contactCount;
rb.velocity = Vector2.Reflect(preHitVelocity, avgNormal);
}
}
This works by caching the velocity of the ball each frame in the Update() method.
Then in the OnCollisionStay2D() method (I initially used OnCollisionEnter2D() but it didn't work for me don't know why) I calculate the average normal of the collision and then I use it with the preHitVelocity to reflect the velocity of the rigidbody.
This gives me an almost perfect bounce. Sometimes the ball will bounce slightly lower then it should, but on the next bounce it will go back up to the right height. Tested it a bunch and seems to be a stable solution. I'm not sure if it's the optimal one though...