Skip to main content
GameDev.net gamedev.net
🔒 Locked

Framerate Independent Mouse Movement

Started by mojobojo May 14, 2016 at 4:29 PM 8 replies 4.4k views
Original Post
mojobojo
mojobojo

I am polling for input every frame from my application using SDL_PollEvent. When I recieve a mouse motion event I set the relative mouse position


// Other input code      
PlayerInput->RelMousePos.x = (f32)SdlEvent->motion.xrel;
PlayerInput->RelMousePos.y = (f32)SdlEvent->motion.yrel;
// Other input code

In my game loop I handle the input like so


f32 MouseXRatio = PlayerInput->RelMousePos.x / GameState->CurrentResolution.Width;
f32 MouseYRatio = PlayerInput->RelMousePos.y / GameState->CurrentResolution.Height;

f32 Units = 64.0f;
v3 Amount = v3(-MouseYRatio, MouseXRatio, 0.0f) * Units;
GameState->CameraRot += Amount;
// Rotate the view matrix

The camera rotates fine, feels good to move, etc. However, when I turn on vsync the sensitivity of the camera goes down. I am a little stuck on how to handle this.

Sponji
Sponji

You're probably adding the mouse motion to camera's rotation multiple times per frame? It should be done just once, so you could try resetting RelMousePos to zero after you've used it.

Derp
mojobojo
mojobojo

You're probably adding the mouse motion to camera's rotation multiple times per frame? It should be done just once, so you could try resetting RelMousePos to zero after you've used it.

It gets reset to zero before the input poll.


internal void
ProcessEvents(game_state *GameState) {
    SDL_Event SdlEvent;
    player_input *PlayerInput = &GameState->Input.PlayerInputs[0];
    PlayerInput->RelMousePos = v3(0.0f, 0.0f, 0.0f);

    while (SDL_PollEvent(&SdlEvent)) {
        ProcessSdlInputEvents(PlayerInput, &SdlEvent);
        switch (SdlEvent.type) {
            case SDL_QUIT: {
                GlobalRunning = false;
                break;
            }
            case SDL_WINDOWEVENT: {
                if (SdlEvent.window.event == SDL_WINDOWEVENT_SIZE_CHANGED) {
                    i32 Width = SdlEvent.window.data1;
                    i32 Height = SdlEvent.window.data2;
                    GameState->CurrentResolution.Width = Width;
                    GameState->CurrentResolution.Height = Height;
                }
                break;
            }
            default: {
                break;
            }
        }
    }
}

I know why I am getting the extra motion I am just drawing a blank on how to compensate for it. For example say I am running 60fps and move the mouse for 1 second,

if the input poll puts RelMousePos to 5 that's 60*5 I am going to process, if its 120fps that is 120*5 which means its going to move farther. Initial thought was compensating for time with my frame dt (Units * DeltaTime) which makes the mouse motion feel really bad.

Sponji
Sponji

Yeah, but you're still applying the motion multiple times, and you shouldn't even use delta time for that. If I move my mouse by X amount, I want it to rotate my camera by Y degrees, it doesn't matter how many frames or seconds it took. You can even try it by moving the rotation code directly in the event handling. And you could still add some lerping on top of that code if that's what you're looking for. Like smoothed_rotation = slerp(smoothed_rotation, actual_rotation, delta) or something, and that should happen in the frame update.

Derp
mojobojo
mojobojo

So what you are saying is I should get the relative mouse position on a frame and move a certain amount and once that amount has been moved that is when I look at the mouse relative position again? So even if sdl gives me another xrel and yrel on the second frame, ignore it?

Sponji
Sponji

You don't ignore it, it's an event. You get the event and you process the values from it.


void events() {
    SDL_Event event;
    while(SDL_PollEvent(&event)) {
        switch(event.type) {
            case SDL_MOUSEMOTION: {
                // Ooh, the mouse was moved, let's apply the motion.
                GameState->CameraRot += v3(event.motion.yrel, event.motion.xrel, 0.0f);
            } break;
        }
    }
}

void update() { ... }
void render() { ... }

void mainloop() {
    while(running) {
        events();
        update();
        render();
    }
}
Derp
mojobojo
mojobojo

What you put there is what I am doing. I am saying SDL gives me back a non zero value for more than one frame.

EDIT: Correction, similar to what I am doing. I am setting the rotation inside the update loop, does that matter?

Sponji
Sponji

I am setting the rotation inside the update loop, does that matter?

That's what I've been trying to say, I don't know about all the code you have but I'm guessing you're adding the same input multiple times.

Derp
Norman Barrows
Norman Barrows

theoretically, you should simply be able to render, getmouse(), then update, and everything should work fine, at any framerate.

Norm Barrows Rockland Software Productions "Building PC games since 1989"</
mojobojo
mojobojo

That appears to have done the trick. Thank you very much.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.