Contents
- Overview
- Transform Manipulation
- Rigidbody Manipulation
- Bonus Content: Frame vs Physics Frame
- References
One of the ways you can influence the objects in a game is by moving them. This is usually done in scripts attached to objects. Movement is seen throughout games such as a moving player character, fired bullets from a gun, etc. We’ve seen a few examples of movement already, but let’s dive into some details.
Overview
We usually use one of the following two approaches to move an object
- By changing position (
Transform
manipulation) - By adding force or changing velocity (
Rigidbody
Manipulation)
The following examples are based on Unity
. Implementation in other engines is more or less the same and follows the same priniciples.
Transform Manipulation
Movement of an object by using its Transform
involves directly changing the position of the object. The position can be changed in code in response to events like the push of a button. Consider the following examples
- Changing the position by some vector each time
Space
is pressed
void Update() { // Check if Space button is Just Pressed down if(Input.GetKeyDown(KeyCode.Space)) { // transform.position is a Vector3 and gives the object's position transform.position += Vector3(0, 0, 10); } }
- Changing the position when
Space
is held
// Constants float velocity = 5.0f; Vector3 moveDirection = Vector3(0, 0, 10); void Update() { // Checks if the space button is held down if(Input.GetKey(KeyCode.Space)) { transform.position += moveDirection * veclocity; } }
- Constantly changing the position
float velocity = 5.0f; Vector3 moveDirection = Vector3(0,0,10); void Update() { // Statement is not inside any if statement so this is executed every frame transform.position += moveDirection * veclocity; }
Note: Movement by manipulation of the Transform
component is done in cases where collisions are not enabled. For example, objects revolving around other objects.
Rigidbody Manipulation
We could also leverage the physics system to make our objects move. This involves either applying a new force or changing the object’s velocity.
The Velocity Approach
This is done in cases such as player movement and moving vehicles. We can manually change the velocity of an object a tiny bit per frame to apply some acceleration.
// See the bonus content for the difference between Update and FixedUpdate void FixedUpdate() { Vector3 acceleration = Vector3(0, 0, 1); if(Input.GetKey(KeyCode.W)) { rigidbody.velocity += acceleration; } }
There’s a slight problem here though. The Update()
is called each frame, and therefore, the acceleration applied is actually 1 m/s/frame, and not 1 m/s2 like we’d expect. At this point we need to establish what units we’ll use. It’s much more convenient to use SI units everywhere, considering that calculating change-per-frame is as easy as
Change per frame = Acceleration in m/s2 * Time duration of the frame in seconds
Most game engines will provide a deltaTime
variable to track the time duration of the last frame, which we can use as an approximation to the duration of the current frame. The fixed code in SI units therefore looks like this
rigidbody.velocity += acceleration * Time.deltaTime; // acceleration can be defined in SI units now
There is a slightly more subtle problem here than just the units, which is described in the bonus content below.
The Force Approach
This is done in cases such as jumping or firing projectiles. We apply an impulse and let the physics system handle the rest.
- Adding force when
Space
is pressed
Vector3 forceVector = Vector3(0, 1, 0); void FixedUpdate() { if(Input.GetKey(KeyCode.Space)) { // Applies impulsive force given by the first argument rigidbody.AddForce(forceVector, ForceMode.Impulse); } }
- Add gravitation force constantly
void FixedUpdate() { // Applies acceleration force rigidbody.AddForce(Vector3(0, -9.81, 0), ForceMode.Acceleration); }
Note: Movement by manipulation of Rigidbody
component is done in cases where collisions or physics are needed. For example, a player jump.
Bonus Content: Frame vs Physics Frame
Game Engines have a concept of game loops which might have different implementations. Unity is one such engine. In the above cases of Transform
and Rigidbody
manipulation we
used 2 different functions
FixedUpdate
is for the loop that handles physics calculations. The duration of a frame here is fixed. For example, this function is guaranteed to be called 60 times per secondUpdate
is for loops that handle everything else, like common game logic, AI etc. Duration of a frame is not fixed and may fluctuate.
Does that mean the deltaTime
variable has a different meaning based on the context? Let’s see.
DeltaTime vs FixedDeltaTime
In these examples the change in position and velocity happens every Update
or FixedUpdate
call. Thus the change is frame
dependent. One example may be of changing position of a player.
float moveSpeed = 5.0f; void Update() { // GetMoveDirection returns a unit vector in the direction to move in based on some inputs Vector3 moveDir = GetMoveDirection(); transform.position += moveDir * moveSpeed; } // OR float acceleration = 2.5f; void FixedUpdate() { Vector3 moveDir = GetMoveDirection(); rigidbody.velocity =+ moveDir * acceleration; }
These frame calls depend on the hardware of the user: different frame rates will lead to different behaviour for different users. For a uniform behaviour, we need to make these changes time dependent. This is where deltaTime
is used.
deltaTime
is the time gap between successiveUpdate
calls.fixedDeltaTime
is the time gap between successiveFixedUpdate
calls.
We can multiply these changes by deltaTime
and fixedDeltaTime
to make the changes dependent on the time gap between function calls leading to a uniform experience.
// Update() transform.position += moveDir * moveSpeed * Time.deltaTime; // multiply deltaTime // OR FixedUpdate() velocity += moveDir * acceleration * Time.fixedDeltaTime; // multiply fixedDeltaTime
The above examples are the most general forms of movement you can see in a game.