I'm trying to smoothly move from my current position to a new position that I've hard coded but even using the Vector3.Lerp and Vector3.MoveTowards it's just moving the player normally without any delay effect.
I have also tried to add Time.deltaTime in the Vector3.Lerp method but it's just moving the player tiny bit. I just want the player to smoothly move towards the set position.
I'm new to Unity and any help would be highly appreciated.
public class PlayerControl : MonoBehaviour {
//change position
private float leftX = -1.65f;
private float leftY = 0.00f;
private float rightX = -1.00f;
private float rightY = -1.13f;
private Vector3 carPosition;
private float slowTime = 2f;
void Start () {
//set the player to its current position
carPosition = transform.position;
}
void Update () {
//control the player
if (Input.GetKeyDown(KeyCode.Space) || Input.GetMouseButtonDown(0)) {
Debug.Log("Pressed!");
if(transform.position.y <= -0.5) {
carPosition.x = leftX;
carPosition.y = leftY;
}
if(transform.position.y >= 0) {
carPosition.x = rightX;
carPosition.y = rightY;
}
//transform.position = carPosition;
transform.position = Vector3.Lerp(transform.position, carPosition, slowTime);
}
}
}
Edit: re-wrote the answer to better explain how Lerp
works.
Lerp
works in a very simple way: let's call the parameters V1, V2 and perc - result = Vector3.Lerp(V1, V2, perc)
.
Let's say that V1 = (0,0,0)
, V2 = (1,0,0)
and perc = 0,2f
. With these fixed parameters, you get result = 0.2f
or, in other words, you get a Vector3 nearer to V2, starting from V1, by the percentage perc.
Now, if you want to move an object from V1 to V2 with a fixed step, you need, every Update()
call, to modify the parameter perc
. For example, if you want to reach the destination in exactly 5 single steps, then you'll need to call Lerp 5 times using this sequence of perc
: 0.2 - 0.4 - 0.6 - 0.8 - 1
. You want to move the object using 10 steps? Then you use the sequence 0.1 - 0.2 - 0.3 etc, you get the idea.
But this way of doing things gives you a choppy animation, so you want to use the time passed to calculate how much is the perc
parameter every Update
(the example code is in the link provided by Lukasz) to get a smooth and linear movement from start to end.
So your class should look like this:
using UnityEngine;
public class PlayerControl : MonoBehaviour {
private float leftX = -1.65f;
private float leftY = 0.00f;
private float rightX = -1.00f;
private float rightY = -1.13f;
private float speed = 2f, startTime, totalDistance = 0f;
private Vector3 carPosition, startPos;
void Start () {
carPosition = transform.position;
startPos = carPosition;
}
void Update () {
if (Input.GetKeyDown (KeyCode.Space) || Input.GetMouseButtonDown (0)) {
Debug.Log ("Pressed!");
startTime = Time.time;
if (transform.position.y <= -0.5) {
startPos = transform.position;
carPosition.x = leftX;
carPosition.y = leftY;
}
if (transform.position.y >= 0) {
startPos = transform.position;
carPosition.x = rightX;
carPosition.y = rightY;
}
totalDistance = Vector3.Distance(startPos, carPosition);
}
if (startPos != carPosition) {
float newPercentageBetweenVectors = (Time.time - startTime) * speed / totalDistance;
transform.position = Vector3.Lerp (startPos, carPosition, newPercentageBetweenVectors);
}
}
}
The other way to use Lerp to move an object is to keep a fixed perc
and use the position of the object as the first parameter. This will give you a logarithmic kind of movement, faster at start and slower the more you're near the destination, but be aware that you'll never reach it since it's an asymptote - this means that you'll need to check by yourself if the current position is near enough the final position by a specific distance, for example 10^-2, with code like this:
using UnityEngine;
public class PlayerControl : MonoBehaviour {
private float leftX = -1.65f;
private float leftY = 0.00f;
private float rightX = -1.00f;
private float rightY = -1.13f;
private float speed = 2f, totalDistance;
private Vector3 carPosition;
void Start () {
carPosition = transform.position;
}
void Update () {
if (Input.GetKeyDown (KeyCode.Space) || Input.GetMouseButtonDown (0)) {
Debug.Log ("Pressed!");
if (transform.position.y <= -0.5) {
carPosition.x = leftX;
carPosition.y = leftY;
}
if (transform.position.y >= 0) {
carPosition.x = rightX;
carPosition.y = rightY;
}
}
if (transform.position != carPosition) {
transform.position = Vector3.Lerp (transform.position, carPosition, speed * Time.deltaTime);
totalDistance = Vector3.Distance(transform.position, carPosition);
if (totalDistance < Mathf.Pow(10,-2)) transform.position = carPosition;
}
}
}
The use of Time.deltaTime
in this case isn't necessary, if you provide a low enough speed
.
This second use of Lerp is particularly indicated (and indeed widely used) for moving cameras towards a game object.
Your mistake is here:
transform.position = Vector3.Lerp(transform.position, carPosition, slowTime);
Dont use transfrom.position as a parameter. Use some startPosition variable as in
transform.position = Vector3.Lerp(startPosition, carPosition, slowTime);
Also slowTime should be a fraction of the distance traveled clamped to [0, 1]. When you put 2f there you are instantly moved to the finish. Put 0.5f there to see what I am talking about.
Please Check:
https://docs.unity3d.com/ScriptReference/Vector3.Lerp.html
This is the way I learned to do it:
Make a new Coroutine (IEnumerator Title){}.
Make a float called t. Assign its value to 0.
Make a while loop:
while(t < 1){
}
Type in "t += Time.deltaTime / speed
Do transform.position = Vector3.Lerp(transform.position, carPosition, t);
Do yield return null.
That's the way I learned it. Your finished code should be this:
IEnumerator Drive(){
float t = 0;
while(t < 1){
t += Time.deltaTime / speed;
transform.position = Vector3.Lerp(transform.position, carPosition, t);
yield return null;
}
}
And remember to start the Coroutine, too. (StartCoroutine(Drive());