Tutorial: adicionar controles move-look ao seu jogo DirectX

Applies to Windows only

Aprenda como adicionar controles move-look tradicionais usando o mouse e o teclado ao seu jogo DirectX.

Também é discutido o suporte a move-look para dispositivos sensíveis ao toque, com o controlador de movimento definido como a seção inferior esquerda da tela, que se comporta como uma entrada direcional, e o controlador de visão definido para o restante da tela, com a câmera centralizada no último lugar que o jogador tocou nessa área.

Se esse conceito de controle lhe parecer pouco familiar, pense nele da seguinte maneira: o teclado (ou a caixa de entrada direcional baseada no toque) controla suas pernas nesse espaço 3D, comportando-se como se suas pernas só pudessem se mover para a frente, para trás ou lateralmente para a esquerda e a direita. O mouse (ou o ponteiro de toque) controla a sua cabeça. Você usa sua cabeça para olhar em uma direção – para a esquerda, para a direita, para cima, para baixo ou para algum lugar dentro desse plano. Caso haja um alvo no seu campo de visão, você deve usar o mouse para centralizar o ponto de vista da câmera nesse alvo e então pressionar a tecla de avanço para se mover em sua direção ou a tecla de recuo para se afastar dele. Para girar em torno do alvo, você mantém o ponto de vista da câmera centralizado no alvo e, simultaneamente, move-se para a esquerda ou a direita. Como você pode perceber, esse é um método de controle extremamente eficaz para a navegação em ambientes 3D!

Em jogos, esses controles costumam ser chamados de controles WASD, nos quais as teclas W, S, A e D são usadas para movimentos da câmera fixos no plano x-z e o mouse é usado para controlar a rotação da câmera em torno dos eixos x e y.

Objetivos

  • Adicionar controles move-look básicos ao seu jogo DirectX, tanto para mouse e teclado como para telas sensíveis ao toque.
  • Implementar uma câmera em primeira pessoa usada para navegar em um ambiente 3D.

Uma observação sobre implementações de controle de toque

Para controles de toque, implementamos dois controladores: o controle de movimento, que se ocupa do movimento no plano x-z com relação ao ponto de vista da câmera; e o controlador de visão, que direciona o ponto de vista da câmera. O controlador de movimento é mapeado aos botões WASD do teclado e o controlador de visão é mapeado ao mouse. Entretanto, para controles de toque, precisamos definir uma região da tela que corresponda às entradas direcionais ou botões WASD virtuais, com o restante da tela servindo como espaço de entrada para os controles de visão.

Nossa tela tem a seguinte aparência.

o layout do controlador move-look

Quando você move o ponteiro de toque (não o mouse!) na região inferior esquerda da tela, qualquer movimento para cima faz a câmera mover-se para a frente. Qualquer movimento para baixo faz a câmera mover-se para trás. O mesmo se aplica aos movimentos para a esquerda e para a direita dentro do espaço do ponteiro do controlador de movimento. Fora desse espaço, a tela torna-se um controlador de visão – você simplesmente toca ou arrasta a câmera para onde deseja olhar.

Configurar a infraestrutura básica de eventos de entrada

Em primeiro lugar, temos que criar a classe de controle que usaremos para manipular os eventos de entrada provenientes do mouse e do teclado e atualizar a perspectiva da câmera com base nessa entrada. Como estamos implementando controles move-look, nós a chamamos de MoveLookController.


using namespace Windows::UI::Core;
using namespace Windows::System;
using namespace Windows::Foundation;
using namespace Windows::Devices::Input;

// Methods to get input from the UI pointers
ref class MoveLookController
{
};  // class MoveLookController

Agora criaremos um cabeçalho para definir o estado do controlador move-look e de sua câmera em primeira pessoa, além dos manipuladores de eventos e métodos básicos que implementarão os controles e a atualização do estado da câmera.



#define ROTATION_GAIN 0.004f	// sensitivity adjustment for look controller
#define MOVEMENT_GAIN 0.1f		// sensitivity adjustment for move controller

