Reputation: 5387
I need an object to move up and down according to a dynamic timing. The exact locations are stored in a List() called Timings. This will contain sorted entries such as 0.90 1.895 2.64 3.98... These timings are relative the playing of music, so they can be compared to TheMusic.time. (TheMusic is my AudioSource).
Right now (see code below), it's moving statically up and down using moveSpeed. How can I make it so that alternatively, the top and bottom point are reached at predefined times? When it reaches the end of the list of timings the movement should stop.
public class Patrol : MonoBehaviour {
public Transform[] patrolPoints; //contains top and bottom position
public float moveSpeed; //needs to be changed dynamically
private int currentPoint;
// Initialization
void Start () {
transform.position = patrolPoints [0].position;
currentPoint = 0;
}
// Update is called once per frame
void Update () {
print (currentPoint);
if (currentPoint >= patrolPoints.Length) {
currentPoint = 0;
}
if (transform.position == patrolPoints [currentPoint].position) {
currentPoint++;
}
transform.position = Vector3.MoveTowards (transform.position, patrolPoints[currentPoint].position, moveSpeed * Time.deltaTime);
}
}
It is important that there is no moving away from the absolute time point. E.g. when Timings reaches a high time such as 1009 there shouldn't be much drift.
Also note that other things (such as changing color and checking user behaviour) need to happen at the same time, see my other question.
Upvotes: 2
Views: 1122
Reputation: 125245
The path to your solution is this answer which shows function to move GameObject over time.
With that function in hand, you can start a coroutine, loop over the List
that contains the beatsTimer
. Inside each loop you should have a variable that determines if you should go up or down after each loop. In my example I named that variable upDownMoveDecider
. This variable will decide which index of the patrolPoints
array to use.(I assume there are only two points with index 0 and 1).
Also, you can call the moveToX
function inside that for
loop each time. Make sure to yield
it so that it will wait for the moveToX
function to finish or return before going to the next function.
Below is what that should look like:
public Transform[] patrolPoints; //contains top and bottom position
List<float> beatsTimer = new List<float>();
public Transform objectToMove;
void Start()
{
//For testing purposes
beatsTimer.Add(0.90f);
beatsTimer.Add(1.895f);
beatsTimer.Add(2.64f);
beatsTimer.Add(3.98f);
//Start the moveobject
StartCoroutine(beginToMove());
}
IEnumerator beginToMove()
{
// 0 = move up, 1 = move down
int upDownMoveDecider = 0;
//Loop through the timers
for (int i = 0; i < beatsTimer.Count; i++)
{
if (upDownMoveDecider == 0)
{
//Move up
Debug.Log("Moving Up with time: " + beatsTimer[i] + " in index: " + i);
//Start Moving and wait here until move is complete(moveToX returns)
yield return StartCoroutine(moveToX(objectToMove, patrolPoints[upDownMoveDecider].position, beatsTimer[i]));
//Change direction to 1 for next move
upDownMoveDecider = 1;
}
else
{
//Move down
Debug.Log("Moving Down with time: " + beatsTimer[i] + " in index: " + i);
//Start Moving and wait here until move is complete(moveToX returns)
yield return StartCoroutine(moveToX(objectToMove, patrolPoints[upDownMoveDecider].position, beatsTimer[i]));
//Change direction to 0 for next move
upDownMoveDecider = 0;
}
}
}
IEnumerator moveToX(Transform fromPosition, Vector3 toPosition, float duration)
{
float counter = 0;
//Get the current position of the object to be moved
Vector3 startPos = fromPosition.position;
while (counter < duration)
{
counter += Time.deltaTime;
fromPosition.position = Vector3.Lerp(startPos, toPosition, counter / duration);
yield return null;
}
}
The code inside that for
loop is long but it is easier to understand. Here is the shorter version with no if/else
statement.
//Loop through the timers
for (int i = 0; i < beatsTimer.Count; i++)
{
//Move up/Down depening on the upDownMoveDecider variable
string upDown = (upDownMoveDecider == 0) ? "Up" : "Down";
Debug.Log("Moving " + upDown + " with time: " + beatsTimer[i] + " in index: " + i);
//Start Moving and wait here until move is complete(moveToX returns)
yield return StartCoroutine(moveToX(objectToMove, patrolPoints[upDownMoveDecider].position, beatsTimer[i]));
//Change direction
upDownMoveDecider = (upDownMoveDecider == 1) ? 0 : 1;
}
Upvotes: 0
Reputation: 16277
Don't reinvent the wheels. Use tween libraries, e.g. iTween. There are more than 20 easing types defined for you:
Example code:
iTween.MoveBy(gameObject,iTween.Hash(
"x" , 2,
"time", 0.2f
));
Upvotes: 0
Reputation: 506
Add a float array lets say public float[] moveSpeedArray;
You can populate this array in Start()
or in editor as you like.
You are already getting your currentPoint
and updating it.
Give that currentPoint
as index of your moveSpeedArray
.
Like;
transform.position = Vector3.MoveTowards (transform.position, patrolPoints[currentPoint].position, moveSpeedArray[currentPoint] * Time.deltaTime);
So like this you can move your object to places in different predefined times.
Hope this helps! Cheers!
Upvotes: 1