Adding physics to cursor movement can create interesting effects like momentum and weight. This is best achieved using custom cursor rendering rather than system cursors. Here's how to implement it:
Here’s an example of a PhysicsCursor
 class:
#include <SDL.h>
#include <cmath>
class PhysicsCursor {
public:
PhysicsCursor(
float maxSpeed = 1000.0f,
float acceleration = 2000.0f,
float friction = 5.0f
) : MaxSpeed{maxSpeed},
Acceleration{acceleration},
Friction{friction} {}
void Update(float deltaTime) {
// Get real mouse position
int mouseX, mouseY;
SDL_GetMouseState(&mouseX, &mouseY);
// Calculate target vector
float targetX{
static_cast<float>(mouseX) - PosX};
float targetY{
static_cast<float>(mouseY) - PosY};
// Apply acceleration towards target
float distance{std::sqrt(
targetX * targetX + targetY * targetY)};
if (distance > 0.1f) {
float dirX{targetX / distance};
float dirY{targetY / distance};
VelX += dirX * Acceleration * deltaTime;
VelY += dirY * Acceleration * deltaTime;
}
// Apply friction
VelX *= std::pow(Friction, deltaTime);
VelY *= std::pow(Friction, deltaTime);
// Clamp velocity to max speed
float speed{std::sqrt(
VelX * VelX + VelY * VelY)};
if (speed > MaxSpeed) {
float scale{MaxSpeed / speed};
VelX *= scale;
VelY *= scale;
}
// Update position
PosX += VelX * deltaTime;
PosY += VelY * deltaTime;
}
void Render(SDL_Renderer* renderer) {
// Draw cursor at physics-controlled position
SDL_SetRenderDrawColor(
renderer, 255, 255, 255, 255);
SDL_Rect cursorRect{
static_cast<int>(PosX - 8),
static_cast<int>(PosY - 8),
16, 16
};
SDL_RenderFillRect(renderer, &cursorRect);
}
private:
float PosX{400.0f}; // Start at screen center
float PosY{300.0f};
float VelX{0.0f};
float VelY{0.0f};
float MaxSpeed;
float Acceleration;
float Friction;
};
Here's how to integrate it into your game loop:
int main() {
SDL_Init(SDL_INIT_VIDEO);
SDL_Window* window{SDL_CreateWindow(
"Physics Cursor",
SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED,
800, 600, SDL_WINDOW_SHOWN
)};
SDL_Renderer* renderer{SDL_CreateRenderer(
window, -1, SDL_RENDERER_ACCELERATED)};
// Hide system cursor
SDL_ShowCursor(SDL_DISABLE);
PhysicsCursor cursor{500.0f, 2000.0f, 3.0f};
Uint32 lastTime{SDL_GetTicks()};
bool running{true};
while (running) {
SDL_Event event;
while (SDL_PollEvent(&event)) {
if (event.type == SDL_QUIT) {
running = false;
}
}
// Calculate delta time
Uint32 currentTime{SDL_GetTicks()};
float deltaTime{
(currentTime - lastTime) / 1000.0f};
lastTime = currentTime;
// Update and render
cursor.Update(deltaTime);
SDL_SetRenderDrawColor(
renderer, 0, 0, 0, 255);
SDL_RenderClear(renderer);
cursor.Render(renderer);
SDL_RenderPresent(renderer);
}
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}
The cursor's behavior can be tuned by adjusting the MaxSpeed
, Acceleration
, and Friction
 parameters.
Lower friction values create more "slippery" movement, while higher values make the cursor more responsive. Higher acceleration values make the cursor catch up to the real mouse position more quickly.
Answers to questions are automatically generated and may not have been reviewed.
Learn how to control cursor visibility, switch between default system cursors, and create custom cursors