- Home /
Unity2D - MoveTowards not working as planned
My final goal was to have point A and point B and use movetowards to smoothly transverse these two points
Solution - A - - - - B
I used the Vector3 Movetowards method to achieve this but I am not getting the desire effect.
Instantiate (laser, estart.transform.position, this.transform.rotation);
laser.transform.position = Vector3.MoveTowards(estart.transform.position, playerpos, Time.deltaTime * 0.3f);
I was sure that: estart,transform would = point A
playerpos is the end result of point B
and my time.deltaTime * speed would be the time in order to transverse these points.
However, rather than get that effect I get nothing in which the laser simply stays on the estart position and moves using the laserspeed without any real destination so simply the same as had i used just the rigidbody2D.velocity
in case this is important ill add several points:
I have not set the velocity of the object in the object's script in this example as this is being done when instantiated and does not move and when i do this it simply goes in the direction of velocity not following the A-B points. Next im doing this off the ground so not using gravity as i want the laser to instantiate and then fly towards the playerpos
I have tried many attempts at getting this working from using raycasts to animation to other vector3 methods however from what i see in unity documentation this seems to be the method i am needing so any help would be appreciated as this is the final part to the boss. Thanks
EDIT:
here is my updated code
using UnityEngine;
using System.Collections;
public class FindPlayer : MonoBehaviour
{
public bool clonecreate = true;
public Vector3 playerpos;
public bool spotted = false;
public GameObject laser;
public GameObject estart;
// Use this for initialization
void Start ()
{
}
// Update is called once per frame
void Update ()
{
if (clonecreate == false) {
Debug.Log ("hello there im in the update");
float step = Time.deltaTime * 2.0f;
if (laser != null) {
if (laser.transform.position != playerpos) {
laser.transform.position = Vector3.MoveTowards (estart.transform.position, playerpos, step);
}
}
clonecreate = true;
}
}
IEnumerator OnTriggerStay2D (Collider2D target)
{
if (target.gameObject.tag == "Player") {
if (spotted == false) {
Vector3 targetcaught = target.transform.position;
spotted = true;
playerpos = targetcaught;
yield return StartCoroutine (Delay (2.0f));
}
}
}
IEnumerator Delay (float wait)
{
if (spotted) {
//Debug.Log ("Delay " + Time.time);
yield return new WaitForSeconds (wait);
//Debug.Log ("Delay finished " + Time.time);
Instantiate (laser, estart.transform.position, this.transform.rotation);
Debug.Log ("this is being instantiated");
clonecreate = false;
if(clonecreate == true)
spotted = false;
}
}
}
im really hoping this is a daft error on my part as im stumped as to why this is happening
Could perhaps this be approved soon as it is the last piece needed for my boss and last moderator took nearly a day to approve my last question which i feel is too long. Thanks very much
Answer by Neamtzu · Apr 09, 2015 at 10:10 AM
Vector3.MoveTowards should be called in Update, until the movement is done, not only once. Here you can find more details: http://docs.unity3d.com/ScriptReference/Vector3.MoveTowards.html
i have my movetowards within my coroutine... is the solution to add a conditional to my update so only when the laser is instiated does it then trigger the movetowards code?
You can keep the $$anonymous$$oveTowards function in the couroutine using this simple logic:
IEnumerator ienum() {
while(Vector3.Distance(yourObject.transform.position, targetPosition) < 0.1f) {
yourObject.transform.position = Vector3.$$anonymous$$oveTowards(yourObject.transform.position, targetPosition, Time.deltaTime);
yield return WaitForEndOfFrame;
}
}
Or you can make a boolean true when you need to move, in Update apply the $$anonymous$$oveTowards function only if that boolean is true and check if your object reached the target position.
I have actually created the bool however its still not working ive edited my question to contain the new code. Thanks
The problem is that in the first frame you move and then you make the boolean true, which will make the $$anonymous$$oveTowards to be called only once. Replace your Update function with this:
void Update ()
{
if (clonecreate == false) {
Debug.Log ("hello there im in the update");
float step = Time.deltaTime * 2.0f;
if (laser != null) {
if (Vector3.Distance(laser.transform.position, playerpos) < 0.1f)
laser.transform.position = Vector3.$$anonymous$$oveTowards (laser.transform.position, playerpos, step);
else
clonecreate = true;
}
}
}
Please note the changes I made:
Because you are working with floats and lerps, it's better to approximate the distance between 2 points. It will take much more time until they will be perfect one on top of the other.
In Vector3.$$anonymous$$oveTowards the first parameter should be the current position of the object (which will be updated over time). If you want to start the movement from "estart", instantiate or move the object to that position before calling the $$anonymous$$oveTowards function
You need to make that bool variable true if the object is near the finish point. At this moment, in the first frame the object will move and then the bool is made true. In the next frame it will not move.
Looks like you're resetting the flag (cloneCreate) as soon as you do the first $$anonymous$$oveTowards (line 28), so it's still only doing it once. And you're ignoring the crucial "until the movement's done" and "check if your object reached the target position" part of Neamztu's answer.