Smooth Acceleration and Deceleration

How can we create smooth acceleration and deceleration effects using time deltas?

Creating smooth acceleration and deceleration effects is a common requirement in game development, especially for character movement or vehicle simulations. By using time deltas, we can ensure these effects are consistent across different frame rates. Let's explore how to implement this:

Linear Acceleration

The simplest form of acceleration is linear. Here's how you can implement it:

#include <SDL.h>
#include <iostream>

class MovingObject {
private:
  float position = 0.0f;
  float velocity = 0.0f;

  // Units per second squared
  float acceleration = 5.0f;

  // Maximum velocity
  float maxVelocity = 10.0f;

public:
  void update(float dt) {
    // Apply acceleration
    velocity += acceleration * dt;

    // Clamp velocity to maximum
    if (velocity > maxVelocity) velocity =
      maxVelocity;

    // Update position
    position += velocity * dt;

    std::cout << "Position: " << position <<
      ", Velocity: " << velocity << "\n";
  }
};

int main(int argc, char** argv) {
  SDL_Init(SDL_INIT_VIDEO);
  MovingObject obj;
  Uint64 previousTime = SDL_GetTicks64();

  for (int i = 0; i < 100; ++i) {
    Uint64 currentTime = SDL_GetTicks64();
    float dt = (currentTime - previousTime) /
      1000.0f;
    previousTime = currentTime;

    obj.update(dt);

    SDL_Delay(16); // Simulate ~60 FPS
  }

  SDL_Quit();
  return 0;
}
Position: 0, Velocity: 0
Position: 0.001445, Velocity: 0.085
Position: 0.004335, Velocity: 0.17
Position: 0.008335, Velocity: 0.25
Position: 0.01403, Velocity: 0.335
Position: 0.02067, Velocity: 0.415
...

This creates a linear acceleration effect. The object starts from rest and gradually increases its speed until it reaches the maximum velocity.

Smooth Acceleration and Deceleration

For a smoother, more natural-feeling acceleration and deceleration, we can use easing functions. One common approach is to use a sigmoid function:

#include <SDL.h>
#include <cmath>
#include <iostream>

class SmoothMovingObject {
private:
  float position = 0.0f;
  float targetPosition = 100.0f;
  // Maximum speed
  float maxSpeed = 50.0f;
  // Higher values make the motion smoother
  float smoothness = 2.0f;

public:
  void update(float dt) {
    float distanceToTarget = targetPosition -
      position;
    float speed =
      maxSpeed *
      (2 / (1 + std::exp(
        -smoothness * distanceToTarget /
        maxSpeed)) - 1);

    position += speed * dt;

    std::cout << "Position: " << position <<
      ", Speed: " << speed << "\n";
  }
};

int main(int argc, char** argv) {
  SDL_Init(SDL_INIT_VIDEO);
  SmoothMovingObject obj;
  Uint64 previousTime = SDL_GetTicks64();

  for (int i = 0; i < 600; ++i) {
    Uint64 currentTime = SDL_GetTicks64();
    float dt = (currentTime - previousTime) /
      1000.0f;
    previousTime = currentTime;

    obj.update(dt);

    SDL_Delay(16); // Simulate ~60 FPS
  }

  SDL_Quit();
  return 0;
}

This implementation uses a sigmoid function to create a smooth S-curve for acceleration and deceleration. In this example, the object decelerates as it approaches the target position.

Position: 0, Speed: 48.2014
Position: 0.819423, Speed: 48.2014
Position: 1.63785, Speed: 48.1426
Position: 2.45524, Speed: 48.0819
Position: 3.27157, Speed: 48.0194
...

Interpolation for Smooth Movement

Another approach is to use interpolation, which can create very smooth movement between two points:

#include <SDL.h>
#include <iostream>

class InterpolatingObject {
private:
  float startPosition = 0.0f;
  float endPosition = 100.0f;

  // Interpolation factor
  float t = 0.0f;

  // Time to complete the movement
  float duration = 2.0f;

public:
  void update(float dt) {
    t += dt / duration;
    if (t > 1.0f) t = 1.0f;

    // Smooth step function for easing
    float smoothT = t * t * (3 - 2 * t);

    float position = startPosition + (
      endPosition - startPosition) * smoothT;

    std::cout << "Position: " << position <<
      ", T: " << t << "\n";
  }
};

int main(int argc, char** argv) {
  SDL_Init(SDL_INIT_VIDEO);
  InterpolatingObject obj;
  Uint64 previousTime = SDL_GetTicks64();

  while (true) {
    Uint64 currentTime = SDL_GetTicks64();
    float dt = (currentTime - previousTime) /
      1000.0f;
    previousTime = currentTime;

    obj.update(dt);

    SDL_Delay(16); // Simulate ~60 FPS

    // Stop after 2 seconds
    if (dt >= 2.0f) break;
  }

  SDL_Quit();
  return 0;
}
Position: 0, T: 0
Position: 0.0215522, T: 0.0085
Position: 0.0807766, T: 0.0165
Position: 0.184375, T: 0.025
...
Position: 99.9332, T: 0.985
Position: 99.9874, T: 0.9935
Position: 100, T: 1

This method uses a smooth step function to interpolate between the start and end positions, creating a smooth acceleration and deceleration effect.

By using these techniques with time deltas, you can create smooth, frame-rate independent acceleration and deceleration effects in your games. Remember to experiment with different easing functions and parameters to find the feel that best suits your game's needs.

Tick Rate and Time Deltas

Learn how to create smooth, time-aware game loops that behave consistently across different hardware configurations

Questions & Answers

Answers are generated by AI models and may not have been reviewed. Be mindful when running any code on your device.

Handling Large Time Deltas
How can we handle very large time deltas that might occur if the game is paused or minimized?
Fixed vs Variable Time Step
What are the pros and cons of using a fixed time step versus a variable time step?
Different Update Rates for Game Objects
Is it possible to have different objects in the game world update at different rates?
Alternatives to SDL_Delay()
What are some alternatives to SDL_Delay() for more precise timing control?
Or Ask your Own Question
Purchase the course to ask your own questions