Unity Physics & Collision π§
Rigidbody Component
Unity Physics is applied on components having the Rigidbody component. There is a version for 2D games: Rigidbody2D.
- Game Object will be subject to gravity
- Game Object will be colliding with other physical objects
β οΈ To move a character under physical constraints, we mustn't update its transform, but apply "forces" to it. Similarly, we use FixedUpdate
instead of Update
to update physics (running at a fixed 50 FPS).
RigidBody Update Example Script
using UnityEngine;
[RequireComponent(typeof(Rigidbody))] // or Rigidbody2D
public class RigidBodyExample : MonoBehaviour
{
[SerializeField] private float speed = 5f;
private Rigidbody _rb;
private float _horizontalInput;
private float _verticalInput;
private void Start()
{
_rb = GetComponent<Rigidbody>();
}
private void Update()
{
// Save input for use in Fixed Update
_horizontalInput = Input.GetAxis("Horizontal");
}
private void FixedUpdate()
{
// Use attributes to calculate positions/velocity/...
// Example of methods:
_rb.AddForce(Vector3.left); // move to the left
_rb.AddForce(Vector3.left * speed);
_rb.AddForce(Vector3.left * speed, ForceMode.A_MODE_HERE);
_rb.MovePosition(position);
_rb.AddExplosionForce(power, explosionPos, radius, 3.0F);
}
}
A few notes:
-
is kinematics: true
: no forces, including gravity -
use gravity: false
: still apply forces but no gravity. - Game objects with a lower mass can be pushed back by others.
- Increase "drag" will slow down the velocity (speed)
- You can freeze an axis, such as the Rotation
z
We turn on Interpolate for the player character to make collisions smoother (β οΈ two interpolated objects colliding may not be smooth at all).
π Use Edit > Project Settings > Physics
to change the gravity.
Colliders
A collider is an invisible component that will detect when a rigidbody enters a pre-defined space around the game object.
Simple colliders, e.g., with as few edges/vertices as possible, are more performant. According to what kind of games you are doing, try using the simplest collider as possible, even if there is some loss.
Click on a collider to edit it. You'll see some green dots to resize it.
Trigger Colliders
By toggling "is trigger," the collider will path through the other collider instead of colliding with it.
Layers and Colliders
By default, objects may collide even if they are not on the same layer. This is determined by the Layer Collision Matrix.
Use Edit > Project Settings > Physics
to configure it.
Physical material
It's an asset that you may create "Create > Physic Material". You can set every friction to 0 and set combine to "minimum" to disable it.
Scripts
You can use these methods to find if game objects are colliding:
// 1. return every collider inside this sphere
Physics.OverlapsSphere(position, radius)
// only layers in mask (ex: mask = LayerMask.GetMask("Default", "Water"))
Physics.OverlapsSphere(position, radius, mask)
// 2. you can use Vector3.Distance (or Vector2)
// 3. you can use Bounds.Intersects
GetComponent<Collider>().bounds.Intersects(anotherBounds);
GetComponent<Renderer>().bounds.Intersects(anotherBounds);
Each Game Object has the methods OnTrigger*
and OnCollision*
that will be called according to what kind of game objects are colliding:
Collider | Collider (isTrigger) | Collider+Rigidbody | Collider+Rigidbody (kinematic) | |
---|---|---|---|---|
Collider | x | x | OnCollisionEnter | x |
Collider (isTrigger) | x | x | OnTriggerEnter | OnTriggerEnter |
Collider+Rigidbody | OnCollisionEnter | OnTriggerEnter | OnCollisionEnter | OnCollisionEnter |
Collider+Rigidbody (kinematic) | x | OnTriggerEnter | OnCollisionEnter | x |
Raycast
We can generate a ray in a direction and detect which game object is colliding with it. The ray has an origin which is a point where the ray is coming from. It could be from the camera position if we simulate the player eyes. β οΈ Too much raycasting will cause performance issues.
var ray = new Ray(origin, direction)
Physics.Raycast(ray, out RaycastHit hit)
Physics.Raycast(ray, distance, layerMask)
Physics.Raycast(ray, out hit, distance)
Physics.RaycastAll(...)
β‘οΈ See also: Camera.ScreenPointToRay
.
For debugging purposes, we can draw a ray using:
Debug.DrawRay(origin, direction * distance, color)
π» To-do π»
Stuff that I found, but never read/used yet.
- Rigidbody: one unit = one meter
- Rigidbody2D: one unit = base sprite size, see Pixel Per Unit
- Z-fighting: increase z by 0.01