Framerate Independent Mouse Movement

Started by
8 comments, last by mojobojo 7 years, 11 months ago

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.

Advertisement

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

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.

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

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?

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

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?

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

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"

rocklandsoftware.net

PLAY CAVEMAN NOW!

http://rocklandsoftware.net/beta.php

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

This topic is closed to new replies.

Advertisement