Saturday, March 10, 2018

unity - How can I move objects in a cyclic loop?


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 objectstomove = new List();
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);
}
}
}

}

Answer



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.


No comments:

Post a Comment

Simple past, Present perfect Past perfect

Can you tell me which form of the following sentences is the correct one please? Imagine two friends discussing the gym... I was in a good s...