Why the object using Vector3.MoveTowards is not moving down ?

I’m using this script on a object to move the object from one position to a target position and when the object is above the target i want the object to move directly down.

But instead what it does not is when the object is above the other object the target then he just rotating in the air above the target. I can’t figure out why it’s not moving down and why the object keep rotating above the target.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class FlyToOverTerrain : MonoBehaviour
{
    public Transform target;
    public float desiredHeight = 10f;

    public float flightSmoothTime = 10f;
    public float maxFlightspeed = 10f;
    public float flightAcceleration = 1f;

    public float levelingSmoothTime = 0.5f;
    public float maxLevelingSpeed = 10000f;
    public float levelingAcceleration = 2f;
    
    private Vector3 flightVelocity = Vector3.zero;
    private float heightVelocity = 0f;

    private RaycastHit hit;

    private void Start()
    {

    }

    private void LateUpdate()
    {
        Vector3 position = transform.position;
        float currentHeight = position.y;
        if (target && flightAcceleration > float.Epsilon)
        {
            position = Vector3.SmoothDamp(position, target.position, ref flightVelocity, flightSmoothTime / flightAcceleration, maxFlightspeed, flightAcceleration * Time.deltaTime);
        }

        if (levelingAcceleration > float.Epsilon)
        {
            float targetHeight = Terrain.activeTerrain.SampleHeight(position) + desiredHeight;

            position.y = Mathf.SmoothDamp(currentHeight, targetHeight, ref heightVelocity, levelingSmoothTime / levelingAcceleration, maxLevelingSpeed, levelingAcceleration * Time.deltaTime);
        }

        transform.position = position;

        if (Physics.Raycast(transform.position, Vector3.down, out hit))
        {
            if (hit.transform == target)
            {
                transform.position = Vector3.MoveTowards(transform.position, target.position, 3 * Time.deltaTime);
            }
        }
        else
        {
            transform.position = position;
        }
    }
}

It’s because the only condition for setting position.y is whether or not there is a leveling acceleration. I added a flag to determine whether or not you are over the target and use that to control the “hovering” part of your code…

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class FlyToOverTerrain : MonoBehaviour
{
  public Transform target;
  public float desiredHeight = 10f;

  public float flightSmoothTime = 10f;
  public float maxFlightspeed = 10f;
  public float flightAcceleration = 1f;

  public float levelingSmoothTime = 0.5f;
  public float maxLevelingSpeed = 10000f;
  public float levelingAcceleration = 2f;

  private Vector3 flightVelocity = Vector3.zero;
  private float heightVelocity = 0f;
  private bool overTarget = false;

  private RaycastHit hit;

  private void Start()
  {

  }

  private void LateUpdate()
  {
    Vector3 position = transform.position;
    float currentHeight = position.y;
    if (target && flightAcceleration > float.Epsilon)
    {
      position = Vector3.SmoothDamp(position, target.position, ref flightVelocity, flightSmoothTime / flightAcceleration, maxFlightspeed, flightAcceleration * Time.deltaTime);
    }

    if (!overTarget && levelingAcceleration > float.Epsilon)
    {
      float targetHeight = Terrain.activeTerrain.SampleHeight(position) + desiredHeight;

      position.y = Mathf.SmoothDamp(currentHeight, targetHeight, ref heightVelocity, levelingSmoothTime / levelingAcceleration, maxLevelingSpeed, levelingAcceleration * Time.deltaTime);
    }

    transform.position = position;

    if (Physics.Raycast(transform.position, Vector3.down, out hit))
    {
      if (hit.transform == target)
      {
        overTarget = true;
        transform.position = Vector3.MoveTowards(transform.position, target.position, 3 * Time.deltaTime);
      }
    }
    else
    {
      transform.position = position;
    }
  }
}

All that said, there’s a state pattern in your problem. You want to hover over the terrain until you are over the target and then start lowering. You might consider refactoring accordingly.

Also the transform.position assignment at the end is superfluous. It already happened before you checked the raycast. :slight_smile: