I’ve read several forums and tutorials but couldn’t find a proper method…
Here’s my example: I need to move an object named ‘obj’ to the x=10 y=10 z=10 point in 5 seconds.
Can anyone show me a simple code for it?
I’ve read several forums and tutorials but couldn’t find a proper method…
Here’s my example: I need to move an object named ‘obj’ to the x=10 y=10 z=10 point in 5 seconds.
Can anyone show me a simple code for it?
First you need to caclulate the velocity of the object. Substract the target position with the object position to get the direction. Divide the respetive axes of this result with the desired time of arrival.
For instance lets say your object is at position (2, 2, 2).
The velocity would be (10, 10, 10) - (2, 2, 2); Divided with the time (8 / 5, 8 / 5, 8 / 5) = (1.6, 1.6, 1.6).
So now, every frame you add the velocity multiplied with delta time and time scale to the object’s position.
private Vector3 targetPosition, velocity;
public void SetTargetPosition(Vector3 position, float travelTime)
{
targetPosition = position;
velocity = new Vector3(transform.position.x - targetPosition.x, transform.position.y - targetPosition.y, transform.position.z - targetPosition.z);
velocity /= travelTime;
}
private void Update()
{
transform.position += velocity * Time.deltaTime * Time.timeScale;
if (targetPosition is reached) // See below
velocity = Vector3.zero;
}
Careful when checking if the target position has been reached, a simple equality call (== operator for example) is not reliable. Frame drops and floating point errors will let the arrival of the object go unnoticed. Rather you should check if the object position is higher or lower than the target one and adjust it if this applies.
You could use a tweening engine to make it simple on yourself. This would depend on the nature of what you are moving and how many movements you’ll need. (if its one movement, adding a tween engine to your project might be overkill)
Vector3.MoveTowards is probably the easiest one.
MoveTowards(a, b, distance) moves the position a towards the position b, but no further than distance. The great thing about using it instead of manually moving is that you won’t have to worry about overshooting. So this:
void Update() {
transform.position = Vector3.MoveTowards(transform.position, destination, Time.deltaTime * 3f);
}
moves the object from the starting position to destination in 1/3d of a second.
To move in exactly 5 seconds, simply calculate the distance to the destination when you start moving, and move 1/5th of that each second:
public Vector3 destination;
private float requiredSpeed;
void Start() {
requiredSpeed = Vector3.Distance(position, destination) / 5f;
}
void Update() {
transform.position = Vector3.MoveTowards(transform.position, destination, Time.deltaTime * requiredSpeed);
}
Why not just a simple lerp? Here is one example.
IEnumerator Move (){
Vector3 startPosition = transform.position;
Vector3 endPosition = new Vector3(10,10,10);
float timer = 0;
while (timer < 5){
transform.position = Vetcor3.Lerp(startPosition, endPosition, timer/5);
timer += Time.deltaTime;
yield return null;
}
}
I’d explicitly set the position to the destination after that loop in the event that deltaTime takes you from below 5 to over 5 in a single frame.
@Kiwasi Lerps are moving the object with varying speed, which is as far as the post above implies not what the poster wants.
The loop is fine, since it exits only when the timer >= 5, the interpolation parameter will be >= 1, so the position will be interpolated to endPosition on the last frame. @Kiwasi I would used float literals instead of integer literals, just to make sure there will be no casting surprises.
The ‘L’ in Lerps stands for ‘linear’, so the speed is constant.
Lerps will never exceed the final value.
Debug.Log(Mathf.Lerp(0, 1, 2));
//output is 1
True - but if the value is 4.8 on one frame and 5.2 on the next then the loop will exit and the final Lerped position will be less than 1. Problem isn’t lerp - it’s the loop condition.
@KelsoMRK you’re right, the last step is skipped. A quick fix is to accumulate deltaTime before the Lerp:
while (timer < 5.0f)
{
timer += Time.deltaTime;
transform.position = Vector3.Lerp(startPosition, endPosition, timer/5.0f);
yield return null;
}