ref class MoveLookController
{
private:
    // properties of the controller object
    float3 m_position;			    // the position of the controller
    float m_pitch, m_yaw;			// orientation euler angles in radians

    // properties of the Move control
    bool m_moveInUse;			    // specifies whether the move control is in use
    uint32 m_movePointerID;		    // id of the pointer in this control
    float2 m_moveFirstDown;		    // point where initial contact occurred
    float2 m_movePointerPosition;   // point where the move pointer is currently located
    float3 m_moveCommand;		    // the net command from the move control

    // properties of the Look control
    bool m_lookInUse;			    // specifies whether the look control is in use
    uint32 m_lookPointerID;		    // id of the pointer in this control
    float2 m_lookLastPoint;		    // last point (from last frame)
    float2 m_lookLastDelta;		    // for smoothing

    bool m_forward, m_back;			// states for movement
    bool m_left, m_right;
    bool m_up, m_down;


public:

    // Methods to get input from the UI pointers
    void OnPointerPressed(
        _In_ Windows::UI::Core::CoreWindow^ sender,
        _In_ Windows::UI::Core::PointerEventArgs^ args
        );

    void OnPointerMoved(
        _In_ Windows::UI::Core::CoreWindow^ sender,
        _In_ Windows::UI::Core::PointerEventArgs^ args
        );

    void OnPointerReleased(
        _In_ Windows::UI::Core::CoreWindow^ sender,
        _In_ Windows::UI::Core::PointerEventArgs^ args
        );

    void OnKeyDown(
        _In_ Windows::UI::Core::CoreWindow^ sender,
        _In_ Windows::UI::Core::KeyEventArgs^ args
        );

    void OnKeyUp(
        _In_ Windows::UI::Core::CoreWindow^ sender,
        _In_ Windows::UI::Core::KeyEventArgs^ args
        );

    // set up the Controls that this controller supports
    void Initialize( _In_ Windows::UI::Core::CoreWindow^ window );

    // accessor to set position of controller
    void SetPosition( _In_ float3 pos );

    // accessor to set position of controller
    void SetOrientation( _In_ float pitch, _In_ float yaw );

    // returns the position of the controller object
    float3 get_Position();

    // returns the point  which the controller is facing
    float3 get_LookPoint();

    void Update( Windows::UI::Core::CoreWindow ^window );

};  // class MoveLookController

Nosso código contém quatro grupos de campos privados. Examinaremos a finalidade de cada um deles.

Primeiro, definimos alguns campos úteis para conter informações atualizadas sobre o ponto de vista da câmera.

  • m_position é a posição da câmera (e, portanto, do plano de visão) na cena 3D, usando coordenadas da cena.
  • m_pitch é a inclinação longitudinal da câmera, ou sua rotação para cima e para baixo em torno do eixo x do plano de visão, em radianos.
  • m_yaw é a direção da câmera, ou sua rotação para a esquerda e para a direita em torno do eixo y do plano de visão, em radianos.

Agora definiremos os campos que serão usados para armazenar informações sobre o status e a posição de nossos controladores. Primeiro definimos os campos necessários para o controlador de movimento baseado em toque. (A implementação do teclado como controlador de movimento não exige nada de especial. Simplesmente lemos os eventos de teclado com manipuladores específicos.)

  • m_moveInUse indica se o controlador de movimento está em uso.
  • m_movePointerID é o ID exclusivo do ponteiro de movimento atual. Nós o usamos para diferenciar o ponteiro de visão do ponteiro de movimento quando verificamos o valor do ID de ponteiro.
  • m_moveFirstDown é o ponto na tela onde o jogador tocou inicialmente a área de ponteiro do controlador de movimento. Esse valor será usado posteriormente para definir uma zona morta a fim de evitar que movimentos minúsculos façam o ponto de vista oscilar.
  • m_movePointerPosition é o ponto na tela para onde o jogador moveu atualmente o ponteiro. Nós o examinamos com relação a m_moveFirstDown para determinar em que direção o jogador deseja se mover.
  • m_moveCommand é o comando final calculado para o controlador de movimento: para cima (para a frente), para baixo (para trás), para a esquerda ou para a direita.

