0
\$\begingroup\$

I've been trying to get a unit in my project to move in a fashion similiar to that of modern MOBA games.

However, I am faced with the issue of the unit moving before the rotation is completed and the unit moving along the Y-axis.

I have tried using a cooroutine to allow the rotation to completed first, but to no avail. Any help would be greatly appreciated.

using UnityEngine;
using System.Collections;

public class Move : MonoBehaviour {

    public float smooth;
    public float speed;

    private float z;
    private float x;
    private Vector3 targetPosition;

    // Use this for initialization
    void Start () {

    }

    // Update is called once per frame
    void Update () {

        if (Input.GetKeyDown(KeyCode.Mouse0))
        {

            speed = 1;
            smooth = 20;

            RaycastHit hit;

            //var playerPlane = new Plane(Vector3.up, transform.position);
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);

            //double hitdist = 0.0;

            if (Physics.Raycast(ray, out hit))
            {
                targetPosition = hit.point;

                x = hit.point.x;
                z = hit.point.z;
                //var targetRotation = Quaternion.LookRotation(targetPoint    - transform.position);
                //transform.rotation = targetRotation;
            }   
        }


        StartCoroutine(Turn(x,z));

        //transform.position = Vector3.RotateTowards(transform.position, targetPosition, speed*Time.deltaTime, 0.0f);
        transform.position = Vector3.MoveTowards(transform.position, targetPosition, Time.deltaTime * smooth);
    }

    IEnumerator Turn(float _x, float _z)
    {
        Vector3 turn = new Vector3 (_x, 0, _z);
        transform.Rotate(turn, speed);
        yield return null;
    }
}
\$\endgroup\$
2
\$\begingroup\$

There are two options here.

  1. Moving the unit at the end of the coroutine (and maybe changing the name of the coroutine)
  2. Creating a second coroutine that waits for the first one to finish before executing

Now I'll illustrate the examples

// 1st option
IEnumerator Turn(float _x, float _z)
{
    Vector3 turn = new Vector3 (_x, 0, _z);
    transform.Rotate(turn, speed);
    yield return null;
    // now move
    transform.position = Vector3.MoveTowards(transform.position, targetPosition, Time.deltaTime * smooth);
}

Let's work out a second option with some code you commented, but I think it's a better approach

// Move function is the coroutine to be called to trigger movement
IEnumerator Move(Vector3 targetPosition)
{
    // we want to rotate first
    yield return Turn(Vector3 targetPosition);
    // then translate
    transform.position = Vector3.MoveTowards(transform.position, targetPosition, Time.deltaTime * smooth);
}

IEnumerator Turn(Vector3 targetPosition)
{
    Quaternion srcRotation = transform.rotation;
    Quaternion dstRotation = Quaternion.LookRotation(targetPosition);
    float percent = 0.1f;
    while (percent <= 1.0f)
    {
        Quaternion newRotation = Quaternion.Lerp(srcRotation, dstRotation, percent);
        transform.rotation = newRotation;
        percent += .01f;
        yield return null;
    }
}

Using Lerp gives us smoothing and then you can change the values according to your own rotation speed, movement speed, etc.

| improve this answer | |
\$\endgroup\$
1
\$\begingroup\$

No need for the coroutine, just don't update the position until the rotation has been completed:

if(turnComplete){
    transform.position = Vector3.MoveTowards(transform.position, targetPosition, Time.deltaTime * smooth);
}

Getting whether the turn is completed means checking how much more the unit needs to turn. If the remaining angle is small enough then turnComplete=true;

| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.