For loop to simulate deceleration

Hello all! I am making a simple topographic view 2D game, and I am trying to simulate the effect of deceleration in the characters movement. My Left, Right, Up, and Down controls work fine, but the character stops immediately after I lift my hand instead of gliding for a small bit. My initial idea was to have a for loop that called a function which decreased the value of “decspeed” by one then transformed the character by that number. So the character would move once by 3, then quickly thereafter by 2, until 0. However, this is not working and I was wondering if anyone could tell me why.

	public float speed = 1.5f;
	public int decspeed = 3;;
	//public Rigidbody2D rb;

	// Use this for initialization
	void Start () {

		//rb = GetComponent <Rigidbody2D>();

	}

	int DecreaseSpeed(int number){
		int ret;

		ret = number - 1;

		return ret;
	}
	
	// Update is called once per frame
	void FixedUpdate() {

		if (Input.GetKey (KeyCode.LeftArrow)) 
		{

			transform.position += Vector3.left * speed * Time.deltaTime;
			for (int i = 0; i = 3; i++)
			{
				transform.position += Vector3.left * decspeed * Time.deltaTime;
				DecreaseSpeed(decspeed);
			}
			//rb.velocity = new Vector2 (-5, 0);
		}

All the iterations of the for loop execute in the same frame, so you change the drawn position only once. You can use a for loop, but you need to make sure that only one iteration of the loop runs for a frame, then the second iteration for the next frame and so on.

The solution for this kind of things is using a coroutine, it could be something like this:

IEnumerator DecreaseSpeedLoop() {
    for (int i = 0; i = 3; i++)
    {
        transform.position += Vector3.left * decspeed * Time.deltaTime;
        DecreaseSpeed(decspeed);
        yield return null;
    }
}

And you’ll use this coroutine like this:

     void FixedUpdate() {
 
         if (Input.GetKey (KeyCode.LeftArrow)) 
         {
 
             transform.position += Vector3.left * speed * Time.deltaTime;
             StartCoroutine(DecreaseSpeedLoop());
         }
    }

Anyway, your code has more problems:

  • FixedUpdate will be called multiple times during the same frame, so you’ll end up starting the coroutine multiple times. You should check key states inside the Update function.

  • Input.GetKey returns true if the key is being held down during the current frame. In your case you’ll start the coroutine (or run the for loop) on every frame while the LeftArrow is being pressed. If the idea is to do it only when the LeftArrow is released you should use Input.GetKeyUp (inside the Update function).

  • You’re using Time.deltaTime (the duration of the whole frame) inside FixedUpdate (which is called multiple times during one frame). You should use Time.deltaTime inside Update, and Time.fixedDeltaTime inside FixedUpdate.

  • Your DecreaseSpeed function always returns “2” and you do nothing with that value. You’re calling it passing decspeed (initialized with “3”) and nothing changes it’s value. Maybe this helps, but I’d do it in a completelly different way:

    for (int i = 0; i = 3; i++)
    {
    transform.position += Vector3.left * decspeed * Time.deltaTime;
    decspeed = DecreaseSpeed(decspeed);
    }

The problem with this is that decspeed won’t go back to 3 for the next time you want to “break”, so maybe you should do this:

for (int i = decspeed; i > 0; i--)
{
    transform.position += Vector3.left * i * Time.deltaTime;
    yield return null;
}

Also, note that your for loop (for (int i = 0; i = 3; i++)) doesn’t make sense, the middle (your “i = 3”) should be a condition, it should be “i == 3” or something similar (I’ll be surprissed if that compiles).

Note that I was just traying to make your code work, but I’d do this differently, the rigidbody approach with velocity and drag on surfaces looks like the cleanest way.