Agora definimos os campos que usaremos para o controlador de visão, nas implementações tanto de mouse como de toque.

  • m_lookInUse indica se o controle de visão está em uso.
  • m_lookPointerID é o ID exclusivo do ponteiro de visão atual. Nós o usamos para diferenciar o ponteiro de visão do ponteiro de movimento quando verificamos o valor do ID de ponteiro.
  • m_lookLastPoint é o último ponto, em coordenadas da cena, que foi capturado no quadro anterior.
  • m_lookLastDelta é a diferença calculada entre o m_position atual e m_lookLastPoint.

Finalmente, definimos seis valores booleanos para os seis graus de movimento, que usamos para indicar o estado atual de cada ação de movimento direcional (ativa ou inativa):

  • m_forward, m_back, m_left, m_right, m_up e m_down.

Usamos os seis manipuladores de eventos para capturar os dados de entrada empregados para atualizar o estado dos controladores:

  • OnPointerPressed. O jogador pressionou o botão esquerdo do mouse com o ponteiro na tela do jogo ou tocou na tela.
  • OnPointerMoved. O jogador moveu o mouse com o ponteiro na tela do jogo ou arrastou o ponteiro de toque na tela.
  • OnPointerReleased. O jogador liberou o botão esquerdo do mouse com o ponteiro na tela do jogo ou parou de tocar na tela.
  • OnKeyDown. O jogador pressionou uma tecla.
  • OnKeyUp. O jogador liberou uma tecla.

Finalmente, usamos esses métodos e propriedades para inicializar, acessar e atualizar as informações de estado dos controladores.

  • Initialize. O aplicativo chama esse manipulador de eventos para inicializar os controles e anexá-los ao objeto CoreWindow que descreve a janela de exibição.
  • SetPosition. O aplicativo chama esse método para definir as coordenadas (x, y e z) dos controles no espaço da cena.
  • SetOrientationO aplicativo chama esse método para definir a inclinação e a rotação da câmera.
  • get_Position. O aplicativo acessa essa propriedade para obter a posição atual da câmera no espaço da cena. Essa propriedade é usada como um método para comunicar a posição atual da câmera ao aplicativo.
  • get_LookPoint. O aplicativo acessa essa propriedade para obter o ponto para o qual a câmera do controlador está voltada atualmente.
  • Update. Lê o estado dos controladores de movimento e visão e atualiza a posição da câmera. Esse método é chamado continuamente a partir do loop principal do aplicativo para atualizar os dados do controlador da câmera e a posição da câmera no espaço da cena.

Agora já temos todos os componentes necessários para implementar os controles move-look.

Portanto, chegou o momento de conectar todas essas peças.

Criar os eventos de entrada básicos

O dispatcher de eventos do Tempo de Execução do Windows fornece cinco eventos que deverão ser manipulados por instâncias da classe MoveLookController:

Esses eventos são implementados no tipo CoreWindow. Presumimos que você tenha um objeto CoreWindow para trabalhar. Se não souber como obter um, veja Como configurar seu aplicativo da Windows Store em C++ para exibir uma visualização DirectX.

Como esses eventos são acionados enquanto o aplicativo está sendo executado, os manipuladores atualizam as informações de estado dos controladores definidas nos campos privados.

Primeiro, preencheremos os manipuladores de eventos dos ponteiros de mouse e de toque. No primeiro manipulador de eventos, OnPointerPressed(), obtemos as coordenadas x-y do ponteiro do CoreWindow que gerencia a exibição quando o usuário clica o mouse ou toca a tela na região do controlador de visão.

OnPointerPressed


