A continuation of this thread kinda. I’ve been working on a Point and click demo, currently using a raycast and the movetoward method. however when the method is called, the player only moves one step toward the hit point. using a while loop causes an infinite loop and the editor hangs. what should I do to get the player to smoothly move to the clicked on point?
here’s my current code:
public override void Movement()
{
mousePos = Input.mousePosition;
ray = cam.ScreenPointToRay(mousePos);
var mask = layer;//layermask
RaycastHit hit;//location of point ray hit
if(Input.GetMouseButtonDown(0))//if LMB is clicked
{
if (Physics.Raycast(ray, out hit, Mathf.Infinity, ~mask))//if a ray hits
{
Debug.Log(hit.point);//return hit location
Debug.Log(hit.collider.gameObject);//return hit object
Travel(hit.point);//travel to point
}
}
}
public void Travel(Vector3 destination)
{
//go to
transform.position = Vector3.MoveTowards(transform.position, destination, .2f);//move toward location
}
MoveToward does exactly what it sounds like. It moves a little bit from A to B, by a distance of the third parameter. Usually when people use MoveTowards they call it once each frame until the object reaches its destination. You’re literally just calling it once here, so naturally it only moves once.
What you do is:
When the player clicks the button, store the destination you want the player to go to (a Vector3 variable). Also store a bool variable saying that you are now moving (isMoving = true).
Then, in Update, if you see that you are moving (check the bool), call MoveTowards to move a little bit towards the destination, then if you have reached the destination, you can set isMoving = false.
One final note: you generally want to multiply the third parameter of MoveTowards by Time.deltaTime. This will ensure that your movement is smooth across different framerates. Otherwise your movement speed will change depending on the framerate of the game.
ah I see, I originally had “while (transform.position != destination)” but that kept hanging up. will moving the bool check prevent that?
EDIT: also, the way my player script is structured, one script handles receiving input and the other handles the response in a listener pattern(this is so that I can change control types quickly)
and the above script is the listener, and as such, doesn’t feature an update method.
You don’t want a while loop here. Remember, update runs once per frame. What you should be going for is moving a little bit each frame. That means just move a little bit in Update and wait for Unity to call Update again.
because your current code is inside an if statement: if(Input.GetMouseButtonDown(0)). That is only true during the one frame during which the user clicked the mouse button. So you’re only calling MoveTowards once, during that single frame. What you should do is set a destination and
Currently the code is a little…odd. Now when the script starts the player moves away from the camera a little bit, and the player jitters when it reaches the destination
Update 2: after adding the isMoving boolean I’m back to square one
public override void Movement()
{
mousePos = Input.mousePosition;
ray = cam.ScreenPointToRay(mousePos);
var mask = layer;//layermask
bool isMoving = false ;
RaycastHit hit;//location of point ray hit
if(Input.GetMouseButtonDown(0))//if LMB is clicked
{
if (Physics.Raycast(ray, out hit, Mathf.Infinity, ~mask))//if a ray hits
{
Debug.Log(hit.point);//return hit location
Debug.Log(hit.collider.gameObject);//return hit object
destination = hit.point;
isMoving = true;
}
}
if(isMoving == true)
{
Travel(destination);//travel to point
}
if (transform.position == destination)
{
isMoving = false;
}
}
after adding if(isMoving == true), the player is back to only moving one step per click
Currently your isMoving variable is a local variable. That means it gets created anew every time Movement() runs. You also explicitly set it to false every frame on line 7. You need to make it an instance variable instead by declaring it outside the method:
bool isMoving = false;
public override void Movement()
{
mousePos = Input.mousePosition;
ray = cam.ScreenPointToRay(mousePos);
var mask = layer;//layermask
RaycastHit hit;//location of point ray hit
if(Input.GetMouseButtonDown(0))//if LMB is clicked
{
if (Physics.Raycast(ray, out hit, Mathf.Infinity, ~mask))//if a ray hits
{
Debug.Log(hit.point);//return hit location
Debug.Log(hit.collider.gameObject);//return hit object
destination = hit.point;
isMoving = true;
}
}
if(isMoving)
{
Travel(destination);//travel to point
}
if (transform.position == destination)
{
isMoving = false;
}
}