Smoothly decrease/increase speed when on trigger object

Hi everybody,
what I want to do is gradually decrease the speed of my Player (a moving disc) as it moves on a Path, and gradually increase it when the Player exits the Path.
This is a mobile app and I’m using the acceleremeter to move the Player.

I tried using the Math.Smoothstep function but the result is that the speed decrease or increase without smoothing.

Here is the script of my Player object:

using UnityEngine;
using System.Collections;

public class MovePlayer : MonoBehaviour {

    // Speed multiplier
    public float speed;

    // FixedUpdate for physical objects
    void FixedUpdate () {
        transform.Translate (
            Input.acceleration.x * Time.deltaTime * speed,
            Input.acceleration.y * Time.deltaTime * speed,
            0);
    }

    // Collision control (requires RigidBody)
    void OnCollisionEnter2D(Collision2D obj){
        if (obj.gameObject.CompareTag ("Wall")) {
            Debug.Log ("Collision: Wall");
        }
    }

    // Player enters path
    void OnTriggerEnter2D(Collider2D obj){
        if (obj.gameObject.CompareTag ("Path")) {
            Debug.Log ("Trigger Enter: Path");
            speed = Mathf.SmoothStep (speed, speed / 2, 2);
        }
    }

    // Player exits path
    void OnTriggerExit2D(Collider2D obj){
        if (obj.gameObject.CompareTag ("Path")) {
            Debug.Log ("Trigger Exit: Path");
            speed = Mathf.SmoothStep (speed, speed * 2, 2);
        }
    }
}

Thanks in advance and have a good day!

That’s because you’re using SmoothStep erroneously. The calculation is done a single time on the trigger events and it doesn’t consider the time, thus the instant change.

The correct usage is at FixedUpdate, and it should be something like this:

currentSpeed = Mathf.SmoothStep(currentStep, targetSpeed, 2 * Time.deltaTime);

Thus, you would set targetSpeed at the triggers, then calculate and apply the new currentSpeed value. The “2” value defines how fast the transition is. You may want to expose it as public property as well for experimenting with the value.

5 Likes

Thank you very much for the answer, now it works!

If can be helpful, here is the working code:

using UnityEngine;
using System.Collections;

public class MovePlayer : MonoBehaviour {

    public float maxSpeed; // Maximum speed reachable
    public float minSpeed; // Minimum speed reachable
    public float duration; // Duration of the speed transition

    private float targetSpeed;
    private float currentSpeed;

    void Start(){
        // Setting the starting speed parameters
        currentSpeed = targetSpeed = maxSpeed;
    }
      
    void FixedUpdate () {
        transform.Translate (
            Input.acceleration.x * Time.deltaTime * currentSpeed,
            Input.acceleration.y * Time.deltaTime * currentSpeed,
            0);

        // Smooting the currentSpeed to the targetSpeed
        currentSpeed = Mathf.SmoothStep (currentSpeed, targetSpeed, duration * Time.deltaTime);
        Debug.Log ("Speed: " + currentSpeed);
    }

    // Player enters path
    void OnTriggerEnter2D(Collider2D other) {
        if (other.gameObject.CompareTag ("Path")) {
            Debug.Log ("Trigger Enter: Path");
            targetSpeed = minSpeed; // Setting the new speed to the minimum
        }
    }

    // Player exits path
    void OnTriggerExit2D(Collider2D other){
        if (other.gameObject.CompareTag ("Path")) {
            Debug.Log ("Trigger Exit: Path");
            targetSpeed = maxSpeed; // Setting the new speed to the maximum
        }
    }

    // Collision control (requires RigidBody)
    void OnCollisionEnter2D(Collision2D obj){
        if (obj.gameObject.CompareTag ("Wall")) {
            Debug.Log ("Collision: Wall");
        }
    }
}

It is not the most efficient way to do that because the Mathf.SmoothStep function is called even when it is not needed, but I think a simple check could solve the problem.

4 Likes