StuckInPhDNoMore
StuckInPhDNoMore

Reputation: 2689

How to continuously move a GameObject between two positions?

I'm coding my games boss behaviour and in the final stage of the battle the boss is supposed to charge towards the player and then move back to its original position. Wait for 5 seconds and then do the same.

I tried to achieve this using coroutines and Vector2.MoveTowards() but am not getting the desired effect, first off the boss does not "Move Towards" the player but instantly appears at the targetPosition and then just stays there, does not move back.

Below is my code:

private Vector2 chargeTarget;
private Vector2 tankStartPosition;

void Start()
{
    chargeTarget = new Vector2(-5.0f, transform.position.y);
    tankStartPosition = transform.position;
}

void Update()
{
    if (Time.time > nextCharge)
    {
        StartCoroutine(TankCharge());
        nextCharge = Time.time + chargeRate;
    }
}

IEnumerator TankCharge()
{
    transform.position = Vector2.MoveTowards(tankStartPosition, chargeTarget, Time.deltaTime * chargeSpeed);

    transform.position = Vector2.MoveTowards(chargeTarget, tankStartPosition, Time.deltaTime * returnSpeed);
}

Any idea what I am doing wrong here? And how to get my desired action?

Thank you

Upvotes: 2

Views: 568

Answers (1)

Ben Rubin
Ben Rubin

Reputation: 7371

Calling MoveTowards once only moves the game object once during that iteration of the game loop. Calling MoveTowards once doesn't move the game object all the way to its target (unless the maxDistanceDelta parameter is big enough to move the game object to its target in one iteration).

If the boss is instantly appearing at the target, I'm guessing your chargeSpeed is too big.

What you want to do is call MoveTowards once per Update cycle. However, the way you're doing your coroutine, the coroutine will only move the game object once and then exit. Normally coroutines will have a loop within them (otherwise the coroutine will exit after running once). Something like this:

IEnumerator TankCharge()
{
    while (Vector3.Distance(transform.position, chargeTarget.position) > Mathf.Epsilon)
    {
        // Adjust this so this game object doesn't move the entire
        // distance in one iteration
        float distanceToMove = Time.deltaTime * chargeSpeed;

        transform.position = Vector3.MoveTowards(transform.position, chargeTarget.position, distanceToMove)

        yield return null;
    }
}

However, for your situation, you don't really need a coroutine. You can just do this directly in Update()

    private bool returnToStart = false;
    private float timer;

    void Update
    {
        float distanceToMove = Time.deltaTime * chargeSpeed;

        if (timer <= 0)
        {
            if (!returnToStart)
            {
                transform.position = Vector3.MoveTowards(transform.position, chargeTarget.position, distanceToMove)

                // Target reached?  If so, start moving back to the original position
                if (Vector3.Distance(transform.position, chargeTarget.position) <= Mathf.Epsilon)
                {
                    returnToStart = true;
                    this.timer = this.chargeRate;
                }
            }
            else
            {
                transform.position = Vector3.MoveTowards(transform.position, tankStartPosition.position, distanceToMove)

                // Original position reached?  If so, start moving to the target
                if (Vector3.Distance(transform.position, tankStartPosition.position) <= Mathf.Epsilon)
                {
                    returnToStart = false;
                    this.timer = this.chargeRate;
                }
            }
        }
        else
        {
            this.timer -= Time.time;
        }
    }    

Upvotes: 1

Related Questions