0

As mentioned previously, the code supposed to keep the pipes (called Top and bottom) moving while they are opening doesn´t seem to do anything but snap them right into the desired eventual position, with no animation Here's the full code of this part (Including the part that makes pipes move regularly).

System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;
using static UnityEditor.PlayerSettings;

public class PipeMove : MonoBehaviour
{
    public float deadZone= -15;
    public float MoveSpeed;
    public BorbPhysics borb;
    public float DeathMoveSpeed = 1;
    public GameObject Top;
    public GameObject Bottom;
    public float Offset = 5;
    private Vector3 TopStartPoint;
    private Vector3 TopEndPoint;
    private Vector3 BottomStartPoint;
    private Vector3 BottomEndPoint;
    public float desiredDuration = 3f;
    private float elapsedTime;
    public float TxCons;
    public float TyStart;
    public float BxCons;
    public float ByStart;
    public bool IsOpening = false;
    public float XOf = 4;
    public float TEnd;
    public float BEnd;
    public bool hasSet = false;
    private AnimationCurve curve;

    // Start is called before the first frame update
    void Start()
    {
        borb = GameObject.FindGameObjectWithTag("borb").GetComponent<BorbPhysics>();

        TyStart = Top.transform.position.y;
        ByStart = Bottom.transform.position.y;
    }

    // Update is called once per frame
    void Update()
    {
        TxCons = Top.transform.position.x;
        BxCons = Bottom.transform.position.x;

        TopStartPoint = new Vector3(TxCons, TyStart, 0);
        TopEndPoint = new Vector3(TEnd, TyStart + Offset, 0);
        BottomStartPoint = new Vector3(BxCons, ByStart, 0);
        BottomEndPoint = new Vector3(BEnd, ByStart - Offset, 0);

        if (borb.BorbIsAlive == true)
        {
            transform.position = transform.position + (Vector3.left * MoveSpeed) * Time.deltaTime;
        }
        if (transform.position.x < deadZone)
        {
          Destroy(gameObject);
        }

        if (borb.BorbIsAlive == false)
        {
            transform.position = transform.position + (Vector3.left * DeathMoveSpeed) * Time.deltaTime;
        }
        if (IsOpening && hasSet == false)
        {
            TEnd = Top.transform.position.x + (-1 * MoveSpeed) * desiredDuration;
            BEnd = Bottom.transform.position.x + (-1 * MoveSpeed) * desiredDuration;
            hasSet = true;
        }
        if (IsOpening == false)
        {
            hasSet = false;
        }

        if (Input.GetKeyDown(KeyCode.W))
        {
            IsOpening = true;
        }
        if (IsOpening)
        { 
            elapsedTime += Time.deltaTime;
            float percentageComplete = elapsedTime / desiredDuration;

            Top.transform.position = Vector3.Lerp(TopStartPoint, TopEndPoint, percentageComplete);
            Bottom.transform.position = Vector3.Lerp(BottomStartPoint, BottomEndPoint, percentageComplete);

            if (percentageComplete >= 1)
            {
                elapsedTime = 0f;
                IsOpening = false;
            }
        }
    }
}

I have mostly explained the issue already, but to clarify completely, the 2D game is kind of a flappy bird where you need to pick up balloons to open the pipes(I will add that later), which are obviously moving, through Vector3.Lerp. The expected result was to see the pipes smoothly open as they move along the screen. Instead, they just appear where they should eventually reach and then display the opening animation (all of this while the pipe isn´t moving, since it waits for the opening animation to end to continue moving, again, for some reason). I don`t understand why it doesnt seem to work, and I have already watched countless Lerp tutorials but none of them seem to use it when the objects in question are moving.

2 Answers2

0

Put this part

TxCons = Top.transform.position.x;
BxCons = Bottom.transform.position.x;

TopStartPoint = new Vector3(TxCons, TyStart, 0);
TopEndPoint = new Vector3(TEnd, TyStart + Offset, 0);
BottomStartPoint = new Vector3(BxCons, ByStart, 0);
BottomEndPoint = new Vector3(BEnd, ByStart - Offset, 0);

Inside the Start function and try. You should not update the start position every frame when using lerp.

Vionix
  • 570
  • 3
  • 8
0

In

Top.transform.position = Vector3.Lerp(TopStartPoint, TopEndPoint, percentageComplete);

you are actively changing the position of Top. So in the next frame when you read

TxCons = Top.transform.position.x;

and update

TopStartPoint = new Vector3(TxCons, TyStart, 0);
TopEndPoint = new Vector3(TEnd, TyStart + Offset, 0);

you are now using different start and end points for your next call to

Top.transform.position = Vector3.Lerp(TopStartPoint, TopEndPoint, percentageComplete);

=> As already mentioned here it is probably enough to calculate the positions once which would already solve that part of the issue.


Further your other issue of running them in parallel is that the Vector3.Lerp overrules the entire position - including the X axis which was supposed to be the leftward movement.

=> You should separate the movement on the X axis from the opening animation on the Y axis!

For a bit better control I would use a Coroutine and do something like e.g.

void Update()
{
    // simplify your movement cases using a ternary 
    transform.position += Vector3.left * (borb.BorbIsAlive ? MoveSpeed : DeathMoveSpeed) * Time.deltaTime);
    
    if (transform.position.x < deadZone)
    {
        Destroy(gameObject);
        // can return in that case
        return;
    }

    // the entire "hasSet" logic becomes redundant

    if (!IsOpening && Input.GetKeyDown(KeyCode.W))
    {
        // start a coroutine that runs "in parallel" 
        // (actually one yield step every frame right after Update)
        StartCoroutine(OpenRoutine());
    }
}

private IEnumerator OpenRoutine()
{
    // just a bit of redundant safety check to really make sure only one 
    // routine runs at a time for this object 
    if(IsOpening) yield break;
    IsOpening = true;

    // get the current Y axis positions ONCE
    var topY = Top.transform.position.y;
    var bottomY = Top.transform.position.y;
    // calculate the target Y axis values ONCE
    var topYEnd = topY + offset;
    var bottomYEnd = bottomY - offset;

    // iterate for the desired duration
    for(var timePassed = 0f; t < desiredDuration; timePassed += Time.deltaTime)
    {
        var percentageComplete = timePassed / desiredDuration;
        // [optional] add ease-in and -out
        //percentageComplete = Mathf.SmoothStep(0f, 1f, percentageComplete);

        // now every frame ONLY overwrite the Y axis component
        // keeping the X axis movement untouched
        var topPosition = Top.transform.position;
        topPosition.y = Mathf.Lerp(topY, topYEnd, percentageComplete);
        Top.transform.position = topPosition;

        var bottomPosition = Bottom.transform.position;
        bottomPosition.y = Mathf.Lerp(bottomY, bottomYEnd, percentageComplete);
        Bottom.transform.position = bottomPosition;
      
        // "Pause" the routine here, fender this frame 
        // and continue from here in the next frame 
        yield return null;
    }

    // apply the final values hard to ensure you end up with clean values
    // in your use case probably optional though 
    var finalTop = Top.transform.position;
    finalTop = topYEnd;
    Top.transform.position = finalTop;

    var finalBottom = Bottom.transform.position;
    finalBottom = bottomYEnd;
    Bottom.transform.position = finalBottom;

    // as to my understanding once opened the animation shouldn't repeat anyway
    // so there is no need to reset the IsOpening flag, you run the routine only exactly once
}
derHugo
  • 83,094
  • 9
  • 75
  • 115