void MoveLookController::OnPointerPressed(
_In_ CoreWindow^ sender,
_In_ PointerEventArgs^ args)
{
    // get the current pointer position
    uint32 pointerID = args->CurrentPoint->PointerId;
    float2 position = float2( args->CurrentPoint->Position.X, args->CurrentPoint->Position.Y );

    auto device = args->CurrentPoint->PointerDevice;
    auto deviceType = device->PointerDeviceType;
    if ( deviceType == PointerDeviceType::Mouse )
    {
        // Action, Jump, or Fire
    }

    // check  if this pointer is in the move control
    // Change the values  to percentages of the preferred screen resolution.
    // You can set the x value to <preferred resolution> * <percentage of width>
    // for example, ( position.x < (screenResolution.x * 0.15) )

    if (( position.x < 300 && position.y > 380 ) && ( deviceType != PointerDeviceType::Mouse ))
    {
        if ( !m_moveInUse )	// if no pointer is in this control yet
        {
            // process a DPad touch down event
            m_moveFirstDown = position;					// save location of initial contact
            m_movePointerPosition = position;
            m_movePointerID = pointerID;				// store the id of pointer using this control
            m_moveInUse = TRUE;
        }
    }
    else // this pointer must be in the look control
    {
        if ( !m_lookInUse )	// if no pointer is in this control yet
        {
            m_lookLastPoint = position;							// save point for later move
            m_lookPointerID = args->CurrentPoint->PointerId;	// store the id of pointer using this control
            m_lookLastDelta.x = m_lookLastDelta.y = 0;			// these are for smoothing
            m_lookInUse = TRUE;
        }
    }
}


Esse manipulador de eventos verifica se o ponteiro não é o mouse (para os fins deste exemplo, que dá suporte a mouse e toque) e se está na área do controlador de movimento. Caso ambos os critérios sejam verdadeiros, ele verifica se o ponteiro acabou de ser pressionado – especificamente, se esse clique não está relacionado a uma entrada de movimento ou visão anterior – testando se m_moveInUse é falso. Em caso afirmativo, o manipulador captura o ponto na área do controlador de movimento onde o pressionamento ocorreu e define m_moveInUse como verdadeiro para que, ao ser chamado novamente, esse manipulador não sobregrave a posição inicial da interação de entrada do controlador de movimento. Ele também atualiza o ID do ponteiro do controlador de movimento para o ID do ponteiro atual.

Caso o ponteiro seja o mouse ou o ponteiro de toque não esteja na área do controlador de movimento, ele deverá estar na área do controlador de visão. O manipulador define m_lookLastPoint para a posição atual onde o usuário pressionou o botão do mouse ou tocou e pressionou a tela, redefine o delta e atualiza o ID do ponteiro do controlador de visão para o ID do ponteiro atual. Além disso, ele define o estado do controlador de visão para ativo.

OnPointerMoved


void MoveLookController::OnPointerMoved(
                                        _In_ CoreWindow ^sender,
                                        _In_ PointerEventArgs ^args)
{
    uint32 pointerID = args->CurrentPoint->PointerId;
    float2 position = float2( args->CurrentPoint->Position.X, args->CurrentPoint->Position.Y );

    // decide which control this pointer is operating
    if ( pointerID == m_movePointerID )			// this is the move pointer
    {
        // Move control
        m_movePointerPosition = position;		// save current position

    }
    else if (pointerID == m_lookPointerID )		// this is the look pointer
    {
        // Look control

        float2 pointerDelta;
        pointerDelta = position - m_lookLastPoint;		// how far did pointer move

        float2 rotationDelta;
        rotationDelta = pointerDelta * ROTATION_GAIN;	// scale for control sensitivity
        m_lookLastPoint = position;			 			// save for next time through

        // update our orientation based on the command
        m_pitch -= rotationDelta.y;						// mouse y increases down, but pitch increases up
        m_yaw   -= rotationDelta.x;						// yaw defined as CCW around y-axis

        // Limit pitch to straight up or straight down
        m_pitch = (float) __max( -M_PI/2.0f, m_pitch );
        m_pitch = (float) __min( +M_PI/2.0f, m_pitch );
    }
}

