⚙️ Physics in Unity 3D
A comprehensive guide to the physics system in Unity 6: components, mechanisms, and best practices for creating realistic simulations.
📋 Table of Contents
🎮 Introduction to the Unity Physics System
Unity's physics system is a simulation engine based on PhysX, which calculates realistic interactions between objects in the 3D world. Without adding code, an object with a Rigidbody will be attracted by gravity and react to collisions.
Why does physics matter?
- Realism: Objects move in a believable and predictable way
- Gameplay: Game mechanics depend on physics (jumps, collisions, gravity)
- Optimization: PhysX is highly optimized for production
- Control: You can adjust every aspect for your specific game
🔧 Main Components of the Physics System
For physics to work in Unity you need at least two components working together:
Function: Controls the movement and physics of a GameObject.
Requires: A Collider to interact.
Key properties:
- Mass
- Drag (Air resistance)
- Angular Drag (Rotational resistance)
- Gravity (Affected by gravity)
- Constraints
Function: Defines the shape of the object to detect collisions.
Types: Box, Sphere, Capsule, Mesh, Wheel, Terrain.
Key properties:
- Is Trigger
- Material (Physics Material)
- Offset
- Size
Rigidbody States
| State | Description | Use Cases |
|---|---|---|
| Dynamic | Full physics simulation. Affected by forces and collisions. | Moving objects (balls, boxes, enemies) |
| Kinematic | Moved by scripts, but dynamic objects bounce off it. | Moving platforms, doors |
| Static | Does not move. More efficient than dynamic. | Floors, walls, fixed obstacles |
📐 Types of Colliders in Unity 3D
Each type of collider is optimized for different shapes and use cases:
Shape: Cube/Rectangle.
Use: Boxes, walls, platforms.
Advantage: Very fast, ideal for simple geometric objects.
CPU: ⭐⭐⭐ | Precision: ⭐⭐⭐
Shape: Sphere.
Use: Balls, explosions, projectiles.
Advantage: Perfect for distance calculations and spherical detection.
CPU: ⭐⭐⭐ | Precision: ⭐⭐
Shape: Cylinder with hemispheres.
Use: Characters, humanoid enemies.
Advantage: Excellent for movement without getting stuck in corners.
CPU: ⭐⭐⭐ | Precision: ⭐⭐⭐
Shape: Exact geometry of the 3D model.
Use: Complex terrains, scenarios.
Warning: More expensive. Use sparingly.
CPU: ⭐ | Precision: ⭐⭐⭐⭐⭐
Shape: Specialized wheel.
Use: Vehicles, cars, motorcycles.
Advantage: Realistic simulation of suspension and grip.
CPU: ⭐⭐ | Precision: ⭐⭐⭐⭐
Shape: Height map.
Use: Wide terrains, mountains.
Advantage: Optimized for large areas.
CPU: ⭐⭐⭐ | Precision: ⭐⭐⭐
Compound Colliders
For complex objects, you can combine multiple primitive colliders on child objects:
GameObject Player
├─ Capsule Collider (body)
├─ Box Collider (arms)
└─ Sphere Collider (head)
Advantage: Greater precision than Mesh Collider, better performance than a single Mesh.
🎨 Physics Materials: Friction and Bounce
Physics Materials define how surfaces behave when they come into contact with other objects.
Main Properties
- Dynamic Friction: Friction while sliding (0 = ice, 1 = sticky)
- Static Friction: Friction at rest
- Bounciness: Bounce (0 = no bounce, 1 = maximum bounce)
- Friction Combine: How frictions are combined
- Bounce Combine: How bounces are combined
Example Values
| Material | Friction | Bounce |
| Ice | 0.05 | 0.0 |
| Asphalt | 0.7 | 0.2 |
| Tennis Ball | 0.5 | 0.8 |
| Rubber | 1.0 | 0.3 |
| Steel | 0.4 | 0.9 |
Combination Modes
When two materials collide, they are combined using one of these modes:
Average
Average of both values. The most realistic.
Multiply
Multiplication. Results in lower values.
Minimum
Uses the smaller value (stickier/less bounce).
Maximum
Uses the larger value (slipperier/more bounce).
🔗 Joints: Constraints and Articulations
Joints connect two Rigidbodies and create constrained movement behaviours. They are essential for ragdolls, chains, and mechanisms.
Behaviour: Rigidly fixes two Rigidbodies in their relative position.
Use: Joined objects, connected machine parts.
Important parameter: Breaking Force (force needed to break the joint).
// Fixed Joint in code
Rigidbody rb1 = obj1.GetComponent<Rigidbody>();
Rigidbody rb2 = obj2.GetComponent<Rigidbody>();
FixedJoint joint = obj1.AddComponent<FixedJoint>();
joint.connectedBody = rb2;
joint.breakForce = 1000f;
Behaviour: Acts like an elastic spring between two Rigidbodies.
Use: Ropes, cables, vehicle suspensions.
Parameters:
- Spring: Spring resistance (higher = stronger)
- Damper: Damping (reduces oscillations)
- Min/Max Distance: Rest distance
Behaviour: Allows rotation on one axis (like a door).
Use: Doors, mechanical arms, levers.
Configuration: Define the axis of rotation (X, Y, or Z) and rotation limits.
// Hinge Joint - Door
HingeJoint hinge = doorGameObject.AddComponent<HingeJoint>();
hinge.axis = Vector3.up; // Rotation on Y axis
hinge.limits = new JointLimits() {
min = 0,
max = 90,
bounciness = 0
};
Behaviour: Extended ball-and-socket joint for ragdolls.
Use: Ragdoll skeletons, human joints (arms, legs, neck).
Advantage: Allows complex rotation on multiple axes.
Parameters: Swing Limits (frontal rotation), Twist Limits (axial rotation).
Behaviour: The most flexible joint. Configurable in all degrees of freedom.
Use: Custom behaviours, specialized joints.
Complexity: High. Allows locking/unlocking 6 degrees of freedom (3 rotations + 3 translations).
Note: More computationally expensive than other joints.
Behaviour: Ball and socket like a hip joint.
Use: Spherical joints, hips, shoulders.
Feature: Allows rotation on all axes with specific limits.
💪 Applying Forces and Movement
There are multiple ways to move a Rigidbody. Each has its purpose:
⚡ AddForce()
Applies a continuous force that accumulates.
rigidbody.AddForce(Vector3.forward * 10);
// Gradually accelerates
Cases: Jumps, pushes, explosions.
🎯 Velocity
Sets the velocity directly.
rigidbody.velocity = Vector3.forward * 5;
// Instant velocity
Cases: Knockback, projectile movement.
🌪️ AddTorque()
Applies rotational force.
rigidbody.AddTorque(Vector3.right * 5);
// Gradual rotation
Cases: Spinning balls, rotating objects.
📍 MovePosition()
Interpolated kinematic movement.
rigidbody.MovePosition(transform.position + Vector3.forward);
Cases: Characters, moving platforms.
Force Modes
When using AddForce(), you can specify how the force is applied:
| Force Mode | Formula | Use |
|---|---|---|
| Force (Default) | acceleration = Force / Mass | Real forces (wind, gravity, pushes) |
| Acceleration | Pure acceleration regardless of mass | When you want all objects to accelerate equally |
| Velocity | Direct velocity change | Smooth character movement |
| Impulse | Applied in one frame | Explosions, instant jumps |
void FixedUpdate() {
rigidbody.AddForce(Vector3.forward * 10);
}
💥 Collision Detection
Unity offers three ways to detect collisions:
Executes when two colliders start touching.
Requires: Both with Collider, at least one with Rigidbody.
void OnCollisionEnter(Collision collision) {
Debug.Log("Collision!");
}
Executes when an object enters a Trigger.
Requires: Collider with "Is Trigger" enabled.
void OnTriggerEnter(Collider collider) {
Debug.Log("Entered!");
}
Casts an invisible ray to detect collisions.
Use: Weapons, AI vision, terrain.
RaycastHit hit;
if (Physics.Raycast(pos, dir, out hit)) {
Debug.Log(hit.collider.name);
}
Collision Detection Methods
The Rigidbody has options to detect collisions in different ways:
⚡ Optimizing the Physics System
Physics can be expensive. Here are the best practices to optimize:
❌ Avoid: Mesh Colliders for dynamic objects.
✅ Do: Use Box, Sphere, Capsule Colliders.
Primitive colliders are 10-100x faster.
❌ Avoid: Dynamic Rigidbody for objects that don't move.
✅ Do: Leave as Static or use Kinematic only when necessary.
Static objects are not recalculated every frame.
In Edit > Project Settings > Physics:
- Define which layers can collide with each other
- Example: Enemies don't need to collide with Enemies
- Reduces unnecessary calculations
For complex objects:
- Use multiple primitive colliders on child objects
- Better than a single Mesh Collider
- Faster + better precision
Each dynamic Rigidbody costs CPU:
- Limit the number in scene (max ~100 at 60 FPS)
- Use Kinematic for objects that don't need full physics
- Destroy/Pool objects when possible
In Edit > Project Settings > Time:
- Fixed Timestep: Default 0.02s (50 FPS)
- Increase to 0.03s-0.05s for less precise games
- Reduces FixedUpdate() calls
Freeze unnecessary axes:
- 2D character: Freeze Z and rotations
- Object that doesn't rotate: Freeze all rotations
- Reduces math calculations
🎮 Practical Examples
Example 1: Character Movement
// Character with jump
public class PlayerController : MonoBehaviour {
private Rigidbody rb;
public float moveSpeed = 5f;
public float jumpForce = 5f;
void Start() {
rb = GetComponent<Rigidbody>();
}
void FixedUpdate() {
// Horizontal movement
float x = Input.GetAxis("Horizontal");
rb.velocity = new Vector3(x * moveSpeed, rb.velocity.y, 0);
// Jump
if (Input.GetKeyDown(KeyCode.Space)) {
rb.AddForce(Vector3.up * jumpForce, ForceMode.Impulse);
}
}
}
Example 2: Realistic Car Physics
// Suspension and traction
public class CarPhysics : MonoBehaviour {
private Rigidbody rb;
public WheelCollider[] wheels;
public float motorForce = 3000;
public float brakeTorque = 3000;
void FixedUpdate() {
float accel = Input.GetAxis("Vertical") * motorForce;
float brake = Input.GetKey(KeyCode.Space) ? brakeTorque : 0;
foreach (WheelCollider wheel in wheels) {
wheel.motorTorque = accel;
wheel.brakeTorque = brake;
}
}
}
Example 3: Ragdoll
// Enable/Disable ragdoll
void EnableRagdoll() {
// Disable animator
animator.enabled = false;
// Enable all Rigidbodies
Rigidbody[] allBodies = GetComponentsInChildren<Rigidbody>();
foreach (Rigidbody body in allBodies) {
body.isKinematic = false;
}
// The skeleton now simulates physics
}
Example 4: Projectile with Physics
// Realistic bullet/arrow
public class Projectile : MonoBehaviour {
private Rigidbody rb;
public void Launch(Vector3 direction, float force) {
rb = GetComponent<Rigidbody>();
rb.velocity = direction * force;
// Rotate according to movement direction
transform.rotation = Quaternion.LookRotation(direction);
}
void OnTriggerEnter(Collider collision) {
if (collision.CompareTag("Enemy")) {
Destroy(gameObject);
}
}
}
📚 Tabla de Referencia Rápida
| Component/Method | Description | Performance |
|---|---|---|
| Rigidbody | Controls physics of an object | ⭐⭐⭐ |
| Box Collider | Cubic collider | ⭐⭐⭐⭐⭐ |
| Sphere Collider | Spherical collider | ⭐⭐⭐⭐⭐ |
| Capsule Collider | Cylindrical collider | ⭐⭐⭐⭐⭐ |
| Mesh Collider | Exact geometry collider | ⭐⭐ (Avoid if possible) |
| Physics.Raycast | Detects collisions with a ray | ⭐⭐⭐⭐ |
| AddForce | Applies cumulative force | ⭐⭐⭐⭐⭐ |
| Velocity | Sets direct velocity | ⭐⭐⭐⭐⭐ |
| FixedJoint | Fixes two bodies together | ⭐⭐⭐ |
| SpringJoint | Creates elasticity | ⭐⭐ |
| HingeJoint | Rotation articulation | ⭐⭐⭐ |
| CharacterJoint | Complex articulation | ⭐⭐ |
✅ Best Practices
✅ DO
- Use primitive Colliders
- Apply forces in FixedUpdate()
- Use Raycasts for detection
- Limit dynamic objects
- Use Constraints to optimize
- Profile performance regularly
- Document physics values
❌ AVOID
- Mesh Colliders on dynamic objects
- Changing transform directly
- Applying forces in Update()
- Too many complex joints
- Continuous Collision for everything
- Ignoring the collision matrix
- Physics without purpose
🔧 Troubleshooting
A: Common issues:
- The floor has NO Collider
- The Rigidbody has "Is Kinematic" enabled
- The object's velocity is too high (use Continuous Collision)
- The Collider is too small (check "Edit Collider" in Inspector)
A: Solutions:
- Apply forces in FixedUpdate(), not Update()
- Use MovePosition() for smooth movement
- Check Fixed Timestep (Project Settings > Time)
- Make sure the Capsule Collider has the correct height
A: This is "jitter":
- Increase Solver Iterations in Physics Settings
- Reduce Force Scale and Penetration per Iteration
- Make sure Colliders don't overlap
- Check that mass is realistic (not too small)
A: Joint issues:
- Verify that both Rigidbodies exist and are configured
- Make sure the Connected Body is not null
- Increase Solver Iterations if unstable
- For ragdolls: configure Character Joints correctly
🎓 Conclusion
Unity's physics system is powerful but requires understanding. Remember:
- Rigidbody + Collider = Base system (neither works without the other)
- FixedUpdate() = The only correct way to apply forces
- Primitives = Faster than Mesh Colliders
- Physics Materials = Full control of behaviour
- Joints = Create complex behaviours
- Optimization = Essential for production games
The key is understanding the difference between what physics does automatically vs what needs to be controlled by code.
- Experiment with different values in Physics Settings
- Create a small prototype: A ball rolling down a ramp
- Build a simple ragdoll to understand Character Joints
- Profile your game to identify physics bottlenecks
Post a Comment