Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I made a camera in DX9. To move forward I press the Up arrow. To rotate on the Y axis I use the mouse. When I perform these movements on their own the camera moves at the speed I want.

However, if I hold down Up and move the mouse at the same time then the camera moves a lot faster than it should. I want it to move at the same speed as it does when only the Up arrow is pressed.

I think I need to normalize something somewhere but not sure what and not sure where. Have tried various combinations without success so if anyone can point me in the right direction that would be great.

Thanks.

My code

#define KEY_DOWN(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 1 : 0)

LRESULT WINAPI MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
    if( KEY_DOWN(VK_UP))    MovePlayer(D3DXVECTOR3(0, 0, -1.0f));
    if( KEY_DOWN(VK_DOWN))  MovePlayer(D3DXVECTOR3(0, 0, 1.0f));

    switch( msg )
    {
        case WM_MOUSEMOVE:
        ProcessMouseInput();
    }
}

void  MovePlayer( D3DXVECTOR3 in_vec )
{
    D3DXMATRIX CameraRot; 
    D3DXMatrixRotationY(&CameraRot,D3DXToRadian(AngleY));
    D3DXVECTOR3 CameraRotTarget;
    D3DXVec3TransformNormal(&CameraRotTarget,&in_vec,&CameraRot);
    CameraPos +=  (m_timeElapsed * CameraRotTarget);
}


void ProcessMouseInput()
{
    GetCursorPos( &CurrentMouseState );

    if ((CurrentMouseState.x != GameMouseState.x) || (CurrentMouseState.y != GameMouseState.y))        
    {
        int dx = CurrentMouseState.x - GameMouseState.x;                
        int dy = CurrentMouseState.y - GameMouseState.y;   
        AngleY+=m_timeElapsed*dx*7.0f;        
    }
    GameMouseState = CurrentMouseState;
    // Set back to window center in Render function
}

VOID UpdateCamera()
{ 
    D3DXVECTOR3 CameraOrigTarget(0, 0, -1); 
    D3DXVECTOR3 CameraOrigUp(0, 1, 0);

    D3DXMATRIX CameraRot; 
    D3DXMATRIX CameraRotX; 
    D3DXMatrixRotationX(&CameraRotX,D3DXToRadian(AngleX));
    D3DXMATRIX CameraRotY; 
    D3DXMatrixRotationY(&CameraRotY,D3DXToRadian(AngleY)); 
    CameraRot = CameraRotX * CameraRotY;
    D3DXVECTOR3 CameraRotTarget;
    D3DXVec3TransformNormal(&CameraRotTarget,&CameraOrigTarget,&CameraRot);

    D3DXVECTOR3 CameraTarget;
    CameraTarget = CameraPos + CameraRotTarget;  

    D3DXVECTOR3 vUpVec( 0.0f, 1.0f, 0.0f );
    D3DXMatrixLookAtLH( &matView, &CameraPos, &CameraTarget, &vUpVec );
    g_pd3dDevice->SetTransform( D3DTS_VIEW, &matView );

    D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI / 4, 1.0f, 1.0f, 100.0f );
    g_pd3dDevice->SetTransform( D3DTS_PROJECTION, &matProj );
}
share|improve this question
1  
Have you asked this question before? It sounds very familiar. –  Byte56 Jun 29 '12 at 13:41
    
-1. "Here's my code, please fix it." At least comment it. –  Anko Mar 9 '13 at 21:24
add comment

1 Answer

You're moving the camera twice, one for the mouse and one for the keyboard. The solution's to set a flag (b_moveUp, for example) in ProcessInput, and in your UpdateCamera "consume" it: if it's set move properly and then reset the flag.

Ok, let's do this properly.

The problem:
The movement's bound to the MsgProc function. You can't control the amount of windows messages you receive, so your speed depends on the user moving the mouse (and its resolution), the character repeat rate, and other foreign events. In order to fix this, we need to isolate these two different issues: detecting user input and applying the required movement.

A possible solution:
We need a way to transfer the input state to the update loop. We can do it like this:

// On MsgProc...  
if( KEY_DOWN(VK_UP)) {
    m_controller.moveForward();
} 
if( KEY_DOWN(VK_DOWN)) {
    m_controller.moveBackward();
}

// On update function...
m_controller.apply(m_timeElapsed);

// And this might be the implementation of the controller
class Controller {
public:
    void moveForward() {
        _directionFlags[Direction::FORWARD] = true;
    }

    void moveBackward() {
        _directionFlags[Direction::BACKWARD] = true;
    }

    void apply(float elapsed) {
        Vector3 offset {0, 0, 0};
        for (auto &flag : _directionFlags) {
            if (flag.second) { // If flag is set...
                offset += _offsets.at(flag.first); // Add the movement's offset.
                flag.second = false; // Reset the flag.
            }
        }
        offset *= elapsed;
        // TODO: Transform offset by rotations...
        // TODO: Apply offset to target entity...
    }
private:

    enum class Direction {
        FORWARD,
        BACKWARD
    };
    typedef std::map<Direction, bool> DirectionFlags;
    DirectionFlags _directionFlags;
    typedef std::map<Direction, Vector3> Offsets;
    const static Offsets _offsets;
};

const Controller::Offsets Controller::_offsets = {
    {Direction::FORWARD, {0, 0, -1.0f}},
    {Direction::BACKWARD, {0, 0, 1.0f}}
};
share|improve this answer
    
Welcome to GDSE, Pablo! You might want to provide more detail on exactly what is causing the problem (windows messages being received for both key input and mouse input), and also provide more detail on the solution. –  ktodisco Oct 30 '12 at 4:28
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.