- Home /
2D Physics problems - Bounciness & Gravity
Hey guys,
So I've been testing out some 2D features in Unity as I'm aiming to create a 2D game. So far, it's wonderful - my last 2D endeavor entailed hand-coding my sprite animation...not fun.
I am relying heavily on physics & 2D rigidbodies in this. My main character is moved using AddForce(). Since I want my character to have a pretty quick jump/land, I have gravity set to -100 (instead of the standard -9.81). The intense gravity setting was done as per suggestion from the actual Unity 2D tutorial video, and I like the response it gives me; however, I've run into a problem.
Problem: With rigidbodies that contain bouncy materials, the intense gravity causes them to bounce/jitter indefinitely when they should be asleep.
I have a circle collider with rigidbody properties tweaked so it behaves how I like it, with bounciness: 0.5 and friction: 1. The physics properties of the ground are friction: 1 and bounciness: 0. I've concluded that the intense gravity and the level of bounciness cause the object to have an indefinite bounce, but I cannot find a way to overcome it!
Here's what I've tried:
Increase linear drag on bouncing object - stops bouncing, but also doesn't allow the object to move much/at all.
Change mass on bouncing object - nope. Nothing.
Change gravity scale on bouncing object - obvious solution to jitter problem, but then this object behaves as it would on the moon while everything else behaves normally, resulting in non-uniform gravity.
Change bounciness - then it doesn't behave how I'd like it to!
Alter Interpolate settings, Sleep Mode settings, Collision Detection settings...no luck
Decrease Physics/Physics2D settings for gravity - then I lose the quick jump that I like.
Alter physics properties of the surfaces it bounces on - nah.
After a few days of trying every possible combination of these things, I can't seem to get it straight. I'm at a loss for ideas, Unity community...and I need your help!
I've included a link to the video below. If you don't have any suggestions, then I hope you'll at least enjoy my cat! :-3
Video: Video Here
I've also tried to adjust the sleep velocity in the physics settings to no avail. Any help would be much appreciated :)
Answer by sandygk · May 13, 2015 at 06:12 AM
You could set the Velocity Threshold from Physics2DSettings to a higher value. It worked for me.
Answer by Invertex · Jan 19, 2014 at 04:34 PM
Well, here's one solution I came up with, that you could build upon. Instead of using a bouncy material, do it through scripting.
private bool grounded; //I'm guessing you have a grounded var by now, right?
private float velY = 0;
public float bouncePower = 5f;
public float minVelBounce = -3.0f; //minimum velocity we must be going faster than, to trigger a bounce, so we don't bounce for infinity
void FixedUpdate()
{
if (!grounded)
{
velY = rigidbody2D.velocity.y; //we do this only if we aren't grounded, so that when we do OnCollisionEnter2D, we have our velocity before collision stored for various uses
}
}
void OnCollisionEnter2D(Collision2D colObj)
{
if (colObj.gameObject.tag == "Ground")
{
if(velY < minVelBounce)
{
rigidbody2D.velocity = new Vector2(rigidbody2D.velocity.x,((velY * -1) * 0.2f) * bouncePower);
velY = 0;
}
}
}
Adjust the division amount before the bouncePower to tweak how much you want the velocity.y to affect how much you bounce when you land.
It basically just stores your velocity.y before you hit a ground collider, and once you hit it, if you're moving fast enough downward to meat the minVelBounce threshold, then your velocity.y will be set to that stored velocity, divided a bit to bring it's value down and then multiplied by your bounce value. Will need some tweaking though, maybe some better math too.
Thank you, Invertex!
I really appreciate your response. Your code worked for some of what I'm looking to accomplish and I wouldn't have thought of it otherwise.
However, I'm trying to mimic the bounce property altogether with scripting, OR allow the physics sleep velocity to work. The code you provided works very well for an object falling straight down to the ground, but not I'm trying to expand it so that it works on any axis and also takes into consideration objects colliding with it at rest.
I modified your code a bit to start, and it's actually a bit shorter. Once the aforementioned properties are implemented, it could be really nice to share!
using UnityEngine;
using System.Collections;
public class Yarnball : $$anonymous$$onoBehaviour {
// Inspector variables
public float bouncePower = 1f; // Bounciness of object
public float $$anonymous$$VelBounce = 2f; // $$anonymous$$inimum velocity we must be going faster than, to trigger a bounce, so we don't bounce for infinity
public Vector2 movement;
public float velY;
void FixedUpdate() {
movement = rigidbody2D.velocity; //
velY = rigidbody2D.velocity.y; // We do this only if we aren't grounded, so that when we do OnCollisionEnter2D, we have our velocity before collision stored for various uses
}
// Function detecting collisions with object collider
void OnCollisionEnter2D(Collision2D colObj) {
rigidbody2D.velocity = new Vector2(rigidbody2D.velocity.x,((velY * -1) * 0.2f) * bouncePower);
}
}
On a side note, I feel like there's an easier way to do this. I think we can gain access to the 2D physics and set a $$anonymous$$imum velocity for which things would stop moving altogether below. This parameter already exists in the Physics options, but not in Physics2D. I'm not sure if the regular physics options affects 2D, but it doesn't seem to make a difference for me.
What if ins$$anonymous$$d:
if(grounded) && (velY < $$anonymous$$VelBounce)
{
rigidbody2D.velocity = new Vector2(rigidbody2D.velocity.x,0);
}
This way you can use your bounce materials, and bounce off walls and stuffs, but if you land on the ground, and your Y velocity is too low, you'll stop bouncing.
Logically that would be the best solution. I'm going to play around with that.
The only problem is that my "grounded" variable goes something like this:
bool grounded = false; // Is the character on the ground?
Layer$$anonymous$$ask whatIsGround; // Create layer select for deciding what is ground and what isn't
Transform groundCheck; // Game object to check for ground beneath us
float groundRadius = 0.1f; // Radius of circle to check within for collision with ground
void FixedUpdate () {
grounded = Physics2D.OverlapCircle(groundCheck.position, groundRadius, whatIsGround);
}
The way that I have the ground layer setup, the boolean will trigger when it hits any collider surface (For reference, check out the official Unity 2D platformer video tutorial).
That means in addition to the bouncing object's y velocity = 0 when it rests on ground beneath it, it will also = 0 when colliding with surfaces above and to the side.
The solution to that is to build your collider's out of Edge colliders, not Box colliders. This means each edge can be in different layers. So the top one in Ground, the side in Wall, and the bottom in Ceiling. It also fixes an issue with tiling box colliders that creates collision issues, by doing it this way.
Can read more about the issue of using box colliders here: https://www.iforce2d.net/b2dtut/ghost-vertices
You also won't have to use a circle collider anymore if you take this route (but you can still if you want to.)