Vector3.MoveTowards absolutely not moving the object
I have something as simple as this:
transform.position = Vector3.MoveTowards (transform.position, rutaObjetivo, velocidad * Time.deltaTime);
And it's not working, I'm debugging before and after and transform.position never changes at all, 'rutaObjetivo is being debugged too and I confirm it has the correct coordinates of the target position.
This is my complete code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using NUnit.Framework;
public class ControladorEnemigo : MonoBehaviour
{
[HideInInspector]
public float salud = 10f, velocidad = 5f;
List<GameObject> movimientosRutas;
Vector3 rutaObjetivo;
void Start ()
{
movimientosRutas = new List<GameObject> ();
foreach (GameObject ruta in GameObject.FindGameObjectsWithTag ("Muralla")) {
movimientosRutas.Add (ruta);
}
determinarRuta ();
}
void Update ()
{
if (!rutaObjetivo.Equals (Vector3.zero)) {
Debug.Log (transform.position + " " + rutaObjetivo);
transform.position = Vector3.MoveTowards (transform.position, new Vector3 (5f, 0.5f, 10f), velocidad * Time.deltaTime);
}
}
void OnTriggerEnter (Collider rutaColisionada)
{
if (rutaColisionada.CompareTag ("Muralla")) {
determinarRuta ();
}
}
void determinarRuta ()
{
if (movimientosRutas.Count > 0) {
float distanciaPuntoMurallaMasCercano = Mathf.Infinity;
int rutaABorrar = 0;
for (int i = 0; i < movimientosRutas.Count; i++) {
float distanciaActual = Vector3.Distance (transform.position, movimientosRutas [i].transform.position);
if (distanciaActual < distanciaPuntoMurallaMasCercano) {
distanciaPuntoMurallaMasCercano = distanciaActual;
rutaObjetivo = movimientosRutas [i].transform.position;
rutaABorrar = i;
}
}
movimientosRutas.RemoveAt (rutaABorrar);
}
}
}
Is something wrong with my code?
Thanks in advance.
Answer by Bunny83 · Jan 22, 2018 at 04:41 AM
Sorry but MoveTowards is implemented like this:
public static Vector3 MoveTowards(Vector3 current, Vector3 target, float maxDistanceDelta)
{
Vector3 a = target - current;
float magnitude = a.magnitude;
if (magnitude <= maxDistanceDelta || magnitude == 0f)
return target;
else
return current + a / magnitude * maxDistanceDelta;
}
So as long as there is any distance between current and target and as long as maxDistanceDelta is greater than 0 this method will always make the returned value be different from what you passed in.
If the object doesn't move there are several possible reasons:
First the most obvious: Your target equals your current position so you don't move at all since you are already there.
Second there might be another script which sets this object's position so you overwrite what you've done here.
If you marked your object as "static" (the static checkmark at the top of the inspector). Static objects might get statically batched. Moving a static object will not change where it's rendered since it's now part of a larger batched mesh.
You may have set your Time.timeScale to 0. This will make your deltaTime to be 0 and therefore your "maxDistanceDelta" will be 0.
To me the first case might be the most logical. Your "determinarRuta" method has several flaws. First of all you always choose the waypoint / gameobject that is closest to your current position. That may be your intention, but if you currently are at a waypoint from that list it will always return this once since the distance will be 0.
You use a foreach loop to iterate through your list and in parallel you count your "rutaABorrar" variable up. However the way you use that variable doesn't make much sense. I guess your intention was to remove the selected waypoint / gameobject from that list. However your code will always remove the last element in the list, regardless of what's the closest object. So when your first object in the list is the closest you will remove the last item in your list.
I would also suggest that you use a generic List instead of an ArrayList. The ArrayList is basically obsolete since generics were implemented in C#. The ArrayList always requires casting to get an object back out of the list. A foreach loop can do this implicit but it still has to cast it. Your search routine should be changed to use a for loop instead. When you found a better / closer object you want to save the index of the choosen element so you can remove it from the list at the end.
Thanks for catching my mistakes. I took all your recommendations and the code is edited in the OP. Still, no result, if you wanna see what my debug outputs in this line:
Debug.Log (transform.position + " " + rutaObjetivo);
I get this: (5.8, 0.5, -5.9) (4.2, 0.5, -0.5) UnityEngine.Debug:Log(Object) ControladorEnemigo:Update() (at Assets/Scripts/ControladorEnemigo.cs:26)
Clearly they're different, but even if I put an arbitrary value in $$anonymous$$oveTowards like:
transform.position = Vector3.$$anonymous$$oveTowards (transform.position, new Vector3 (5f, 0.5f, 10f), velocidad * Time.deltaTime);
It still doesn't move
I also want to point out I haven't changed the timeScale, it has all the default values once you first create a project: 
And there's no other scripts interfeering with this script, in fact this is the only one attached to that gameobject.
Answer by cuartas15 · Jan 23, 2018 at 02:27 AM
Ok, I'm gonna answer myself. The error was here:
public float salud = 10f, velocidad = 5f;
The variables are not initialized there, that's weird because I've seen hundreds of examples initializing primitive type variables there. The solution was just to give their values in the Start() function and it worked.
Well your variable is initialized there. However field initializers run even before the constructor of the class run. Since your declared the variable public the variable will be serialized in the inspector. You may have set it to 0 there. So check your inspector. If you don't want to set the variable in the inspector, don't make the variable public or use the NonSerialized attribute.
I have hideininspector above them, doesn't do the same? I want to keep them public because in the future those values will change once instantiated
No, HideInInspector will just hide it but the value is still serialized. This is the worst case you could have as you don't see what value is serialized and you can't changed it through the inspector. If you want to set the variable through code only use NonSerialized.
Your answer
Follow this Question
Related Questions
Change Target Script For Move Towards 1 Answer
how can I "play" the whole MoveTowards sequence after one click? 1 Answer
Why does my cube not move? 0 Answers
Using MoveTowards to move GameObject from starting point to mouse cursor 0 Answers
[Solved] Sliding garage door using transform.translate. 1 Answer