0
\$\begingroup\$

I have number of objects I want to move them up and forward then when the last one each time in the array get to the end position move this object to the start of the array and to the start position the original start position of the first object.

The idea is to make the objects cyclic on place. Not to move all the objects but to cyclic them up and forward.

I tried this but it's totally wrong. It's moving all the objects as a group to another place and the last one return to the first position big mess.

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

public class MoveObjects : MonoBehaviour
{
    public float speed = 1f;

    private Vector3[] startPos;
    private Vector3[] endPos;
    private Vector3[] currentPos;
    private GameObject[] objectstoMove;

    // Use this for initialization
    public void Init()
    {
        objectstoMove = GameObject.FindGameObjectsWithTag("Stair");
        startPos = new Vector3[objectstoMove.Length];
        endPos = new Vector3[objectstoMove.Length];
        currentPos = new Vector3[objectstoMove.Length];

        for(int i = 0; i < objectstoMove.Length; i++)
        {
            startPos[i] = objectstoMove[i].transform.position;
            endPos[i] = new Vector3(objectstoMove[i].transform.position.x + 50, objectstoMove[i].transform.position.y + 50, 0);
        }
    }

    // Update is called once per frame
    void Update()
    {
        if (objectstoMove != null)
        {
            for(int i = 0; i < objectstoMove.Length; i++)
            {
                currentPos[i] = objectstoMove[i].transform.position;
                objectstoMove[i].transform.Translate(1, 1, speed * Time.deltaTime);

                if(currentPos[i].x >= endPos[i].x && currentPos[i].y >= endPos[i].y)
                {
                    SetTransform(objectstoMove[objectstoMove.Length-1]);
                }
            }
        }
    }

    void SetTransform(GameObject n)
    {
        n.transform.position = startPos[0];
    }
}

Example screenshot:

Cubes

Each cube should move up and forward following the one above it. The top one when it's reaching to the end position it should move back to the first cube start position. Then the next top cube when reaching the end position it should move to the original first cube start position !

The idea is to simulate some kind of stairs escalator. So the cubes should move in cyclic. The whole cubes not should change position but they should cyclic.

I tried also this for testing: But not working at all.

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

public class MovingTest : MonoBehaviour
{
    public List<Transform> objectstomove = new List<Transform>();
    public float speed = 1;
    public Vector3 position1;
    public Vector3 position2 = new Vector3(2, 2, 2);

    private Transform lastobj;

    // Use this for initialization
    void Start ()
    {
        position1 = objectstomove[0].position;
        lastobj = objectstomove[objectstomove.Count - 1];
    }

    // Update is called once per frame
    void Update ()
    {


        for (int i = 0; i < objectstomove.Count; i ++)
        {
            objectstomove[i].position = Vector3.MoveTowards(objectstomove[i].position,
                                                 position2, speed * Time.deltaTime);
        }

        if (lastobj.position.x == 2)
        {

            lastobj.position = position1;
            objectstomove.Remove(lastobj);
            objectstomove.Insert(0, lastobj);
            lastobj = objectstomove[objectstomove.Count - 1];

            for (int i = 0; i < objectstomove.Count; i++)
            {
                objectstomove[i].position = Vector3.MoveTowards(objectstomove[i].position,
                                                     position2, speed * Time.deltaTime);
            }
        }
    }
}
\$\endgroup\$

1 Answer 1

0
\$\begingroup\$

I'd approach this by thinking of the hypothetical track the steps are sliding along.

It has a start and an endpoint, and each step takes its respective position in line between the two.

For a simple straight line track, we can use a Lerp to find the corresponding spot on the line. If you want to use a more realistic escalator track, with a short flat section at the top and bottom curving to a slope in between, you can sample an AnimationCurve instead.

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

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

void Start() {
    // Infer the start & end positions of the track 
    // from the position of the first & last steps
    trackStart = steps[0].position;
    int count = steps.Length;
    var span = steps[count - 1].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;
}

void Update() {
    float divisor = 1f / steps.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 < steps.Length; i++) {
        float t = Mathf.Repeat(phase + i * divisor, 1f);
        steps[i].position = Vector3.Lerp(trackStart, trackEnd, t);        
    }
}

Note that if you want to use this escalator to push physics objects, you might instead want to (in FixedUpdate) treat this calculated position as a target, then compute a velocity to reach that target, and apply it to the step's RigidBody. This gives the collision solver more to work with, since instead of the steps teleporting every frame they're pushing with a specific momentum that they can transfer to objects riding on top of them. You'll find you get less jittering and tunneling this way, though it will be possible to nudge the steps slightly out-of-track with enough force.

\$\endgroup\$
5
  • \$\begingroup\$ It's working good when I'm generating for example 10 stairs(Cubes). Then it's simulating the escalator effect fine. The stairs look like moving up smooth. But then I tried for testing to generate 300 stairs this time it was looks like they are moving down and they were all also stuttering. What could be the reason that on large amount of stairs it's acting like that ? \$\endgroup\$
    – Daniel Lip
    Nov 17, 2018 at 20:23
  • \$\begingroup\$ Could be a temporal aliasing effect, like the Wagon Wheel Effect: when the movement of a regular pattern is undersampled, it can look jerky, inconsistent, or like it's moving in the wrong direction. Reducing your movement speed (steps per second) can help. In fact, it looks like my calculation of steps per second isn't correctly dividing by the number of steps. Fixing that now.... \$\endgroup\$
    – DMGregory
    Nov 17, 2018 at 20:37
  • \$\begingroup\$ Getting exception in the editor on the line: objectsToMove[i].transform.position = Vector3.Lerp(trackStart, trackEnd, t); transform.position assign attempt for 'Cube(Clone)' is not valid. Input position is { NaN, NaN, NaN }. \$\endgroup\$
    – Daniel Lip
    Nov 17, 2018 at 20:44
  • \$\begingroup\$ Then I trust you will debug this to determine where your calculation is producing a value of NaN. \$\endgroup\$
    – DMGregory
    Nov 17, 2018 at 20:54
  • \$\begingroup\$ Found the problem. I had to add a check if objectstoMove(My array instead steps) is Length large then 0. Instead only checking if (objectstoMove != null) then: if (objectsToMove != null && objectsToMove.Length > 0) and now it's working. Thanks. \$\endgroup\$
    – Daniel Lip
    Nov 17, 2018 at 21:03

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .