Reputation: 2724
I'm trying to make a target lerp between two objects based on a timer.
At the moment, I have the following code:
float distCovered = (Time.time - waitTime) * speed;
float fracJourney = distCovered / journeyLength;
if (_moveDown == false)
{
if (startTime + waitTime < Time.time)
{
transform.position = Vector3.Lerp(start.position, end.position, fracJourney);
if (transform.position == end.position)
{
Debug.Log("going down");
_moveDown = true;
transform.position = Vector3.Lerp(end.position, start.position, fracJourney);
}
}
}
if (_moveDown == true)
{
float distCovered1 = (Time.time - goDowntimer) * speed;
float fracJourney1 = distCovered1 / journeyLength;
transform.position = Vector3.Lerp(end.position, start.position, fracJourney1);
if (transform.position == start.position)
{
Debug.Log("going up");
// waitTime = 20;
_moveDown = false;
}
}
This code is in my update function and is attached to each of my objects that I want to move up and down. Each object is able to set their wait time independently of the others, thus i can have 1 move after 5 seconds, another after 10 etc.
Then, each target waits a few seconds and moves back down. However, the movement isn't smooth and it tends to jump a set distance. But then, when it gets back to the bottom it goes crazy between the _movedown bool and wont move.
Does anyone know of a way I can fix these issues?
I do know of the Mathf.PingPong method that constantly moves the object back forth between two points, but that wont allow me to pause the movement at each section. Though, if someone knows a way I can do this, please let me know as well.
Upvotes: 0
Views: 2141
Reputation: 4056
Here is a quick hack at the code. It could probably be cleaner but it should do in a pinch. I've replaced the OPs if/then blocks w/ a 'direction' variable that indicates whether we are moving from start to end or end to start.
Vector3.Lerp() takes a t value in the range [0,1], notionally a % distance from start to end point. If you want to reverse that direction, all you need to do is subtract from 1 so that the range becomes [1,0] (reverse direction). That's all I'm doing with direction_ below. As soon as fracJourney is out of range, we switch directions, trigger a pause, and reset the main timer.
I put the pause code in Update() to separate it from the movement code but there isn't any reason both code blocks couldn't be in either FixedUpdate() or Update().
This example is a modified version of the one in the Vector3.Lerp documentation:
// additional data members beyond Vector3.Lerp's documentation
public float PauseTime = 2.0f;
int direction_ = 1;
bool doPause_ = false;
void Update(){
float elapsedTime = Time.time - startTime;
// if the elapsed time has exceeded the pause time and we're paused
// unpause and reset the startTime;
if(elapsedTime > PauseTime && doPause_){
doPause_ = false;
startTime = Time.time;
}
}
void FixedUpdate(){
if(doPause_)return;
float distCovered = (Time.time - startTime) * Speed;
float fracJourney = distCovered / journeyLength;
// +direction means we are going from [0,1], -direction means [1,0]
fracJourney = (direction_>0)?fracJourney:1.0f-fracJourney;
transform.position = Vector3.Lerp(StartPt.position, EndPt.position, fracJourney);
// When fracJourney is not in [0,1], flip direction and pause
if(fracJourney > 1.0 || fracJourney < 0.0){
direction_ = -direction_;
startTime = Time.time;
doPause_ = true;
}
}
My 'direction' member could just as easily have been a bool, but I like having a signed direction for other purposes.
Upvotes: 1
Reputation: 2381
Try this :
transform.position = Vector3.Lerp(start.position, end.position, fracJourney * Time.deltaTime);
Or possibly even this:
transform.position = Vector3.Lerp(start.position, end.position, speed * Time.deltaTime);
x *Time.deltaTime is such cases basically instructs the movement method to move the object by x meters per second. Without deltaTime, it's performing these movements at x meters per frame instead.
Upvotes: 0
Reputation: 11759
I've added some comments below that may help you clarify what you're intending.
float distCovered = (Time.time - waitTime) * speed;
float fracJourney = distCovered / journeyLength;
// Going up...
if (_moveDown == false)
{
// Should we be checking this in the other half of the statement too?
// Or, outside the conditional altogether?
if (startTime + waitTime < Time.time)
{
transform.position = Vector3.Lerp(start.position, end.position, fracJourney);
if (transform.position == end.position)
{
Debug.Log("going down");
// The way this is structured, we're going to *immediately* fall into the
// following block, even if that's not your intended behavior.
_moveDown = true;
// Going down, but with the fracJourney value as though we were going up?
transform.position = Vector3.Lerp(end.position, start.position, fracJourney);
}
}
}
// As noted above, we're going to fall directly into this block on the current pass,
// since there's no *else* to differentiate them.
if (_moveDown == true)
{
// Doesn't follow the same pattern as in the previous block, though that may be intended
float distCovered1 = (Time.time - goDowntimer) * speed;
float fracJourney1 = distCovered1 / journeyLength;
transform.position = Vector3.Lerp(end.position, start.position, fracJourney1);
if (transform.position == start.position)
{
Debug.Log("going up");
// waitTime = 20;
_moveDown = false;
// Should there be a Lerp here, as above, to start heading back the other way again? Or, do you need to remove the other one?
}
}
Upvotes: 0