O manipulador de eventos OnPointerMoved é acionado sempre que o ponteiro se move; nesse caso, o ponteiro da tela sensível ao toque sendo arrastado ou o ponteiro do mouse sendo movido com o botão esquerdo pressionado. Se o ID do ponteiro for idêntico ao ID do ponteiro do controlador de movimento, trata-se do ponteiro de movimento; caso contrário, verificamos se o ponteiro ativo é o controlador de visão.

Se for o controlador de movimento, simplesmente atualizamos a posição do ponteiro. Continuamos atualizando a posição enquanto o evento PointerMoved continuar sendo acionado, porque queremos comparar a posição final à primeira posição capturada com o manipulador de eventos OnPointerPressed.

Se for o controlador de visão, as coisas são um pouco mais complicadas. Como precisamos calcular um novo ponto de visão e centralizar a câmera nele, calculamos o delta entre o último ponto de visão e a posição atual da tela e o multiplicamos pelo nosso fator de escala, que pode ser ajustado para tornar os movimentos de visão menores ou maiores com relação à distância do movimento na tela. Usando esse valor, calculamos a inclinação longitudinal e a rotação.

Finalmente, temos que desativar os comportamentos do controlador de movimento ou de visão quando o jogador para de mover o mouse ou de tocar a tela. Usamos OnPointerReleased, que é chamado quando PointerReleased é acionado, para definir m_moveInUse ou m_lookInUse como FALSE e interromper o movimento panorâmico da câmera e zerar o ID do ponteiro.

OnPointerReleased


void MoveLookController::OnPointerReleased(
_In_ CoreWindow ^sender,
_In_ PointerEventArgs ^args)
{
    uint32 pointerID = args->CurrentPoint->PointerId;
    float2 position = float2( args->CurrentPoint->Position.X, args->CurrentPoint->Position.Y );


    if ( pointerID == m_movePointerID )    // this was the move pointer
    {
        m_moveInUse = FALSE;
        m_movePointerID = 0;
    }
    else if (pointerID == m_lookPointerID ) // this was the look pointer
    {
        m_lookInUse = FALSE;
        m_lookPointerID = 0;
    }
}

Até aqui, cuidamos de todos os eventos da tela sensível ao toque. Agora cuidaremos so eventos de entrada de tecla para um controlador de movimento baseado no teclado.

OnKeyDown


void MoveLookController::OnKeyDown(
                                   __in CoreWindow^ sender,
                                   __in KeyEventArgs^ args )
{
    Windows::System::VirtualKey Key;
    Key = args->VirtualKey;

    // figure out the command from the keyboard
    if ( Key == VirtualKey::W )		// forward
        m_forward = true;
    if ( Key == VirtualKey::S )		// back
        m_back = true;
    if ( Key == VirtualKey::A )		// left
        m_left = true;
    if ( Key == VirtualKey::D )		// right
        m_right = true;
}

Enquanto uma dessas teclas permanece pressionada, esse manipulador de eventos define o estado do movimento direcional correspondente como verdadeiro.

OnKeyUp


void MoveLookController::OnKeyUp(
                                 __in CoreWindow^ sender,
                                 __in KeyEventArgs^ args)
{
    Windows::System::VirtualKey Key;
    Key = args->VirtualKey;

    // figure out the command from the keyboard
    if ( Key == VirtualKey::W )		// forward
        m_forward = false;
    if ( Key == VirtualKey::S )		// back
        m_back = false;
    if ( Key == VirtualKey::A )		// left
        m_left = false;
    if ( Key == VirtualKey::D )		// right
        m_right = false;
}

Quando a tecla é liberada, esse manipulador de eventos define-o novamente como falso. Ao ser chamado, Update verifica esses estados de movimento direcional e produz o movimento correspondente da câmera. Isso é um pouco mais simples do que a implementação de toque.

