- Home /
My click to move to script moves instantly instead of steadily
No, the problem isn't that I need to use lerp or MoveTowards becuase I've tried both of those(right now Lerp is in my script) I know my character is not just moving very fast becuase a enemy that is supposed to kill my player on contact doesn't kill them when they should intersect while moving. I have a feeling the problem is caused by my makeshift collision system for my player movement because my player has to be kinematic(see the bottom part of the script) I don't know how else to implement the collision system. If you have any suggestions on that please give me some. Finally the way the player moves. There is a commented out selection of my lerp script that when enabled makes my lerp script lerp in a triangle fashion rather then in a straight line. I have no clue what i'm doing wrong here but if you have a suggestion I'd gladly accept.
my script
using UnityEngine;
using System.Collections;
public class Dash : MonoBehaviour
{
public GameObject Previouscollided;
private GameObject collided;
public LayerMask Wall;
Vector3 newPosition;
public GameObject RecentWall;
public float speed;
[SerializeField]
public int CurrentWall;
private bool LerpToPosition;
private bool LerpToX = true;[SerializeField]
private bool LerpToY = true;[SerializeField]
private bool LerpToZ = true;[SerializeField]
public bool clicked;
private Vector3 NewPositionX;
private Vector3 NewPositionZ;
private Vector3 NewPositionY;
void Start()
{
newPosition = transform.position;
}
void Update()
{
if (Input.GetMouseButtonDown(0))
{
RaycastHit hit;
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out hit, Wall.value))
{
LerpToX = true;
LerpToZ = true;
LerpToY = true;
collided = hit.collider.gameObject;
LerpToPosition = true;
RecentWall = collided;
newPosition = hit.point;
Previouscollided.layer = LayerMask.NameToLayer("Wall");
Previouscollided = hit.collider.gameObject;
CollidedCheck();
}
}
}
private void CollidedCheck()
{
if (collided.tag == "Wall")
{
StartCoroutine("LerpPos");
}
}
private IEnumerator LerpPos()
{
NewPositionX = newPosition;
NewPositionY = newPosition;
NewPositionZ = newPosition;
while (LerpToX == true || LerpToZ == true || LerpToY == true)
{
while (LerpToX == true)
{
NewPositionX.y = 0;
NewPositionX.z = 0;
if (Vector3.Distance(transform.position, NewPositionX) <= 5)
{
LerpToX = false;
yield return null;
}
transform.position = Vector3.Lerp(transform.position, NewPositionX, speed);
}
/* while (LerpToY == true) // the commented out section I was talking about
{
NewPositionY.x = 0;
NewPositionY.z = 0;
if (Vector3.Distance(transform.position, NewPositionY) <= 5)
{
LerpToY = false;
yield return null;
}
transform.position = Vector3.Lerp(transform.position, NewPositionY, speed);
}*/
while (LerpToZ == true)
{
NewPositionY.x = 0;
// no this is not typo, if I don't have this as NewPositionY even
//this shoiuld be NewPositionZ the cube will only move on the x and z/ x and y axis |I cant tell |
NewPositionY.y = 0;
if (Vector3.Distance(transform.position, NewPositionZ) <= 5)
{
LerpToZ = false;
yield return null;
}
transform.position = Vector3.Lerp(transform.position, NewPositionZ, speed);
}
yield return null;
}
}
}
Using a coroutine for movement is a bad choice, as @Nose$$anonymous$$ills said, you're your usage of the "while loop" basically moves you all the way there before a new frame. Which is one reason why you never get the colllission of the enemy. The other reason being that you aren't even moving the player with physics, so a collision will never occur.
Answer by NoseKills · May 12, 2017 at 02:58 PM
You yield out of the method in the 3 inner loops only when the object is closer than 5 units away from the target position and at the same time you move on to lerp the next coordinate.
Only when you yield out of the method, your app can execute the rest of its code, including all of Unity's code, for example the part where the game gets drawn on screen.
I think you should move the yield commands out of the if-clauses in the loops so you move the objects only once every Update(), not all the way to the target coordinate.
I assume you are moving the object just 1 coordinate at a time on purpose so i won't cover that.
Another thing to check is the value of speed
. If it's 1 or greater, this will all happen in 3 frames even if you fix the other problems.
It is true that it doesn't matter whether you use Lerp or MoveTowards, but whichever you choose, you have to understand what they do and what are their differences so you can achieve the result you want with them and know what to pass in as parameters.
They execute one at a time? So should I have them in like 3 different scripts because the purpose of the 3 lerps is to replicate collision with a kinematic game-object. Or is there a better way to do that?
Each of the inner loops has an exit condition that's fulfilled by rolling in that loop until the Lerp has moved the object enough. The next inner loop can start executing only after the one before it has finished - yielding takes you out of the method but the same loop continues when you return back to it - so the object in this case will first move all the way on th X-axis and then move on to the loop that moves it on the Z-axis. After both the inner loops have finished LerpToX and LerpToZ are set to false, but LerpToY is true and keeps your coroutine forever trapped in the outer loop... doing nothing because x and z conditions are still met.
This will also cause a bug since the LerpTo variables are not local variables in the coroutine and the next time you click to start another coroutine, the previous, trappped, coroutine is still there waiting for you to turn LerpToX and Z back to true. Now you have 2 coroutines moving the object at double speed. So make sure the exit conditions can be met.
If you just need to move the object s$$anonymous$$dily from A to B in a coroutine, you don't need to Lerp each component of the vector separately. Thats exactly what Vector3.$$anonymous$$oveTowards and Vector3.Lerp are there for and thats why they take in and return a Vector3: they handle x, y and z all in 1 go.
All you should need to do is something like
private IEnumerator LerpPos()
{
NewPosition = newPosition;
while (Vector3.Distance(transform.position, NewPosition) > 5)
{
transform.position = Vector3.$$anonymous$$oveTowards(transform.position, NewPosition, speed);
yield return null;
}
}
You could do it with Lerp too but to do it "properly" it would require a few lines more and this comment is long enough already. There's already so many threads here about Lerp vs. $$anonymous$$oveTowards that you should easily find info about them by searching if you need to :)
Your answer
Follow this Question
Related Questions
Multiple Cars not working 1 Answer
Unity input system character control 1 Answer
Distribute terrain in zones 3 Answers