Lerping within OnCollisionEnter

Upon detecting collision on a button, I need the child object called Button to move down smoothly but quickly by 0.05 (-Y), but I know that both Lerp and MoveTowards have to be located within an Update function, I am looking for a little information on the best way to go about doing this.

I need to be able to move the button down so much when OnCollisionEnter is called, but also to be able to move it back up by that much when OnCollisionExit is called.

while is a magical keyword :wink:

You can’t use while just like that in OnCollisionEnter, you would just see the final result instantly as it all happens within the same frame.

Kyle, you’ll have to either work with a coroutine, or use animations.

Heh, can you please explain why not?

OnCollisionEnter() is called within a single frame. If you perform a loop within said frame, you will not see the targeted object move, as the output of each loop is not displayed on screen. Instead, you will see the final result after the entire loop has completed.

1 Like

UPDATE:

Using coroutine now, thanks for the help.

I now have another, related issue though; When using the coroutine (and Vector3.MoveTowards) I get rather odd results.

When the button object is pushed down, it goes a lot further than it should, and depending on the value of moveSpeed, it vibrates as well.
Additionally, once the tagged object is removed from the button, the button piece does not move back up to the determined position, it remains where it was placed (in the down position, further than it should).

using UnityEngine;
using System.Collections;

public class WeightedButton : MonoBehaviour
{

    public GameObject connectedObject;
    public GameObject buttonObject;
    public Vector3 buttonOrigin = new Vector3(0f, 0.1f, 0f);
    public Vector3 buttonTarget = new Vector3(0f, 0.05f, 0f);
    public float moveSpeed;

    void OnCollisionEnter(Collision other)
    {
        StartCoroutine(MoveDown(buttonTarget));

        if (other.gameObject.tag == "Box" || other.gameObject.tag == "Player")
        {
            if (connectedObject.GetComponent<Barrier>().enabled == true)
            {
                Barrier barrierObject = connectedObject.gameObject.GetComponent<Barrier>();
                barrierObject.state = Barrier.State.Inactive;
            }

            else
            {
                Barrier barrierObject = connectedObject.gameObject.GetComponent<Barrier>();
                barrierObject.state = Barrier.State.Active;
            }
        }
    }

    void OnCollisionExit(Collision other)
    {
        StartCoroutine(MoveUp(buttonOrigin));

        if (other.gameObject.tag == "Box" || other.gameObject.tag == "Player")
        {
            if (connectedObject.GetComponent<Barrier>().enabled == true)
            {
                Barrier barrierObject = connectedObject.gameObject.GetComponent<Barrier>();
                barrierObject.state = Barrier.State.Active;
            }
        }
    }

    IEnumerator MoveDown(Vector3 target)
    {
        while (buttonObject.transform.position != target)
        {
            buttonObject.transform.position = Vector3.MoveTowards(transform.position, target, moveSpeed * Time.deltaTime);
            yield return 0;
        }
    }

    IEnumerator MoveUp(Vector3 origin)
    {
        while (buttonObject.transform.position != origin)
        {
            buttonObject.transform.position = Vector3.MoveTowards(transform.position, origin, moveSpeed * Time.deltaTime);
            yield return 0;
        }
    }
}

Something like so:

using UnityEngine;

public class CollisionOffset : MonoBehaviour {

    //settable in inspector. This is the local offset by which
    //the button will lerp to, on impact.
    [SerializeField] Vector3 offset = Vector3.forward * 0.05f;

    //Will hold the original localPosition, so that the localTransform
    //can be set to it's offset according to it's original.
    Vector3 original = Vector3.zero;

    //settable in inspector. This is the speed by which the button will apply its lerp
    [SerializeField, Range(0.5f,5f)] float speed = 1f;

    //Our state keeper. At magnitude 1f, our button is at it's offset.
    //at magnitude 0f, not offset at all.
    float magnitude = 0f;

    //determins weather or not the offset should be applied.
    bool applyOffset = false;

    void OnCollisionEnter(Collision other)
    {
        applyOffset = true;       
    }

    void OnCollisionExit(Collision other)
    {
        applyOffset = false;       
    }

    void Start()
    {
        original = transform.localPosition;
    }

    void Update()
    {
        float targetMagnitude = applyOffset ? 1f : 0f;
        magnitude = Mathf.Lerp(magnitude, targetMagnitude, Time.deltaTime * speed);

        transform.localPosition = original + offset * magnitude;
    }

}

You’re using transform.position in your MoveTowards(), instead of buttonObject.transform.position. Also, buttonOrigin and buttonTarget should be relative to the buttonObject’s position.

1 Like