Inicializar os controles de toque e o estado dos controladores

Agora conectaremos os eventos e inicializaremos todos os campos de estado de controladores.

Initialize


void MoveLookController::Initialize( _In_ CoreWindow^ window )
{

    // opt in to recieve touch/mouse events
    window->PointerPressed += 
    ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &MoveLookController::OnPointerPressed);

    window->PointerMoved += 
    ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &MoveLookController::OnPointerMoved);

    window->PointerReleased += 
    ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &MoveLookController::OnPointerReleased);

    window->CharacterReceived +=
    ref new TypedEventHandler<CoreWindow^, CharacterReceivedEventArgs^>(this, &MoveLookController::OnCharacterReceived);

    window->KeyDown += 
    ref new TypedEventHandler<CoreWindow^, KeyEventArgs^>(this, &MoveLookController::OnKeyDown);

    window->KeyUp += 
    ref new TypedEventHandler<CoreWindow^, KeyEventArgs^>(this, &MoveLookController::OnKeyUp);

    // Initialize state of the controller
    m_moveInUse = FALSE;				// no pointer is in the Move control
    m_movePointerID = 0;

    m_lookInUse = FALSE;				// no pointer is in the Look control
    m_lookPointerID = 0;

    //	need to init this as it is reset every frame
    m_moveCommand = float3( 0.0f, 0.0f, 0.0f );

    SetOrientation( 0, 0 );				// look straight ahead when the app starts

}

Initialize recebe uma referência à instância de CoreWindow do aplicativo como um parâmetro e registra os manipuladores de eventos que desenvolvemos para os eventos apropriados nessa CoreWindow. Ele inicializa os IDs dos ponteiros de movimento e visão, zera o vetor de comando para nossa implementação do controlador de movimento de tela sensível ao toque e coloca a câmera voltada diretamente para a frente quando o aplicativo é iniciado.

Obtendo e definindo a posição e a orientação da câmera

Definiremos alguns métodos para obter e definir a posição da câmera em relação ao visor.


void MoveLookController::SetPosition( _In_ float3 pos )
{
    m_position = pos;
}

// accessor to set position of controller
void MoveLookController::SetOrientation( _In_ float pitch, _In_ float yaw )
{
    m_pitch = pitch;
    m_yaw = yaw;
}

// returns the position of the controller object
float3 MoveLookController::get_Position()
{
    return m_position;
}

// returns the point at which the camera controller is facing
float3 MoveLookController::get_LookPoint()
{
    float y = sinf( m_pitch );		// vertical
    float r = cosf( m_pitch );		// in the plane
    float z = r*cosf( m_yaw );		// fwd-back
    float x = r*sinf( m_yaw );		// left-right

    return m_position + float3( x, y, z );
}

Atualizando as informações de estado do controlador

Agora efetuamos os cálculos para converter as informações de coordenadas do ponteiro rastreadas em m_movePointerPosition em novas informações de coordenadas relativas ao sistema de coordenadas do nosso mundo. Nosso aplicativo chama esse método cada vez que seu loop principal é atualizado. Portanto, é aqui que calculamos as informações de posição do novo ponto de visão que queremos passar ao aplicativo para que a matriz de visualização seja atualizada antes da projeção no visor.



