Game Frameworks  
Lecture 03: 2D Physics in Unity  
Edirlei Soares de Lima  
<edirlei.lima@universidadeeuropeia.pt>  
Unity – Physics  
•
•
Unity simulates physics in 2D and 3D to ensure that objects  
correctly accelerate and respond to collisions, gravity, and  
various other forces.  
–
3D physics: Nvidia PhysX engine integration  
–
2D physics: Box2D engine integration  
Main components:  
–
Rigidbodies  
–
Colliders  
Rigidbody 2D  
•
Rigidbody is the main component that  
enables physical behavior for a GameObject.  
–
With a Rigidbody attached, the object will  
immediately respond to gravity.  
–
If a Collider component is also added, the  
GameObject will be moved by incoming collisions.  
•
Important: since a Rigidbody component controls the  
movement of the GameObject, never try to move it  
from a script by changing the Transform properties  
such as position and rotation.  
–
Instead, use the physics engine to apply forces to push the  
GameObject and let the physics engine calculate the results.  
Rigidbody 2D  
•
Body Type:  
–
Dynamic: for objects designed to move under  
simulation. It uses the full set of properties, such  
as finite mass and drag, and is affected by gravity  
and forces.  
•
•
•
A Dynamic body will collide with every other body type.  
It is the most performance-expensive body type.  
Never use a script to set the position or rotation of a  
Dynamic Rigidbody using its Transform component.  
Rigidbody 2D  
•
Body Type:  
–
Kinematic: for objects designed to move under  
simulation, but only under very explicit user  
control. It is not affected by gravity and forces.  
•
•
•
It does not collide with other Kinematic or Static  
Rigidbodies (only collides with Dynamic Rigidbodies).  
It has a lower demand on system resources than a  
Dynamic Rigidbody.  
It is designed to be repositioned explicitly via  
MovePosition or MoveRotation functions.  
Rigidbody 2D  
•
Body Type:  
–
Static: for objects designed to not move under  
simulation at all. If anything collides with it, the  
object behaves like an immovable object.  
•
•
•
Only collides with Dynamic Rigidbodies.  
The least resource-intensive body type.  
All GameObjects that have a Collider component and do  
not have a Rigidbody, are automatically considered Static  
RigidBodies.  
Collider 2D  
•
A Collider component defines the shape of a  
GameObject for the purposes of physical  
collisions.  
–
A collider is invisible and does not need to be the  
exact same shape as the object.  
•
Rough approximations are often more efficient and  
indistinguishable in gameplay).  
–
–
The simplest (and least processor-intensive)  
colliders are primitive collider types:  
•
Box, Circle, and Capsule.  
More complex and customizable colliders:  
•
Edge and Polygon.  
Physics – Example 1  
•
Example 1: Hello Physics World  
–
–
–
Add Box Colliders 2D to the platforms.  
Add a Circle Collider 2D to the ball.  
Add a RigidBody 2D to the Ball.  
Physics Material 2D  
•
A Physics Material is used to adjust the  
friction and bounce that occurs between  
physics objects when they collide.  
–
Example: Ball bouncing  
Scripting – Add Force  
•
Example 2: Moving the Ball with a Force  
public class BallMovement : MonoBehaviour  
{
public float moveForce = 20;  
private Rigidbody2D rigidBody;  
private void Start()  
{
rigidBody = GetComponent<Rigidbody2D>();  
}
private void FixedUpdate()  
{
float horizontalInput = Input.GetAxis("Horizontal");  
rigidBody.AddForce(Vector2.right * horizontalInput *  
moveForce);  
}
}
–
Important: always use FixedUpdate when manipulating a Rigidbody.  
Scripting – Vector2 Class  
•
•
The Vector2 class represents 2D vectors.  
–
It also contains functions and properties for common vector  
operations: magnitude, normalization, dot product, cross product,  
angle, etc.  
Main Constants:  
–
–
–
–
–
–
Vector2.down: shorthand for writing Vector2(0, -1).  
Vector2.left: shorthand for writing Vector2(-1, 0).  
Vector2.one: shorthand for writing Vector2(1, 1).  
Vector2.right: shorthand for writing Vector2(1, 0).  
Vector2.up: shorthand for writing Vector2(0, 1).  
Vector2.zero: shorthand for writing Vector2(0, 0).  
Scripting – Vector2 Class  
•
Main functions:  
Vector2.Angle(Vector2 from, Vector2 to): returns the unsigned angle in degrees  
between from and to.  
–
–
Vector2.ClampMagnitude(Vector2 vector, float maxLength): returns a copy of  
vector with its magnitude clamped to maxLength.  
–
–
–
Vector2.Distance(Vector2 a, Vector2 b): returns the distance between a and b.  
Vector2.Dot(Vector2 lhs, Vector2 rhs): dot Product of two vectors.  
Vector2.Lerp(Vector2 a, Vector2 b, float t): linearly interpolates between  
vectors a and b by t.  
–
–
Vector2.MoveTowards(Vector2 current, Vector2 target, float maxDistanceDelta):  
moves a point current towards target.  
Vector2.SmoothDamp(Vector2 current, Vector2 target, ref Vector2  
currentVelocity, float smoothTime, float maxSpeed = Mathf.Infinity, float  
deltaTime = Time.deltaTime): Gradually changes a vector towards a desired goal  
over time.  
Scripting – Velocity Change  
•
Example 3: Player Movement (Platform Game)  
public class PlayerMovement : MonoBehaviour  
{
public float moveForce = 6;  
private Rigidbody2D rigidBody;  
private void Start()  
{
rigidBody = GetComponent<Rigidbody2D>();  
}
private void FixedUpdate()  
{
float horizontalInput = Input.GetAxis("Horizontal");  
rigidBody.velocity = new Vector2(horizontalInput *  
moveForce, rigidBody.velocity.y);  
}
}
Effectors 2D  
•
•
Effector 2D are components that control the  
forces of physics when GameObject colliders  
come into contact with each other.  
Effectors:  
–
PlatformEffector2D: creates platform behaviors  
such as one-way collisions and no side friction;  
–
–
SurfaceEffector2D: simulates conveyor belts;  
PointEffector2D: attracts or repulses against a  
given source point;  
–
–
BuoyancyEffector2D: makes GameOjects float;  
AreaEffector2D: randomly vary force and angle  
magnitude;  
Scripting – Impulse Force & Raycast  
•
Example 4: Player Jump (Platform Game)  
public class PlayerMovement : MonoBehaviour{  
public float moveForce = 6;  
public float jumpForce = 7.2f;  
private Rigidbody2D rigidBody;  
private float feetOffset = 0;  
private void Start(){  
rigidBody = GetComponent<Rigidbody2D>();  
BoxCollider2D collider = GetComponent<BoxCollider2D>();  
feetOffset = ((collider.size.y * transform.localScale.y) / 2)+ 0.01f;  
}
private bool IsOnGround(){  
Vector2 playerFeet = new Vector2(transform.position.x,  
transform.position.y - feetOffset);  
RaycastHit2D hit = Physics2D.Raycast(playerFeet, Vector2.down, 2.0f);  
if (hit.collider != null){  
float distance = Mathf.Abs(hit.point.y - playerFeet.y);  
if (distance < 0.1){  
return true;  
}
}
return false;  
}
Scripting – Impulse Force & Raycast  
•
Example 4: Player Jump (Platform Game)  
...  
private void FixedUpdate()  
{
float horizontalInput = Input.GetAxis("Horizontal");  
float jumpInput = Input.GetAxis("Jump");  
if ((jumpInput > 0) && (IsOnGround()))  
{
rigidBody.AddForce(Vector2.up * jumpForce, ForceMode2D.Impulse);  
}
rigidBody.velocity = new Vector2(horizontalInput * moveForce,  
rigidBody.velocity.y);  
}
}
Physics 2D – Raycast  
•
The Raycast function casts a ray against colliders in the Scene.  
RaycastHit2D Raycast(Vector2 origin, Vector2 direction, float distance =  
Mathf.Infinity, int layerMask = DefaultRaycastLayers,  
float minDepth = -Mathf.Infinity, float maxDepth =  
Mathf.Infinity);  
–
Returns a RaycastHit object with a reference to the collider that is hit  
by the ray.  
•
The collider property of the result will be NULL if nothing was hit.  
–
The layerMask can be used to detect objects selectively only on  
certain layers.  
•
In last example, the function IsOnGround() can be optimized by defining a Layer on  
objects that represent ground. The Layer can then be used in the layer mask  
parameter to only check collisions with relevant objects.  
RaycastHit2D hit = Physics2D.Raycast(playerFeet, Vector2.down, 2.0f,  
LayerMask.GetMask("Ground"));  
Physics 2D Settings  
•
Edit -> Project Settings  
–
Physics 2D settings can be used  
to change global settings for 2D  
physics simulation.  
Scripting – Top-Down Movement  
•
Example 5: Player Movement (Top-Down Game)  
public class TopDownPlayerMovement : MonoBehaviour  
{
public float moveForce = 6;  
private Rigidbody2D rigidBody;  
private void Start()  
{
rigidBody = GetComponent<Rigidbody2D>();  
}
private void FixedUpdate()  
{
float horizontalInput = Input.GetAxis("Horizontal");  
float verticalInput = Input.GetAxis("Vertical");  
rigidBody.velocity = new Vector2(horizontalInput * moveForce,  
verticalInput * moveForce);  
}
}
Scripting – Top-Down Movement  
•
Example 6: Pushing Objects (Top-Down Game)  
–
–
Dynamic objects must have a RigidBody2D.  
Adjust the Linear Drag to make them stop faster.  
•
For the physics engine, the objects are in the air, so there  
is not friction.  
–
Adjust the Mass to make objects heavier.  
Scripting – Top-Down Movement  
•
Example 7: Player Movement based on Mouse Position  
public class SpaceshipMovement : MonoBehaviour{  
public float moveForce = 3;  
public float minMouseDistance = 50;  
private Rigidbody2D rigidBody;  
private void Start(){  
rigidBody = GetComponent<Rigidbody2D>();  
}
private void FixedUpdate(){  
float horizontalInput = Input.GetAxis("Horizontal");  
float verticalInput = Input.GetAxis("Vertical");  
Vector2 mouseDirection = Input.mousePosition -  
Camera.main.WorldToScreenPoint(transform.position);  
if (mouseDirection.magnitude > minMouseDistance){  
float rotationAngle = Mathf.Atan2(mouseDirection.normalized.y,  
mouseDirection.normalized.x) * Mathf.Rad2Deg;  
rigidBody.SetRotation(rotationAngle - 90);  
}
rigidBody.velocity = (((transform.up * verticalInput) +  
(transform.right * horizontalInput)) * moveForce);  
}
}
Scripting – 2D Physics Events  
•
•
Collision Events:  
–
–
–
void OnCollisionEnter2D(Collision collision) – is called when the  
collider/rigidbody has begun touching another rigidbody/collider.  
void OnCollisionStay2D(Collision collision) – is called once per frame for every  
collider/rigidbody that is touching the rigidbody/collider.  
void OnCollisionExit2D(Collision collision) – is called when the collider/rigidbody  
has stopped touching another rigidbody/collider.  
Trigger Events:  
–
–
–
void OnTriggerEnter2D(Collider collider) – is called when the collider/rigidbody  
has begun touching another collider that is a trigger.  
void OnTriggerStay2D(Collider collider) – is called once per frame for every  
trigger collider that is touching the rigidbody/collider.  
void OnTriggerExit2D(Collider collider) – is called when the collider/rigidbody  
has stopped touching another collider that is a trigger.  
Scripting – 2D Physics Events  
•
Example 8: Destroy the Spaceship on Collision  
public class SpaceshipMovement : MonoBehaviour{  
...  
private void OnCollisionEnter2D(Collision2D collision)  
{
if (collision.collider.tag == "Asteroid")  
{
Destroy(gameObject);  
}
}
}
Scripting – 2D Physics Events  
•
Example 9: Change the color of the Spaceship when it enters the heal area.  
public class HealArea : MonoBehaviour  
{
private void OnTriggerEnter2D(Collider2D collision)  
{
if (collision.gameObject.tag == "Player")  
{
collision.gameObject.GetComponent<SpriteRenderer>().color = Color.blue;  
}
}
private void OnTriggerExit2D(Collider2D collision)  
{
if (collision.gameObject.tag == "Player")  
{
collision.gameObject.GetComponent<SpriteRenderer>().color = Color.white;  
}
}
}
Scripting – 2D Physics Events  
•
Example 10: Shooting and Destroying Asteroids  
public class TopDownPlayerMovement : MonoBehaviour  
{
public float moveForce = 3;  
public float minMouseDistance = 50;  
public GameObject bulletPrefab;  
public float bulletForce = 12;  
public float bulletStartOffset = 1.2f;  
public float cooldownTime = 0.5f;  
private Rigidbody2D rigidBody;  
private float shootTimer = 0;  
private void Start(){  
rigidBody = GetComponent<Rigidbody2D>();  
}
private void OnCollisionEnter2D(Collision2D collision){  
if (collision.collider.tag == "Asteroid"){  
Destroy(gameObject);  
}
}
...  
Scripting – 2D Physics Events  
•
Example 10: Shooting and Destroying Asteroids  
...  
private void Update()  
{
float fireInput = Input.GetAxis("Fire1");  
if ((fireInput > 0) && (shootTimer <= 0))  
{
Vector3 mouseDirection = Input.mousePosition –  
Camera.main.WorldToScreenPoint(transform.position);  
GameObject bullet = Instantiate(bulletPrefab, transform.position +  
(mouseDirection.normalized * bulletStartOffset),  
Quaternion.identity);  
bullet.GetComponent<Rigidbody2D>().velocity = mouseDirection.normalized  
bulletForce;  
*
shootTimer = cooldownTime;  
}
if (shootTimer >= 0)  
{
shootTimer -= Time.deltaTime;  
}
}
...  
Scripting – 2D Physics Events  
•
Example 10: Shooting and Destroying Asteroids  
private void FixedUpdate()  
{
float horizontalInput = Input.GetAxis("Horizontal");  
float verticalInput = Input.GetAxis("Vertical");  
Vector2 mouseDirection = Input.mousePosition –  
Camera.main.WorldToScreenPoint(transform.position);  
if (mouseDirection.magnitude > minMouseDistance)  
{
float rotationAngle = Mathf.Atan2(mouseDirection.normalized.y,  
mouseDirection.normalized.x) * Mathf.Rad2Deg;  
rigidBody.SetRotation(rotationAngle - 90);  
}
rigidBody.velocity = (((transform.up * verticalInput) + (transform.right *  
horizontalInput)) * moveForce);  
}
}
Exercise 1  
1
) Create an enemy for a 2D platform game that can only be  
killed by jumping on his head (like some enemies of Super  
Mario games).  
–
Start with the code created for the player jump example.  
–
If the player touches the sides of the enemy, the player dies.  
Enemy  
Enemy  
Kill the enemy  
Player dies  
2
D Joints  
•
•
Joints can be used to attach GameObjects together.  
There are different types of 2D joints:  
–
–
Distance Joint 2D - attaches two GameObjects and keeps them a certain distance apart.  
Fixed Joint 2D - keeps two objects in a position relative to each other, so the objects are  
always offset at a given position and angle.  
–
–
–
Friction Joint 2D - reduces both the linear and angular velocities between two  
GameObjects to zero  
Hinge Joint 2D - allows a GameObject to be attached to a point in space around which it  
can rotate.  
Relative Joint 2D - allows two GameObjects to maintain a position based on each other’s  
location.  
–
–
–
–
Slider Joint 2D - allows a GameObject to slide along a line in space.  
Spring Joint 2D - allows two GameObjects to be attached together by a spring.  
Target Joint 2D - connects to a specified target, rather than another rigid body.  
Wheel Joint 2D - simulates wheels and suspension.  
Distance Joint 2D  
•
Distance Joint 2D – Attaches two GameObjects and keeps  
them a certain distance apart.  
–
Update the Line Renderer positions do show a line:  
private void Update()  
{
Rigidbody2D attachedBall = GetComponent<DistanceJoint2D>().connectedBody;  
LineRenderer line = GetComponent<LineRenderer>();  
line.SetPosition(0, transform.position);  
line.SetPosition(1, attachedBall.transform.position);  
}
Hinge Joint 2D  
•
Hinge Joint 2D - allows a GameObject to be attached to a  
point in space around which it can rotate.  
–
Update the Line Renderer positions do show a line:  
private void Update()  
{
HingeJoint2D hinge = GetComponent<HingeJoint2D>();  
LineRenderer line = GetComponent<LineRenderer>();  
line.SetPosition(0, transform.position);  
line.SetPosition(1, hinge.connectedBody.position);  
}
Spring Joint 2D  
•
Spring Joint 2D - allows two GameObjects to be attached  
together by a spring.  
–
Update the Line Renderer positions do show a line:  
private void Update(){  
SpringJoint2D hinge = GetComponent<SpringJoint2D>();  
if (hinge){  
LineRenderer line = GetComponent<LineRenderer>();  
line.SetPosition(0, transform.position);  
line.SetPosition(1, hinge.connectedBody.position);  
}
else{  
Destroy(GetComponent<LineRenderer>());  
}
}
Further Reading  
•
Unity User Manual, Available at: https://docs.unity3d.com/2020.1/  
Documentation/Manual/  
–
2D  
•
•
•
•
•
•
Gameplay in 2D  
Physics Reference 2D  
Rigidbody 2D  
Collider 2D  
Effectors 2D  
2D Joints  
•
Books  
–
Jeremy G. (2017). Introduction to Game Design, Prototyping, and  
Development: from the Concept to Playable Game - with Unity and C# (2nd  
ed.). Boston, MA: Addison-Wesley Professional. ISBN: 978-0134659862  
–
Hocking, J. (2018). Unity in Action: Multiplatform Game Development in C#  
(2nd ed.). Shelter Island, NY: Manning Publications. ISBN: 978-1617294969