0

I am attempting to use quadratic interpolation in order to throw a rock at the player's position. The rock simply follows the curve. However, if the player moves, the rock begins to loop and starts back at its original position. I have stopped the rock following the curve once it reaches the end of the curve and add force to the rock's rigidbody but it only works in specific examples. I was wondering if there was a way to extend the curve so the rock hits the ground and destroys itself using the code I already have. The code I am using is below. Thanks in advance. The code is below.

Quadratic Interpolation Code (it is run every frame)

private void FollowQuadraticPath()
    {
        interpolateAmount = (interpolateAmount + Time.deltaTime) % 1f;
        pointAB.transform.position = Vector3.Lerp(transformerPosition, throwHeightPosition, interpolateAmount);
        pointBC.transform.position = Vector3.Lerp(throwHeightPosition, playerPosition, interpolateAmount);

        transform.position = Vector3.Lerp(pointAB.transform.position, pointBC.transform.position, interpolateAmount);
    }

Damage

    private void OnCollisionEnter2D(Collision2D collision)
    {
        if (collision.gameObject.GetComponent<PlayerHealth>())
        {
            Destroy(pointABInstance);
            Destroy(pointBCInstance);
            collision.gameObject.GetComponent<PlayerHealth>().DealDamage(damage);
            Destroy(gameObject);
        }
        else
        {
            Destroy(pointABInstance);
            Destroy(pointBCInstance);
            Destroy(gameObject);
        }
    }

This is what I want to happen. Pretending the player had moved, the rock would continue and hit the ground past the player point.

Instead, once again pretending the player wasn't there, the object is destroyed before it reaches the ground

Edit: Check comments of the answer for the solution I used

1 Answers1

2

I guess you are using FollowQuadraticPath() within Update so what happens is you always use it with the current updated position of the player.

Instead I would use a Coroutine. A Coroutine is somewhat like a temporary Update method so it has a clear start and end and you can have local variables that persist through all frames the routine is running and do something like e.g.

private IEnumerator FollowQuadraticPath()
{
    // Cash the target positions ONCE so they are not updated later
    var startAB = TransformerPosition;
    var targetAB = throwHeightPosition;
    var targetBC = playerPosition;

    // Iterates until 1 second has passed
    // linearly increasing interpolateAmount from 0 to 1    
    for(var interpolateAmount = 0f; interpolateAmount < 1f; interpolateAmount += Time.deltaTime)
    {
        pointAB.transform.position = Vector3.Lerp(startAB, targetAB, interpolateAmount);
        pointBC.transform.position = Vector3.Lerp(targetAB, targetBC, interpolateAmount);

        transform.position = Vector3.Lerp(pointAB.transform.position, pointBC.transform.position, interpolateAmount);

        // Tells Unity to "pause" the routine here, render this frame
        // and continue from here in the next frame
        yield return null;
    }

    // Destroy if it reaches the original player position
    Destroy (gameObject);
}

You run this ONCE e.g. in

private void Start ()
{
    StartCorouine(FollowQuadraticPath());
}

or Start can also be the routine itself like

private IEnumerator Start()
{
    var startAB = TransformerPosition;
    var targetAB = throwHeightPosition;

    .....
}

you don't have to worry about terminating the routine because it either reaches the original player position and is then destroyed or it hits the ground before and is destroyed. In either case the coroutine is automatically gone as well.


What I don't really get though is why you have 2 additional transforms for this. Why not simply only calculate with Vector3 itself like

var ab = Vector3.Lerp(startAB, targetAB, interpolateAmount);
var bc = Vector3.Lerp(targetAB, targetBC, interpolateAmount);

transform.position = Vector3.Lerp(ab, bc, interpolateAmount);
derHugo
  • 83,094
  • 9
  • 75
  • 115
  • I already cached cached transforms in the start functions so they wrrent updated. And, I'm not really sure about the 2 extra transforms. I was following a tutorial I found online. If I use a coroutine, I'll still have the same issue. Once it reaches the players position, the rock gameobject goes back to the original location and follows the path again. If it doesn't collide with the player, it would continue like that infinitely because the player is above the floor – Njal_Inferno Jul 29 '21 at 17:14
  • It would continue in a loop infinitely until the coroutine expired I mean – Njal_Inferno Jul 29 '21 at 17:22
  • Not if you use the Coroutine I show you here .. it terminates after the rock reaches the final position or is destroyed before that – derHugo Jul 29 '21 at 17:42
  • @Njal_Inferno did you actually try the code here before leaving this feedback? I don't see how it would do what you said it does unless there's major information missing from your question – Ruzihm Jul 29 '21 at 18:17
  • Yes, I did try the code. The code works, but it deletes the rock before it reaches the ground. If the player moves, the rock is deleted when the it reaches the players old position. However, the ground is below this and the rock doesn't reach the ground and is destroyed midair. I'm sorry if my question was unclear, I'm not very familiar with quadratic interpolation and how to phrase this question – Njal_Inferno Jul 29 '21 at 20:05
  • I have made amendments to the question, adding pictures and more of a description, in the hope that it makes it more clear – Njal_Inferno Jul 29 '21 at 20:24
  • In that case I would suggest to simply use a position on the ground as player position .. this way it always moves to the ground and if the player is still there it will hit the player before hitting the ground – derHugo Jul 29 '21 at 22:20
  • Ok, thank you very much for your help. And, thanks for the code, it works much better than my original code – Njal_Inferno Jul 30 '21 at 07:14