Tutorial 15 - Movimiento-3D - (Primera Persona)
Fecha Miércoles, 05 septiembre a las 23:27:04
Tema DirectX/Opengl


Ya sólo nos falta pegar tiros. Vamos a ver el movimiento en primera persona, bien conocido en juegos tipo FPS (First Person Shooter).



Para llevar a cabo el movimiento en primera persona, nuestro personaje (m_Player) se moverá según las teclas del cursor y añadiremos un nuevo objeto (m_Camera) que cambiará su orientación según movamos el ratón.

El método CheckMovement() sufre bastantes cambios. Por un lado, m_Player se mueve según las teclas del cursor y por otro, m_Camera varía su matriz de transformación si se mueve el ratón. Al cambiar la orientación de la "cámara", variamos también la orientación de m_Player.

Se gira la cámara de arriba a abajo (giro sobre X) y de izquierda a derecha (giro en Y) en función del movimiento del ratón según los ejes X e Y de la pantalla. Dicho movimiento se aplica a la matriz de transformación.


    ///////////////////////////////////////////////////////////////////////////////
    ///     CheckMovement: Comprueba si hay pulsada una tecla.
    ///
    ///     @param  long msElapsed: misilegundos transcurridos entre cada frame.
    ///
    ///     @return  nada
    ///////////////////////////////////////////////////////////////////////////////
    void GraphicApplication::CheckMovement( long msElapsed )
    {
        float speed= m_Player.GetSpeed();
    // ********************************* NEW **************************************
        float angleX, angleY;

        if ( m_KeysPressed[KEY_UP] || m_KeysPressed[''W''] || m_KeysPressed[''w''] )
        {
            m_Player.Forward( speed * msElapsed );      // Avance
        }
        else if ( m_KeysPressed[KEY_DOWN] || m_KeysPressed[''S''] || m_KeysPressed[''s''] )
        {
            m_Player.Forward( -speed * msElapsed );     // Retroceso
        }

        if ( m_KeysPressed[KEY_LEFT] || m_KeysPressed[''A''] || m_KeysPressed[''a''] )
        {
            // Izquierda
            if ( m_pVideoDriver->GetAxisSystem() == eRightHanded )
                m_Player.Strafe( -speed * msElapsed );
            else
                m_Player.Strafe(  speed * msElapsed );
        }
        else if ( m_KeysPressed[KEY_RIGHT] || m_KeysPressed[''D''] || m_KeysPressed[''d''] )
        {
            // Derecha
            if ( m_pVideoDriver->GetAxisSystem() == eRightHanded )
                m_Player.Strafe(  speed * msElapsed );
            else
                m_Player.Strafe( -speed * msElapsed );
        }

        // Si ha cambiado de posición
        if ( (m_MousePosition.x != m_MiddleWindow.x) || (m_MousePosition.y != m_MiddleWindow.y) )
        {
            angleY = (float)( m_MiddleWindow.x - m_MousePosition.x ) / 10.0f;
            angleX = (float)( m_MiddleWindow.y - m_MousePosition.y ) / 10.0f;

            // Movimiento del ratón en eje Y de pantalla, giro en eje X en 3D
            m_Camera.Pitch( -angleX );

            // Movimiento del ratón en eje X de pantalla, giro en eje Y en 3D   
            if ( m_pVideoDriver->GetAxisSystem() == eRightHanded )
                m_Camera.Yaw(  angleY );
            else
                m_Camera.Yaw( -angleY );

            // En el vector Up no debemos dejar que varíe el valor X y el Z,
            // porque si no, se nos inclina el eje Y hacia los lados.
            m_Camera.GetRefLocalMatrix().SetUpVector(Vector3(0,1,0));

            // Hacemos los ejes perpendiculares.
            m_Camera.UpdateAxis();

            // Hacemos la dirección de avance de m_Player sea dónde mira la cámara
            Vector3 vForwardCamera= m_Camera.GetLocalMatrix().GetForwardVector();

            // No permitimos que se eleve del suelo.
            vForwardCamera.y= 0;

            // Actualizamos nuestra orientación.
            m_Player.SetOrientation ( m_Player.GetPosition() - vForwardCamera, Vector3(0,1,0) );

            // Colocamos siempre el puntero del ratón en el centro de la pantalla
            System::SetMousePosition( m_MiddleWindow.x, m_MiddleWindow.y );
        }

    // ****************************************************************************
    }

La función SetMousePosition(), está definida en el módulo system, que tiene diferentes implementaciones (en winsystem.cpp y linuxsystem.cpp). Esto depende de si se genera el proyecto para Windows, Glut o SDL; ya que para cada una hay una forma distinta de fijar la posición del puntero del ratón. La verdad es que ha sido un quebradero de cabeza conseguir que funcionase para los tres, pero al final lo he conseguido.

Finalmente, en el método OnRender(), el punto de vista será una combinación entre la posición de m_Player y la orientación (a dónde mira) m_Camera.


    // ********************************* NEW **************************************
            vPosition= m_Player.GetPosition() + m_Camera.GetPosition();
            vUp      = m_Camera.GetLocalMatrix().GetUpVector();
            vLook    = vPosition - m_Camera.GetLocalMatrix().GetForwardVector();
            m_pVideoDriver->LookAt( vPosition, vLook, vUp );
    // ****************************************************************************

Podéis descargaros el ejemplo: tutorial-15.zip



Compartir en Facebook



Este artículo proviene de Programacion Grafica: Desarrollo 2D/3D con C++ y DirectX/OpenGL/GLUT/SDL - Windows/Linux
http://www.programaciongrafica.com

La dirección de esta noticia es:
http://www.programaciongrafica.com/modules.php?name=News&file=article&sid=16