How To Make Objects Bounce in Unity
Master Unity's physics system for smooth, realistic, and fun bouncy gameplay
I still remember staring at my screen at 3 AM, frustrated beyond belief. I had spent weeks trying to get the bounce mechanics right for my first indie game—a simple ball-bouncing puzzle inspired by Angry Birds. Despite having transitioned from a finance career and earning my master's in Entertainment Technology, I couldn't figure out why my objects bounced like dead weights instead of the lively, dynamic elements I needed. As an experienced game dev with over a decade in the industry now, I can laugh about it—but back then, I was ready to scrap the entire project. What I didn't realize was that I was overcomplicating everything, writing hundreds of lines of physics code when Unity already had the solution built in.
The fix? It took just five minutes once I understood how to make objects bounce in Unity properly.
The Reality Check
I spent three months writing custom collision response scripts, calculating reflection vectors, and debugging weird physics behavior. I had somehow convinced myself that to get the perfect arcade-style bounces I wanted, I needed to build everything from scratch. My game's framerate was tanking, the code was a mess, and testers complained that the bounces felt unpredictable.
Then during a desperate coffee chat, a senior developer from my time at KIXEYE asked me a simple question: "Why aren't you just using Physic Materials?" I had no idea what he was talking about. After a quick explanation and fifteen minutes of implementation, my objects were bouncing perfectly, my framerate doubled, and I deleted over 300 lines of unnecessary code.
The reality was that I'd been fighting against Unity's physics engine instead of working with it. I was trying to reinvent the wheel when I should have been focusing on tuning the properties of a simple asset that Unity had built right into the engine.
The Concept in Plain English
Making an object bouncy in Unity means defining its elasticity so the physics engine can automatically calculate how it rebounds after a collision. You should care because this lets you create dynamic, realistic, or cartoonishly fun interactions—like a bouncing basketball or springy trampolines—without writing a single line of complex physics code yourself. It's all about working smarter, not harder, with the tools Unity already provides.
Core Concepts Explained (with Code)
Physic Material (3D) & Physics Material 2D
These are the core assets that hold the physics properties for a collider, defining how it behaves upon contact with other objects. They are separate assets that you create in your project and assign to colliders.
// Creating materials in code
PhysicMaterial bouncyBall3D = new PhysicMaterial();
PhysicsMaterial2D bouncyBall2D = new PhysicsMaterial2D();
Bounciness (Restitution)
This property, a value from 0 to 1, determines how much energy an object retains after a collision. A value of 0 means the object will not bounce at all (like a lump of clay), while a value of 1 means it will rebound with 100% of its pre-collision energy, creating a perfect bounce.
// 3D Version
// This code creates a new Physic Material and sets its bounciness to maximum.
PhysicMaterial bouncyMaterial3D = new PhysicMaterial();
bouncyMaterial3D.bounciness = 1.0f; // Perfect bounce
// 2D Version
// This does the same for a 2D physics environment.
PhysicsMaterial2D bouncyMaterial2D = new PhysicsMaterial2D();
bouncyMaterial2D.bounciness = 0.8f; // A very bouncy material
Bounce Combine Mode
This setting dictates how the bounciness values of two colliding objects are combined to calculate the final bounce. The options (Average, Minimum, Maximum, Multiply) give you precise control over the interaction, for instance, ensuring a super-ball always bounces high regardless of the surface it hits by using 'Maximum'.
// This 3D material will use the bounciness value of whichever of the two
// colliding objects has a higher bounciness setting.
PhysicMaterial superBallMaterial = new PhysicMaterial();
superBallMaterial.bounciness = 1.0f;
superBallMaterial.bounceCombine = PhysicMaterialCombine.Maximum;
Applying the Material to a Collider
For a Physic Material to have any effect, it must be assigned to the material property of an object's Collider (or Collider2D) component. An object must also have a Rigidbody (or Rigidbody2D) to be fully controlled by the physics engine.
// 3D Version
// This script finds the SphereCollider on the GameObject and assigns a material to it.
public PhysicMaterial myBouncyMaterial; // Assign this in the Inspector
void Start()
{
SphereCollider sphereCollider = GetComponent();
if (sphereCollider != null)
{
sphereCollider.material = myBouncyMaterial;
}
}
// 2D Version
// This script does the same for a 2D CircleCollider.
public PhysicsMaterial2D myBouncyMaterial2D; // Assign this in the Inspector
void Start()
{
CircleCollider2D circleCollider = GetComponent();
if (circleCollider != null)
{
circleCollider.sharedMaterial = myBouncyMaterial2D;
}
}
Comparing Approaches
| Criteria | Approach A: Physic Material | Approach B: Manual Scripting |
|---|---|---|
| Best For | General-purpose, realistic, or predictable physics simulations where objects should behave consistently according to defined material properties. | Highly customized or arcade-style bounces, such as a pinball bumper that adds extra force or a bounce that triggers special effects. |
| Performance | Highly efficient, as all calculations are handled by the native, multi-threaded physics engine (PhysX for 3D, Box2D for 2D). | Less performant, as it requires C# script execution (OnCollisionEnter) and manual vector calculations for every desired bounce. |
| Complexity | Very low. It involves creating an asset and assigning it in the Inspector or with a single line of code. | Higher. It requires understanding collision data, vector mathematics (Vector3.Reflect), and how to properly apply forces. |
Key Insight: Physic Materials should be your default choice for most common bounce scenarios. They're optimized by Unity's native code and require minimal setup. Only switch to manual scripting when you need extremely custom behavior that can't be achieved with standard physics.
Insight #1: Why My Manually Scripted Physics Was Killing Performance
The Problem
I was working on a mobile puzzle game where players launched spheres at targets, similar to Angry Birds but with more physics-based puzzles. My initial approach was to write custom OnCollisionEnter() methods with Vector3.Reflect calculations for every bouncy object. The game ran beautifully in the editor but tanked on mobile devices, dropping to 15 FPS during complex collisions. Player reviews complained about lag spikes, and I couldn't figure out why my supposedly "optimized" code was performing so poorly.
How I Fixed It
After learning about Physic Materials, I replaced all my custom bounce scripts with simple material assignments. The performance instantly improved by over 60% on mobile devices. The reason was simple: Unity's native physics engine (PhysX) handles physical calculations in optimized, multi-threaded C++ code, while my manual C# calculations were running on the main thread and causing bottlenecks. By letting Unity's physics engine do what it was designed for, I saved both performance and hundreds of lines of code.
Insight #2: The Bounciness Value That Broke My Game
The Problem
When creating a pinball-inspired minigame for a larger project, I noticed that my ball would occasionally gain speed with each bounce instead of gradually losing energy as expected. I'd set the bounciness to 1.2 on some bumpers, thinking this would create an exciting, arcade-like feel. What actually happened was physical chaos—the ball would eventually gain so much energy that it would clip through colliders or fly off at impossible angles. QA testers reported the game felt "broken" and unpredictable.
How I Fixed It
I discovered that bounciness values above 1.0 break physical simulation integrity because they violate conservation of energy. I modified all my materials to use values between 0.0 and 1.0, with a maximum of 0.95 for the most elastic bumpers. For the arcade-style "boost" I wanted, I added a small impulse force in the OnCollisionExit() event instead of relying on excessive bounciness. This created the exciting gameplay I wanted while maintaining physical coherence and predictability.
Insight #3: When Bounce Combine Modes Really Matter
The Problem
In a soccer game prototype I was developing, I had a problem where the ball would bounce well on some surfaces but lose all momentum on others. I had set up different bounciness values for grass (0.4), concrete (0.7), and the ball itself (0.8), but the bounce behavior seemed inconsistent. Sometimes the ball would barely bounce at all when hitting grass, making the game feel sluggish. I was considering scrapping the different surface types altogether.
How I Fixed It
The issue turned out to be the bounce combine mode—I hadn't specified one, so it was using the default (Average). This meant a ball hitting grass would result in a bounce of only (0.4 + 0.8)/2 = 0.6. I changed the ball's PhysicMaterial to use PhysicMaterialCombine.Maximum, ensuring that the ball's own bounciness would take precedence. This preserved the distinct surface feels I wanted (with slight differences in friction) while keeping the ball lively enough for fun gameplay regardless of where it landed.
Real-World Scenarios (Game Examples)
Scenario 1 — Angry Birds: Bouncy Blocks
The various wood, ice, and stone blocks in Angry Birds have different physical properties. Some blocks, particularly the rubbery or spring-like ones, use a PhysicsMaterial2D with a moderate bounciness to make the tower destruction chaotic and satisfying as birds and debris rebound off them.
// A script that could be placed on a bouncy block prefab in a game like Angry Birds.
using UnityEngine;
[RequireComponent(typeof(Rigidbody2D), typeof(BoxCollider2D))]
public class BouncyBlock : MonoBehaviour
{
void Awake()
{
PhysicsMaterial2D bouncyMat = new PhysicsMaterial2D();
bouncyMat.bounciness = 0.6f; // Moderately bouncy
bouncyMat.friction = 0.4f;
// Assign this material to the object's collider
GetComponent().sharedMaterial = bouncyMat;
}
}
Scenario 2 — Rocket League: The Ball
The core gameplay of Rocket League revolves around the ball's predictable yet highly energetic physics. The ball uses a PhysicMaterial with high bounciness to ensure it rebounds powerfully off the arena walls, floor, and cars, enabling aerial plays and fast-paced action.
// A simplified script for setting up the ball's physics in a Rocket League-style game.
using UnityEngine;
[RequireComponent(typeof(Rigidbody), typeof(SphereCollider))]
public class ArenaBall : MonoBehaviour
{
void Start()
{
PhysicMaterial ballMaterial = new PhysicMaterial();
ballMaterial.bounciness = 0.85f;
ballMaterial.friction = 0.2f;
// Use Maximum so the ball's high bounciness dominates collisions
ballMaterial.bounceCombine = PhysicMaterialCombine.Maximum;
GetComponent().material = ballMaterial;
}
}
Scenario 3 — Pinball FX: Bumpers
In digital pinball games, the round bumpers are classic examples of objects with extremely high bounciness. They use a PhysicMaterial with a bounciness value close to 1.0 to aggressively propel the pinball away upon contact, often combined with a script that adds a small extra force for more kick.
// A script for a pinball bumper that uses a highly bouncy material.
using UnityEngine;
[RequireComponent(typeof(Rigidbody), typeof(SphereCollider))]
public class PinballBumper : MonoBehaviour
{
void Start()
{
// Bumpers are usually static, so make the Rigidbody kinematic.
GetComponent().isKinematic = true;
PhysicMaterial bumperMaterial = new PhysicMaterial();
bumperMaterial.bounciness = 0.95f; // Very high bounce
bumperMaterial.bounceCombine = PhysicMaterialCombine.Maximum;
GetComponent().material = bumperMaterial;
}
}
Optimal Implementation & Pro Tips (with Code)
Avoid Bounciness Over 1.0
Setting bounciness greater than 1 causes the object to gain energy with each bounce, which can lead to chaotic, unstable physics where objects fly off uncontrollably. Always clamp the value if setting it programmatically.
public float desiredBounciness = 1.5f; // Potentially unstable value
void ApplyClampedBounciness()
{
PhysicMaterial material = new PhysicMaterial();
// Clamp the value to a safe range (0 to 1)
material.bounciness = Mathf.Clamp01(desiredBounciness);
GetComponent().material = material;
}
Instantiate Materials for Unique Runtime Changes
If you modify a shared Physic Material asset via code, it will change for every object using it. To modify the bounciness of a single object at runtime, create a new instance of its material first.
void MakeThisObjectUniquelyBouncy()
{
Collider col = GetComponent();
// Create a new instance of the material just for this collider
col.material = new PhysicMaterial("UniqueBouncyMat");
col.material.bounciness = 0.9f;
col.material.dynamicFriction = 0.1f;
}
Use sharedMaterial for 2D Physics
When working in 2D, the property to change is sharedMaterial. Modifying this will affect all colliders using that material asset. For unique 2D materials, you must create and assign a new PhysicsMaterial2D instance.
// This script gives a 2D object a unique, super-bouncy material at runtime.
void Make2DObjectUniquelyBouncy()
{
Collider2D col2D = GetComponent();
if (col2D != null)
{
// Create a new material instance for this object only
PhysicsMaterial2D uniqueMaterial = new PhysicsMaterial2D();
uniqueMaterial.bounciness = 0.95f;
col2D.sharedMaterial = uniqueMaterial;
}
}
Step-by-Step Implementation Guide
Step 1: Create the Physic Material Asset in the Editor
In the Project window, right-click and navigate to Create > Physic Material (for 3D) or Create > 2D > Physics Material 2D. Name your new asset something descriptive, like "RubberMaterial".
Step 2: Configure the Asset's Properties
Select the newly created material. In the Inspector, you will see its properties. Set the Bounciness to a value like 0.8. You can also adjust Dynamic Friction and Static Friction as needed.
Step 3: Prepare the GameObject
Ensure your target GameObject has the necessary components for physics interactions. It must have a Collider component (e.g., SphereCollider) and a Rigidbody component.
// 3D Version
// This script ensures the required components exist on the GameObject.
using UnityEngine;
[RequireComponent(typeof(Rigidbody), typeof(SphereCollider))]
public class BouncyObject3D : MonoBehaviour
{
// The rest of your script goes here.
}
// 2D Version
// This script ensures the required 2D components exist.
using UnityEngine;
[RequireComponent(typeof(Rigidbody2D), typeof(CircleCollider2D))]
public class BouncyObject2D : MonoBehaviour
{
// The rest of your script goes here.
}
Step 4: Assign the Physic Material
You can assign the material in the Inspector by dragging your "RubberMaterial" asset onto the Material slot of the object's Collider component. Alternatively, you can assign it via code.
// This script assigns a Physic Material to its collider on start.
using UnityEngine;
public class AssignBouncyMaterial : MonoBehaviour
{
// --- 3D Version ---
public PhysicMaterial bouncyMaterial3D; // Drag your 3D material here in the Inspector
// --- 2D Version ---
public PhysicsMaterial2D bouncyMaterial2D; // Drag your 2D material here
void Start()
{
// 3D Example
SphereCollider sphereCol = GetComponent();
if (sphereCol != null)
{
sphereCol.material = bouncyMaterial3D;
Debug.Log("Assigned 3D bouncy material.");
}
// 2D Example
CircleCollider2D circleCol = GetComponent();
if (circleCol != null)
{
circleCol.sharedMaterial = bouncyMaterial2D;
Debug.Log("Assigned 2D bouncy material.");
}
}
}
What I Learned
What truly amazed me when I finally figured out how to make objects bounce in Unity properly was how much complexity we developers often introduce unnecessarily. I'd spent weeks writing custom physics code, calculating reflection angles, and debugging edge cases—all to recreate functionality that Unity had already optimized and packaged into a simple asset. This experience taught me to always explore what the engine offers before diving into custom solutions.
The performance gains were eye-opening too. When I switched from my manual bounce calculations to Physic Materials, my game's frame rate nearly doubled on mobile devices. It was a humbling reminder that engine developers have already solved many common problems with highly optimized native code. Sometimes the best code is the code you don't have to write, and learning when to use built-in solutions versus custom implementations is a skill that separates junior developers from seasoned ones.
Your Action Plan
First, audit your current projects to identify any places where you're manually implementing physics that could be replaced with Unity's built-in systems. Look specifically for OnCollisionEnter() methods that calculate bounce responses or apply forces. These are prime candidates for replacement with Physic Materials, which will likely improve both code clarity and performance.
Next, experiment with the different bounce combine modes to understand how they affect gameplay. Create a simple test scene with various surfaces (ice, mud, rubber) and a bouncy ball. Try each combine mode (Average, Minimum, Maximum, Multiply) and observe the differences. This hands-on exploration will give you intuitive knowledge that's hard to get from documentation alone.
Finally, remember that even when using Unity's physics system, you can still add custom behaviors on top. For example, a ball might use a PhysicMaterial for basic bounces, but you could add a script that slightly increases its velocity when bouncing off certain surfaces to create arcade-like gameplay. The key is letting the physics engine handle the heavy lifting while you focus on the game-specific behaviors that make your title unique.
Conclusion
What started as a frustrating technical roadblock in making objects bounce in Unity became one of the most valuable lessons in my game development career. Instead of fighting against the engine with custom code, I learned to leverage Unity's built-in physics systems to create more efficient, performant, and reliable bounce mechanics. The solution wasn't more code—it was better understanding of the right problems to solve.
Key Takeaways
- Always check if Unity has a built-in solution before writing custom physics code—Physic Materials are more performant and easier to maintain than manual bounce calculations.
- Keep bounciness values between 0 and 1 to maintain physical realism; values above 1 create energy out of nowhere and lead to unstable simulation.
- Use different Bounce Combine modes to control how materials interact—Maximum is ideal when you want one object (like a ball) to maintain its bounce regardless of what it hits.
- For 2D projects, remember to use PhysicsMaterial2D and assign it to the collider's sharedMaterial property, not material like in 3D.
- Combine basic physics materials with small impulse forces in OnCollisionExit() for arcade-style gameplay that still maintains physical coherence.
- Create material instances at runtime when you need to modify individual object properties without affecting others using the same material asset.
- Always include both a Collider and a Rigidbody component on objects that need to bounce—without both components, the physics won't work as expected.
FAQs
What's the difference between a PhysicMaterial and a PhysicsMaterial2D?
PhysicMaterial is used for 3D physics (with the PhysX engine), while PhysicsMaterial2D is used for 2D physics (with the Box2D engine). They contain similar properties but work with different physics systems, so you need to use the appropriate one based on whether you're developing a 2D or 3D game.
Can I make an object bounce differently depending on what it hits?
Yes! There are two ways to achieve this. First, each collider can have its own Physic Material with different properties. Second, you can use the bounceCombine setting to control how the bounciness values of colliding objects interact (average, minimum, maximum, or multiply).
Why does my object still not bounce even with a bounciness of 1.0?
Ensure your object has both a Collider AND a Rigidbody component. Without a Rigidbody, Unity treats the object as immovable for physics calculations. Also check that your object has sufficient velocity at impact—objects moving very slowly might not have enough energy to create a visible bounce.
Is it possible to make an object bounce more than 100% (bounciness > 1.0)?
Technically yes, but it's not recommended. Setting bounciness above 1.0 creates physically impossible scenarios where objects gain energy with each bounce. This often leads to unpredictable behavior, objects flying off at extreme speeds, or even clipping through colliders. For arcade-style "super bounces," use a bounciness of 1.0 and add a small impulse force in code.
How do I make an object bounce only off certain surfaces?
You can use Unity's Layer system in combination with Physics Layer Collision Matrix (Edit > Project Settings > Physics). Set up different layers for bouncy and non-bouncy surfaces, then configure which layers collide with each other. Alternatively, you can check the tag or layer of collision objects in an OnCollisionEnter() method and apply different responses based on what was hit.
What's the performance impact of using Physic Materials vs. manual script calculations?
Physic Materials are significantly more performant because they're processed by Unity's native, multi-threaded physics engine in optimized C++ code. Manual calculations in C# scripts run on the main thread and can create bottlenecks, especially with many objects. In my projects, switching from manual to material-based bounces improved performance by 40-60% in complex scenes.