Moving Platforms

The MovingObject2D component is a very simple system for moving platforms (or any object) back and forth between two points. Its main purpose is just to demonstrate the way the Character Physics interacts with moving platforms, but in a real game you would likely want to find or make a more powerful system with features like following multiple points in a path, curved paths, and variable speeds.

The script is set to update very early so that it moves before other objects do anything based on its position or velocity:

[DefaultExecutionOrder(DefaultExecutionOrder)]
public sealed class MovingObject2D : MonoBehaviour
{
    public const int DefaultExecutionOrder = -10000;

The fields have tooltips explaining what they do, Units Attributes where appropriate, and an OnValidate method to automatically find the _Rigidbody if it's missing and prevent the _Speed from being set to a negative value:

    [SerializeField]
    [Tooltip("The object to move")]
    private Rigidbody2D _Rigidbody;

    [SerializeField]
    [Tooltip("The destination to move to (relative to the starting position)")]
    private Vector2 _Movement;

    [SerializeField, MetersPerSecond]
    [Tooltip("The speed at which the object moves")]
    private float _Speed = 3;

    [SerializeField]
    [Tooltip("Should it keep moving back and forth between the start and end?")]
    private bool _Loop = true;

#if UNITY_EDITOR
    private void OnValidate()
    {
        gameObject.GetComponentInParentOrChildren(ref _Rigidbody);
        PlatformerUtilities.NotNegative(ref _Speed);
    }
#endif

On startup, it stores its current position as the start point:

    private Vector2 _StartingPosition;

    private void Awake()
    {
        _StartingPosition = _Rigidbody.position;
    }

In FixedUpdate it calculates its destination based on the _StartingPosition and adds the _Movement if it is currently _Returning:

    private bool _Return;

    private void FixedUpdate()
    {
        var movement = _Speed * Time.deltaTime;
        var startingPosition = _Rigidbody.position;
        var position = startingPosition;

        Move:

        var destination = _StartingPosition;
        if (!_Return)
            destination += _Movement;

Then it calculates how far it has to go to reach that destination:

        var offset = destination - position;
        var distance = offset.magnitude;

If the remaining distance is still larger than the movement this frame, add it to the current position:

        if (distance > movement)// Still going.
        {
            position += offset * movement / distance;
            
            _Rigidbody.velocity = (position - startingPosition) / Time.deltaTime;
            _Rigidbody.MovePosition(position);
        }

Otherwise, it will reach the destination this frame so if _Loop is enabled, subtract the remaining distance from the amount left to move this frame then go back up to the Move: label near the start of the method to continue the rest of this frame's movement back the other way:

        else if (_Loop)
        {
            position = destination;
            movement -= distance;
            _Return = !_Return;
            goto Move;
        }

Otherwise just snap to the destination and stop moving:

        else
        {
            _Rigidbody.velocity = default;
            _Rigidbody.MovePosition(destination);
            enabled = false;
            return;
        }

Gizmos

The script also has an OnDrawGizmos method which draws some lines in the Scene view to help visualise where the _Movement will actually end up.

#if UNITY_EDITOR
    private void OnDrawGizmos()
    {
        var collider = GetComponent<Collider2D>();
        if (collider == null)
        {
            var start = UnityEditor.EditorApplication.isPlaying ? (Vector3)_StartingPosition : transform.position;

            Gizmos.DrawLine(start, start + (Vector3)_Movement);
            return;
        }

        var bounds = collider.bounds;
        var center = UnityEditor.EditorApplication.isPlaying ? (Vector3)_StartingPosition : bounds.center;
        var extents = bounds.extents;

        var corner = extents;
        Gizmos.DrawLine(center + corner, center + corner + (Vector3)_Movement);

        corner.y = -corner.y;
        Gizmos.DrawLine(center + corner, center + corner + (Vector3)_Movement);

        corner.x = -corner.x;
        Gizmos.DrawLine(center + corner, center + corner + (Vector3)_Movement);

        corner.y = -corner.y;
        Gizmos.DrawLine(center + corner, center + corner + (Vector3)_Movement);
    }
#endif
}