0
\$\begingroup\$

This script is attached to each drone.

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

public class DroneControl : MonoBehaviour
{
    public Transform target;
    public float turnSpeed = .01f;
    Quaternion rotGoal;
    Vector3 direction;
    public float movingSpeed;
    public bool go = false;

    private bool waitBeforeRotate = false;
    private bool startRotating = false;

    // Start is called before the first frame update
    void Start()
    {
      
    }

    // Update is called once per frame
    void Update()
    {
        if(go)
        {
            transform.position += transform.forward * movingSpeed * Time.deltaTime;

            if (waitBeforeRotate == false)
            {
                StartCoroutine(StartRotating());

                waitBeforeRotate = true;
            }

            if (startRotating)
            {
                direction = (target.position - transform.position).normalized;
                rotGoal = Quaternion.LookRotation(direction);
                transform.rotation = Quaternion.Slerp(transform.rotation, rotGoal, turnSpeed);
            }
        }
    }

    IEnumerator StartRotating()
    {
        yield return new WaitForSeconds(3f);

        startRotating = true;
    }
}

I can think of two potential problems here, but I'm not sure if this is what making the behaviour of spinning nonstop at the target:

  1. The objects are moving forward but nothing tells them to stop at the target. Only the rotation makes them move to the target direction.

  2. Since the objects rotate to face the target direction, maybe when they reach the target they keep rotating ?

The goal at first is to move the objects to the target and stop at the target.

\$\endgroup\$
1
\$\begingroup\$

The drone does not know when it reached its target. When it passes through the target it just continues its forward movement and rotation toward the target like before. Because the target is so close drone's rotation can't keep up with the forward movement and it looks like rotation around the target, i.e. while turning back toward the target the drone has already moved away from it. When both forward move and rotation balance out it looks like orbiting.

You need a way for your drone to know if it is close enough to its target to stop. I modified your code to add range check:

using System.Collections;
using UnityEngine;

public class DroneControl : MonoBehaviour
{
    public Transform target;
    public float turnSpeed = .01f;

    Quaternion rotGoal;
    Vector3 direction;
    public float movingSpeed;
    public bool go = false;

    private bool waitBeforeRotate = false;
    private bool startRotating = false;

    #region AddedCode
    public float targetRange = 1.0f;

    private bool IsTargetReached(Vector3 dronePos, Vector3 targetPos)
    {
        var distance = Vector3.Distance(dronePos, targetPos);
        return distance < targetRange;
    }
    #endregion AddedCode

    // Update is called once per frame
    void Update()
    {
        // next line is modified to incorporate the range check
        if (go && !IsTargetReached(transform.position, target.position))
        {
            transform.position += transform.forward * movingSpeed * Time.deltaTime;

            if (waitBeforeRotate == false)
            {
                StartCoroutine(StartRotating());

                waitBeforeRotate = true;
            }

            if (startRotating)
            {
                direction = (target.position - transform.position).normalized;
                rotGoal = Quaternion.LookRotation(direction);
                transform.rotation = Quaternion.Slerp(transform.rotation, rotGoal, turnSpeed);
            }
        }
    }

    IEnumerator StartRotating()
    {
        yield return new WaitForSeconds(3f);

        startRotating = true;
    }
}
\$\endgroup\$
1
\$\begingroup\$

I think the method you are looking for is Quaternion.RotateTowards. This method can be used to turn one quaternion towards another, but limit the angular distance it is allowed to change per call of the method. When that angular distance is enough to reach the desired rotation, then it will set the rotation to exactly the desired rotation and not overshoot.

This method is the standard solution for making one object track another with its rotation.

transform.rotation = Quaternion.RotateTowards(transform.rotation, rotGoal, turnSpeed * time.deltaTime);

Note that turnSpeed is now measured in degrees per second. For example, if you want the object to be able to turn 180° in one second, you would set it to 180. Your current default value of 0.01 is far too slow to even be visible.

If you want to check whether or not the object reached the desired rotation, you can do this just after the line above:

if (transform.rotation == rotGoal) {
    // now aiming directly at the target
} else {
    // still some way to go
}
\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .