0
\$\begingroup\$

As the title says, I am having an issue with prefabs: I am trying to make a bullet follow a curve and then hit a target using this method:

private IEnumerator BezierShooting()
{
    GameObject shotInstance = new GameObject();
    shotInstance = Instantiate(shotPrefab, transform.position, Quaternion.identity);
    Vector3 currentPosition = new Vector3();
    if (shotInstance != null)
    {
        while (t < 1 && shotInstance != null)
        {
            currentPosition = Mathf.Pow(1 - t, 3) * controlPoint0.position +
                            3 * Mathf.Pow(1 - t, 2) * t * controlPoint1.position +
                            3 * (1 - t) * Mathf.Pow(t, 2) * controlPoint2.position +
                            Mathf.Pow(t, 3) * controlPoint3.position;
            Debug.Log(currentPosition);
            shotInstance.transform.position = currentPosition;
            t += 0.02f;
            yield return new WaitForEndOfFrame();
        }
    }
    else
    {
        currentPosition = transform.position;
        t = 0;
        yield break;
    }

}

Where t is a float variable that I initialised before as well as the transforms controlPoint0, controlPoint1, controlPoint2 and controlPoint3.

The bullet is succesfully following the path that I created, however the problem is that once the bullet hits an object in position (x, y, z) and gets destroyed, if I call the method again the prefab will spawn in the last position it was on. I thought that final else statement would do the trick, but appearantly I am missing something. Can somebody help me please?

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

It looks like you want this:

private IEnumerator BezierShooting()
{
    var shotInstance = Instantiate(shotPrefab, transform.position, Quaternion.identity);
    while (t < 1 && shotInstance != null)
    {
        float invT = 1f - t;
        var currentPosition = invT * invT * invT * controlPoint0.position
                            + 3 * invT*invT * t  * controlPoint1.position
                            + 3 * invT * t * t   * controlPoint2.position
                            +     t * t * t      * controlPoint3.position;
        Debug.Log(currentPosition);
        shotInstance.transform.position = currentPosition;
        t += Time.deltaTime/bezierDuration;
        yield return null;
    }

    t = 0;
}

Some mistakes I corrected above:

  • Don't create a new GameObject() you never use, only to replace the reference with the result of Instantiate.

  • Your while already doubles as an if, so you don't need to wrap it in an if.

  • You want t = 0 to execute once you're done no matter what, so don't restrict it to an else branch. (Or, if you don't use t outside this coroutine, you could just make it a temporary variable in this method, initialized at the start, so you don't need to do anything to reset it later)

  • currentPosition = transform.position doesn't accomplish anything - it's a temporary variable that's about to be thrown out when we end this coroutine anyway.

  • Mathf.Pow() is generally more expensive than a multiplication, if all you need is a low power.

  • You'll want to use Time.deltaTime to get a consistent speed along this curve regardless of frame rate.

\$\endgroup\$
  • \$\begingroup\$ It works like a charm, you are great! I am still not understanding why, if the temporary variable currentPosition would have been thrown away, the position of the following bullet is the last taken from the previous one, even if I have stated to be the original position i.e. the player's? \$\endgroup\$ – FSic Aug 3 at 18:39
  • 1
    \$\begingroup\$ You left t >=1, because the line of code that reset it was only in an else branch that your code decided not to take on the first iteration. You never told it to consider the else branch again after that. \$\endgroup\$ – DMGregory Aug 3 at 18:41

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.