How Do You Make a Moving Platform in Unity?
A major part of 2D and 3D platform games is… you guessed it: platforms. Movement allows for variety in level design and can present extra challenges during gameplay.
You can make a moving platform in Unity by using the MoveTowards() function and have it go to several transform positions. You can also use Mathf.PingPong to make a platform move from one position to another. Use a trigger collider for logic to keep a player on a platform while it’s moving.
Setting Up a Moving Platform
You will need a gameobject to act as a platform. In this example, we have a cube that was scaled by the following: X = 4, Y = .5, and Z = 4. We also have a cube that is able to move on the X and Z axes and jump up the Y axis. Give the platform a rigidbody component and uncheck the ‘Use Gravity’ box. Also, check the ‘Is Kinematic’ checkbox. Otherwise, it would react to the weight of an object on top of it.
The platform will be moving back and forth along the X axis continuously at a fixed speed. This is a very simple platform example and makes a great basis for how to create more advanced behavior.
In order to have the platform move between two points, we will use two empty gameobjects with only transform data, no colliders or meshes. We only need position data, so we will use the Transform’s position data for that.
In this example, we will name one of the empty gameobjects Point1 and the other Point2. The platform will first move to Point1, then Point2. Point1’s position will be X = -8, Y = 3, and Z = 0. Point2’s position will be X = 8, Y = 3, and Z = 0.
Create a C# script, and attach it to the platform. Let’s begin writing the movement logic.
Creating Logic for a Moving Platform
public class Platform : MonoBehaviour
{
[SerializeField]
private Transform position1, position2;
private float _speed = 3.0f;
private bool _switch = false;
[SerializeField] – This allows the variable declared below or to the right of it to be seen in the Inspector, even if the variable is private. You can then edit the variable in the Inspector.
private Transform position1, position2; – In the first part of this example, we will make the platform move back and forth between two positions. These two variables, each hold an empty gameobject’s location data. This will allow us to reference the data and use it as two positions for the platform to move toward. Once you have typed this out save your script, and check the Unity editor and the platform gameobject’s inspector. In the script component, you will see there is a spot for 2 Transforms to be placed. Drag the Point1 object into position1 and Point2 object into position2.
private float _speed = 3.0f; – This line creates a private float variable named _speed and initializes its value to 3. This variable will be used for the speed of the platform.
private bool _switch = false; – This line creates a private boolean variable named _switching and sets its value to false. This variable is important to the logic of which direction the platform will move once it is in the same position as Point1 or Point2. The _switch variable’s value starts as false. You will see in the code to come what happens when the value is either true or false.
void FixedUpdate()
{
if(_switch == false)
{
transform.position = Vector3.MoveTowards(transform.position, position1.position,
_speed * Time.deltaTime);
}
else if (_switch == true)
{
transform.position = Vector3.MoveTowards(transform.position, position2.position,
_speed * Time.deltaTime);
}
if(transform.position == position1.position)
{
_switch = true;
}
else if(transform.position == position2.position)
{
_switch = false;
}
}
The Update() function is where we make the movement happen. The logic is fairly basic, so you should be able to easily understand it. In this case, however, we will use FixedUpdate().
FixedUpdate() in Unity is called after a specific amount of time, every .02 seconds by default. It runs at the same frequency of the physics system and is mainly used for physics calculations.
FixedUpdate() is not needed for the movement of the platform. However, if you want a player or other gameobject to be able to jump onto and stay on a platform, you should use it to avoid glitchy behavior.
if(_switch == false) – We start with an if() statement that will check if the _switch variable is set to false. Remember, _switch is set to false as soon as the game is run. So the code after this if() statement will be run.
transform.position = Vector3.MoveTowards(transform.position, position1.position, _speed * Time.deltaTime); – This statement sets the platform’s position to the value of a function. This function is part of the Vector3 structure, which has functions to calculate specific vector math.
Vector3.MoveTowards() is a function that calculates a position between a start and end position. It will then move an object towards the end position by the speed specified in the code. The parameter transform.position is the current position of the platform.
The second parameter, position1.position is the end position that the platform will be moving towards. The third parameter, _speed, is the value of units the platform will travel during one call of update. This is multiplied by Time.deltaTime. If it wasn’t, it would be ridiculously fast.
else if (_switch == true) – Next, we use an else if() statement to check if another condition is true. This will run if the condition before it was false. This specific statement checks if _switch’s value is true. If it is, the code below will execute.
transform.position = Vector3.MoveTowards(transform.position, position2.position, _speed * Time.deltaTime); – Again, this statement uses Vector3.MoveTowards() to move the platform towards the position in the second parameter. The second parameter happens to be the position of our other empty gameobject, position2.
if(transform.position == position1.position) – Next, we need to make sure that after the platform gets to a position it doesn’t just stop. Without any more code, it would just stay at that position forever. So now, we are checking if the position is the same position as our gameobject at position1. If it is, the code below will execute.
_switch = true; – If the platform is at position1, the _switch is set to true. Remember what happens when it is set to true? It uses MoveTowards() to head over to position2.
else if(transform.position == position2.position) – There is one last else if() statement. We are checking if the platform is at position2 this time. If it is, the code below executes.
_switch = false; – This statement sets _switch’s value to false. Once that happens, it will use MoveTowards() to make the platform move towards position1. The movement logic is now complete. This creates an endless loop of the platform moving back and forth in between position1 and position2.
How Do I Move a Player with The Moving Platform in Unity?
If you’ve tried to put another object on the moving platform, such as a player, you may have noticed that it doesn’t work. The platform just leaves the other object behind. How do we keep the platform and the other object together?
To move a player while on a platform, add a trigger collider component to the platform and move the center up a small amount, and give the player the tag ‘Player.’ In the OnTriggerEnter() function, check if an object with the Player tag is on the platform, and parent that object to the platform.
In this example, I will use a cube as my player. Set the tag of the player gameobject to ‘Player.’ We will use this for when the player’s collider component touches the platform’s collider.
We also need to edit the platform a bit. We need a way to for Unity to know that the player is on the platform so that we can make the player stay on the platform while it is using. We will add another collider to the platform for this. This collider will be a trigger. We want the player to stay on the platform when it enters the trigger collider, so we will move the trigger collider up a little to make sure the player has entered it.
Next, we need to write the code that will execute when the player collides with the trigger collider, and when they exit the trigger collider. Remember, an object can move through a trigger collider so it will not affect how the player stands on the original collider of the platform. This next code is part of the platform’s script.
private void OnTriggerEnter(Collider other)
{
if(other.CompareTag("Player"))
{
other.transform.parent = this.transform;
}
}
private void OnTriggerEnter(Collider other) – This is the function that executes logic when another object with a collider component collides with and enters the trigger collider’s boundaries. You can see that that the parameter it takes in is type Collider. This is the base class of all colliders. We use the information stored in the Collider class to find information about the collider that entered the platform’s collider.
if(other.CompareTag(“Player”)) – Remember that we tagged our Player object as ‘Player.’ Now, this if() statement uses the CompareTag() function that checks if an object’s tag is the one in the CompareTag() function’s parameter, which is a string. If it is, then the code within the if() statement executes.
other.transform.parent = this.transform; – This statement uses the parameter from the OnTriggerEnter() function named ‘other.’ Remember, ‘other’ is of type Collider which tells us information about the object’s collider that entered the platform’s trigger collider. In this case, it is the Player’s collider. Other.transform.parent accesses the Player’s transform’s parent property.
Then ‘= this.transform’ sets the Player’s parent to the platform. The keyword ‘this’ refers to the gameobject that the script is attached to. In this case, it is the platform gameobject. So the platform gameobject is the parent of our player. This is only when the player is inside the boundaries of the trigger collider. Being the child of the platform, the player automatically moves with the platform.
Even though the player’s parent is the platform, it can still move around. It will just be affected by the platform’s movement. That means that the player leave the trigger collider’s boundaries. Check out the code below to see what will then happen.
private void OnTriggerExit(Collider other)
{
if (other.CompareTag("Player"))
{
other.transform.parent = null;
}
}
private void OnTriggerExit(Collider other) – This function is similar to the one above, but this time this executes code when a collider leaves the trigger collider. So if the player leaves the trigger collider’s boundaries, the code within this function will execute.
if (other.CompareTag(“Player”)) – Again, we use an if() statement to check if the gameobject that is leaving the boundaries of trigger collider has the ‘Player’ tag. If it does, then the code within the if() statement executes.
other.transform.parent = null; – This statement accesses the collider information of the collider that is leaving the trigger collider’s boundaries. The ‘= null’ sets the value of the parent to null or nothing. At this point, the Player no longer has a parent. Thus, the Platform’s movement will no longer affect the player’s movement. The Player is free.
This is all the code you will need to allow the player to stay on the platform as it is moving. You’re done.
Another Way to Move a Platform: Mathf.PingPong
The beauty about coding is that there are usually several solutions to a problem. Mathf.PingPong is used to continuously move back and forth by a specific value. For example, if you used a value of 5 as its parameter, an object would start at 0 and go 5 units greater on the axis. However, if use 10 as the length of units to travel and you add a -5 as the minimum value, the platform will travel 10 units, from -5 to 5 and back again.
public class PlatformPiPo : MonoBehaviour
{
[
SerializeField] private float _speed = 5.0f;
void Update()
{
transform.position = new Vector3(Mathf.PingPong(Time.time * _speed, 10) -5,
transform.position.y, transform.position.z);
}
You probably noticed that there is much less code here than when we used MoveTowards() and if() statements for our platform’s movement logic. This is basically one statement.
[SerializeField] private float _speed = 5.0f; – This statement creates a float variable and sets its value to 5. The [SerializeField] allows the variable to be viewed and manipulated in the Inspector.
transform.position = new Vector3(Mathf.PingPong(Time.time * _speed, 10) -5, transform.position.y, transform.position.z); – In this statement we are setting a new Vector3 to transform.position. In the X value of the Vector3, we use Mathf.PingPong().
The first parameter is Time.time and is the time at the beginning of a frame. This is basically a counter for the function and is multiplied by a speed to make the platform move. Time.time increments its values automatically.
The next parameter, 10, tells the function how many units it will travel total from side to side. The -5 shows minimum valley that the platform will travel along the X axis. So in this example, the platform will start at X = -5, move to X = 5, and continuously go back and for between those X values.
Use the same method of having trigger collider to keep the player on the platform while moving.
Wrapping Up
As you can see, there are several ways you can move platforms in Unity. There are actually more. One way is to us an Animation. This will be discussed in another post. You can do more complex movement fairly easily so it is pretty fun. Using MoveTowards() and PingPong() are also simple ways to get platforms moving really quickly.
Remember to keep a player on the platform while it is moving. This can be done easily with a trigger collider. Experiment and have fun. Moving platforms can add much depth to level design.