using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

public class MoveObjects : MonoBehaviour
    public GameObject[] objectsToMove;
    public float stepsPerSecond = 1f;
    public float speed = 3f;

    private Vector3 trackStart;
    private Vector3 trackEnd;
    private float phase = 0f;

    // Use this for initialization
    public void Init()
        objectsToMove = GameObject.FindGameObjectsWithTag("Stair");
        // Infer the start & end positions of the track 
        // from the position of the first & last steps
        trackStart = objectsToMove[0].transform.position;
        int count = objectsToMove.Length;
        var span = objectsToMove[count - 1].transform.position - trackStart;
        // The track ends one more step distance after the last step.
        // (So the last step has some distance to travel before it wraps)
        trackEnd = trackStart + (count + 1) * span / count;

    // Update is called once per frame
    void Update()
        if (objectsToMove != null && objectsToMove.Length > 0)

    private void MoveRealistic()
        float n = (float)objectsToMove.Length;

        foreach (GameObject step in objectsToMove)
            float step_x = step.transform.position.x;
            float max_x = (n - 1f) * 24f; // The javascript has this "24", which is based on the width of the step + the outline.
            step_x = Mathf.Repeat(step_x + speed * Time.time, max_x);

            float r = 5f;
            float x_for_atan = step_x * r / max_x - r / 2f;
            if (step_x < 3f * 24f)
                x_for_atan = -r / 2f + .5f;
            if (step_x >= max_x - 3f * 24f)
                x_for_atan = r / 2f - .5f;

            float step_y = 180f + 120f * (float)Math.Atan(x_for_atan);

            step.transform.position = new Vector3(step_x, -step_y, 0);
            // negative y because the javascript uses top, which starts at 0
            // at the top, and positive goes down. Unity goes the other direction.

    private void MoveRegular()
        float divisor = 1f / objectsToMove.Length;

        // Compute the current phase of the escalator, 
        // from 0 (1st step at track start) to 1 (1st step at track end)
        phase = Mathf.Repeat(phase + stepsPerSecond * divisor * Time.deltaTime, 1f);

        // Place each step a proportional distance along the track.
        for (int i = 0; i < objectsToMove.Length; i++)
            float t = Mathf.Repeat(phase + i * divisor, 1f);
            objectsToMove[i].transform.position = Vector3.Lerp(trackStart, trackEnd, t);

Whne I'm using the MoveRealistic I'm using a break point on the line:

step_x = Mathf.Repeat(step_x + speed * Time.time, max_x);

I see that speed value is 3 and max_x value is 216. The only value that change is the step_x what make the speed to change to very very high. And I want a static speed(3).

Another problem is that each time one object(step) is moving when he finished moving the next one move. But I want to create a escalator stairs effect using this method and the objects should move all the same time like it is in this jsfiddle: And this is where I have take the code from and converted it to unity csharp:


Last problem is that the objects the step's(stairs) moving in other position/s and not on their original position/s.

This is the steps/stairs original position. And where they should move.


And this is where they are moving when using the MoveRealistic method:


When using the MoveRegular method they are moving fine but I want to be able to use also the MoveRealistic method like in the jsfiddle.

  • 1
    \$\begingroup\$ You might find asking about your actual goal "how can I animate an escalator?" is clearer than "How can I keep the same speed to be static speed and how to move the objects all at the same time?" \$\endgroup\$ – DMGregory Nov 18 '18 at 15:50

As I mentioned in my previous answer, if you want to get a curve at the top and bottom of your escalator, I'd recommend using an AnimationCurve. That way you can precisely control the shape you want.

Here's a modified example using an animation curve instead of a Lerp to space out the steps.

Animated gif of alternating white & red cubes descending like steps of an escalatorSame animation, from a 3/4 view instead of side-on

public class Escalator : MonoBehaviour {

    public Transform[] steps;
    public AnimationCurve curve;
    public float stepsPerSecond = 1f;

    Vector3 trackStart;
    Vector3 horizontalTravel;
    float verticalTravel;
    float divisor;

    float phase = 0f;      

    void Start() {
        trackStart = steps[0].position;
        int count = steps.Length;
        var span = steps[count - 1].position - trackStart;

        divisor = 1f / count;
        horizontalTravel = (count + 1) * span * divisor;
        horizontalTravel.y = 0f;

        verticalTravel = span.y;

    void Update() {
        phase = Mathf.Repeat(phase + stepsPerSecond * divisor * Time.deltaTime, 1f);

        for (int i = 0; i < steps.Length; i++) {
            float t = Mathf.Repeat(phase + i * divisor, 1f);
            // Get the height of the curve at this step.
            float curveHeight = curve.Evaluate(t) * verticalTravel;

            steps[i].position = trackStart                // First step
                              + horizontalTravel * t      // evenly spaced horizontal
                              + curveHeight * Vector3.up; // curving vertical

This assumes your animation curve runs from 0 to 1 on the horizontal, and 0 to 1 on the vertical. (It works for "down" escalators too - it takes its direction from the offset between the first and the last step, so you don't need to change the curve itself)

Here's an example of how I set up my curve:

Screenshot of curve editor in Unity

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.