void MoveLookController::Update( CoreWindow ^window )
{
    // check for input from the Move control
    if ( m_moveInUse )
    {
        float2 pointerDelta = m_movePointerPosition - m_moveFirstDown;

        // figure out the command from the touch-based virtual joystick
        if ( pointerDelta.x > 16.0f )		// leave 32 pixel-wide dead spot for being still
            m_moveCommand.x =  1.0f;
        else
            if ( pointerDelta.x < -16.0f )
                m_moveCommand.x = -1.0f;

        if ( pointerDelta.y > 16.0f )		// joystick y is up so change sign
            m_moveCommand.y = -1.0f;
        else
            if (pointerDelta.y < -16.0f )
                m_moveCommand.y =  1.0f;
    }

    // poll our state bits set by the keyboard input events
    if ( m_forward )
        m_moveCommand.y += 1.0f;
    if ( m_back )
        m_moveCommand.y -= 1.0f;

    if ( m_left )
        m_moveCommand.x -= 1.0f;
    if ( m_right )
        m_moveCommand.x += 1.0f;

    if ( m_up )
        m_moveCommand.z += 1.0f;
    if ( m_down )
        m_moveCommand.z -= 1.0f;

    // make sure that 45  degree cases are not faster
    float3 command = m_moveCommand;
    if ( fabsf(command.x) > 0.1f || fabsf(command.y) > 0.1f || fabsf(command.z) > 0.1f )
        command = normalize( command );

    // rotate command to align with our direction (world coordinates)
    float3 wCommand;
    wCommand.x = command.x*cosf( m_yaw ) - command.y*sinf( m_yaw );
    wCommand.y = command.x*sinf( m_yaw ) + command.y*cosf( m_yaw );
    wCommand.z = command.z;

    // scale for sensitivity adjustment
    wCommand = wCommand*MOVEMENT_GAIN;

    // our velocity is based on the command,
    // also note that y is the up-down axis 
    float3 Velocity;
    Velocity.x = -wCommand.x;
    Velocity.z =  wCommand.y;
    Velocity.y =  wCommand.z;

    // integrate
    m_position = m_position + Velocity;

    // clear movement input accumulator for use during next frame
    m_moveCommand = float3( 0.0f, 0.0f, 0.0f );

}

Como não queremos movimentos erráticos quando o jogador usar o controlador de movimento baseado em toque, definimos uma zona morta virtual com diâmetro de 32 pixels em torno do ponteiro. Também adicionamos velocidade, que é o valor do comando mais um taxa de incremento do movimento. (Você pode ajustar esse comportamento como preferir, para reduzir ou acelerar a taxa de movimento com base na distância percorrida pelo ponteiro na área do controlador de movimento.)

Quando calculamos a velocidade, também traduzimos as coordenadas recebidas dos controladores de movimento e visão para o movimento do ponto de visão real que enviamos ao método responsável pelo cálculo da matriz de visualização da cena. Primeiro invertemos a coordenada x, porque quando clicamos-movemos ou arrastamos para a esquerda ou para a direita com o controlador de visão, o ponto de visão gira em direção oposta à cena, como na rotação de uma câmera sobre o seu eixo central. Em seguida, trocamos os eixos y e z, porque o pressionamento de uma tecla para cima/para baixo ou um movimento de tocar e arrastar (lidos como um comportamento no eixo y) no controlador de movimento devem se traduzir em uma ação da câmera que move o ponto de visão para perto ou para longe da tela (o eixo z).

A posição final do ponto de visão para o jogador é a última posição mais a velocidade calculada, e é isso que é lido pelo renderizador quando chama o método get_Position (muito provavelmente durante a configuração para cada quadro). Depois disso, redefinimos o comando de movimento para zero.

Atualizando a matriz de visualização com a nova posição da câmera

Podemos obter a coordenada do espaço da cena em que a câmera está focalizada, que é atualizada com a frequência programada no aplicativo (a cada 60 segundos no loop principal do aplicativo, por exemplo). Este pseudocódigo sugere o comportamento de chamada que você pode implementar:


myMoveLookController->Update( m_window );	

// update the view matrix based on the camera position
myFirstPersonCamera->SetViewParameters(
                 myMoveLookController->get_Position(),		// point we are at
                 myMoveLookController->get_LookPoint(),		// point to look towards
                 float3( 0, 1, 0 )					// up-vector
                 );	


Parabéns! Você implementou controles move-look básicos para telas sensíveis ao toque e controles de toque para entrada via teclado/mouse em jogos da Windows Store em C++.

 

 

Mostrar:
© 2014 Microsoft