Didacticiel : ajouter des contrôles de déplacement/vue à votre jeu DirectX

Applies to Windows only

Découvrez comment ajouter des contrôles de déplacement/vue de souris et de clavier classiques (également connus sous le nom de contrôles de vue à la souris) à votre jeu DirectX.

Nous allons également aborder la prise en charge du déplacement et de la vue pour les appareils tactiles, avec le contrôleur de déplacement défini en tant que section inférieure gauche de l’écran qui se comporte comme une entrée directionnelle, et le contrôleur de vue défini pour le reste de l’écran, avec la caméra centrée sur le dernier endroit que le joueur a touché dans cette zone.

Si ce concept de contrôle ne vous est pas du tout familier, pensez-y de la façon suivante : le clavier (ou la zone d’entrée directionnelle tactile) contrôle vos jambes dans cet espace en 3D et se comporte comme si vos jambes étaient uniquement capables de se déplacer vers l’avant ou l’arrière, ou de mitrailler à droite et à gauche. La souris (ou le pointeur tactile) contrôle votre tête. Vous utilisez votre tête pour regarder dans une direction, à gauche ou à droite, vers le haut ou vers le bas, ou quelque part dans ce plan. Si une cible se présente dans votre vue, vous utilisez la souris pour centrer votre vue caméra sur cette cible, puis appuyez sur la touche avant pour avancer vers elle ou la touche arrière pour vous en éloigner. Pour encercler la cible, vous gardez la vue caméra centrée sur la cible, et vous vous déplacez vers la gauche ou la droite en même temps. Vous pouvez constater qu’il s’agit là d’une méthode de contrôle très efficace pour naviguer dans les environnements 3D !

Ces contrôles sont généralement connus sous le nom de contrôles WASD dans le jeu, où les touches W, S, A et D sont utilisées pour le mouvement de caméra fixe de plan x-z, et la souris permet de contrôler la rotation de la caméra autour des axes x et y.

Objectifs

  • Ajouter des contrôles de déplacement/vue de base à votre jeu DirectX à la fois pour la souris et le clavier, et les écrans tactiles.
  • Implémenter une caméra subjective utilisée pour naviguer dans un environnement 3D.

Note sur les implémentations de contrôles tactiles

Pour les contrôles tactiles, nous implémentons deux contrôleurs : le contrôleur de déplacement, qui gère les mouvements dans le plan x-z par rapport au point de mire de la caméra, et le contrôleur de vue, qui vise le point de mire de la caméra. Notre contrôleur de déplacement est mappé aux boutons WASD du clavier et le contrôleur de vue est mappé à la souris. Cependant, pour les contrôles tactiles, nous devons définir une zone de l’écran qui est utilisée pour les entrées directionnelles, ou les boutons WASD virtuels, avec le reste de l’écran servant d’espace d’entrée pour les contrôles de vue.

Notre écran se présente ainsi.

disposition du contrôleur de déplacement/vue

Lorsque vous déplacez le pointeur tactile (pas la souris !) dans la partie inférieure gauche de l’écran, tout mouvement vers le haut déplace la caméra vers l’avant. Tout mouvement vers le bas déplace la caméra vers l’arrière. Cela s’applique également aux mouvements vers la gauche et la droite à l’intérieur de l’espace de pointeur du contrôleur de déplacement. Hors de cet espace, et cela devient un contrôleur de vue, il vous suffit de toucher ou de faire glisser la caméra dans la direction dans laquelle vous souhaitez l’orienter.

Configurer l’infrastructure des événements d’entrée de base

Nous devons d’abord créer notre classe de contrôle à utiliser pour gérer les événements d’entrée à partir de la souris et du clavier, puis mettre à jour la perspective de la caméra en fonction de ces entrées. Puisque nous implémentons des contrôles de déplacement/vue, nous l’appelons 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

Créons maintenant un en-tête qui définit l’état du contrôleur de déplacement/vue et sa caméra subjective, plus les méthodes de base et gestionnaires d’événements qui implémentent les contrôles et mettent à jour l’état de la caméra.



#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

Notre code contient 4 groupes de champs privés. Passons en revue le rôle de chacun d’eux.

Définissons d’abord quelques champs utiles qui contiennent nos informations mises à jour sur notre vue caméra.

  • m_position représente la position de la caméra (et, par conséquent, le plan de vue) dans la scène 3D, avec les coordonnées de scène.
  • m_pitch représente le tangage de la caméra, ou sa rotation de haut en bas autour de l’axe X du plan de vue, en radians.
  • m_yaw représente le lacet de la caméra, ou sa rotation de gauche à droite autour de l’axe Y du plan de vue, en radians.

Définissons maintenant les champs à utiliser pour stocker des informations sur l’état et la position de nos contrôleurs. Définissons d’abord les champs dont nous avons besoin pour notre contrôleur de déplacement tactile. (Rien de spécial n’est requis pour l’implémentation clavier du contrôleur de déplacement. Nous devons juste lire les événements de clavier avec des gestionnaires spécifiques.)

  • m_moveInUse indique si le contrôleur de déplacement est en cours d’utilisation.
  • m_movePointerID représente l’ID unique pour le pointeur de déplacement actuel. Il est utilisé pour différencier le pointeur de vue du pointeur de déplacement lors de la vérification de la valeur de l’ID de pointeur.
  • m_moveFirstDown est le point de l’écran où le joueur a touché pour la première fois la zone du pointeur du contrôleur de déplacement. Nous utiliserons cette valeur plus tard pour définir une zone morte afin d’empêcher les mini-mouvements de déstabiliser la vue.
  • m_movePointerPosition est le point de l’écran où le joueur a actuellement placé le pointeur. Il est utilisé pour déterminer la direction dans laquelle l’utilisateur souhaite se déplacer en l’examinant par rapport à m_moveFirstDown.
  • m_moveCommand est la dernière commande calculée pour le contrôleur de déplacement : haut (avant), bas (arrière), gauche ou droite.

Définissons maintenant les champs à utiliser pour notre contrôleur de vue, les implémentations de souris et tactile.

  • m_lookInUse indique si le contrôle de vue est en cours d’utilisation.
  • m_lookPointerID représente l’ID unique pour le pointeur de vue actuel. Il est utilisé pour différencier le pointeur de vue du pointeur de déplacement lors de la vérification de la valeur de l’ID de pointeur.
  • m_lookLastPoint est le dernier point, en coordonnées de scène, qui a été capturé dans la trame précédente.
  • m_lookLastDelta est la différence calculée entre les éléments m_position et m_lookLastPoint actuels.

Enfin, définissons 6 valeurs booléennes pour les 6 degrés de mouvement, qui permettent d’indiquer l’état actuel de chaque action de déplacement directionnel (activé ou désactivé) :

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

Nous utilisons les 6 gestionnaires d’événements pour capturer les données d’entrée utilisées pour mettre à jour l’état de nos contrôleurs :

  • OnPointerPressed. Le joueur a appuyé sur le bouton gauche de la souris avec le pointeur dans l’écran du jeu, ou a touché l’écran.
  • OnPointerMoved. Le joueur a déplacé la souris avec le pointeur dans l’écran du jeu, ou a fait glisser le pointeur tactile sur l’écran.
  • OnPointerReleased. Le joueur a relâché le bouton gauche de la souris avec le pointeur dans l’écran du jeu, ou a arrêté de toucher l’écran.
  • OnKeyDown. Le joueur a appuyé sur une touche.
  • OnKeyUp. Le joueur a relâché une touche.

Enfin, nous utilisons les méthodes et propriétés suivantes pour accéder aux informations sur l’état des contrôleurs, les initialiser et les mettre à jour.

  • Initialize. Notre application appelle ce gestionnaire d’événements pour initialiser les contrôles et les associer à l’objet CoreWindow qui décrit notre fenêtre d’affichage.
  • SetPosition. Notre application appelle cette méthode pour définir les coordonnées (x, y et z) de nos contrôles dans l’espace de scène.
  • SetOrientationNotre application appelle cette méthode pour définir les tangage et lacet de la caméra.
  • get_Position. Notre application accède à cette propriété pour obtenir la position actuelle de la caméra dans l’espace de scène. Vous utilisez cette propriété comme méthode de communication de la position actuelle de la caméra à l’application.
  • get_LookPoint. Notre application accède à cette propriété pour obtenir le point actuel vers lequel la caméra du contrôleur est orientée.
  • Update. Lit l’état des contrôleurs de déplacement et de vue, et met à jour la position de la caméra. Vous appelez continuellement cette méthode à partir de la boucle principale de l’application pour actualiser les données de contrôleur de la caméra et la position de la caméra dans l’espace de scène.

Vous disposez à présent ici de tous les composants nécessaires pour implémenter vos contrôles de déplacement/vue.

Rassemblons tous ces éléments.

Créer les événements d’entrée de base

Le répartiteur d’événements Windows Runtime fournit 5 événements qui doivent être gérés par les instances de la classe MoveLookController :

Ces événements sont implémentés sur le type CoreWindow. Nous supposons que vous disposez d’un objet CoreWindow à manipuler. Si vous ne savez pas comment en obtenir un, voir Comment configurer une application C++ Windows Store pour afficher une vue DirectX.

Comme ces événements sont déclenchés pendant que notre application est en cours d’exécution, les gestionnaires mettent à jour les informations sur l’état des contrôleurs définies dans nos champs privés.

Remplissons d’abord les gestionnaires d’événements de pointeur de souris et tactile. Dans le premier gestionnaire d’événements, OnPointerPressed(), nous obtenons les coordonnées x-y du pointeur à partir du CoreWindow qui gère notre affichage lorsque l’utilisateur clique sur la souris ou touche l’écran dans la zone du contrôleur de vue.

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;
        }
    }
}


Ce gestionnaire d’événements vérifie que le pointeur n’est pas la souris (dans le cadre de cet exemple, qui prend en charge à la fois les opérations tactiles et avec la souris) et qu’il se trouve dans la zone du contrôleur de déplacement. Si les deux critères sont respectés, il vérifie si une simple pression a été effectuée sur le pointeur, en particulier si ce clic n’est pas lié à une précédente action de vue ou de déplacement, en testant si m_moveInUse a la valeur False. Si tel est le cas, le gestionnaire capture le point dans la zone du contrôleur de déplacement là où le joueur a appuyé sur le pointeur et affecte la valeur True à m_moveInUse de façon à ce qu’il ne remplace pas la position de départ de l’interaction de l’entrée du contrôleur de déplacement la prochaine fois qu’il est appelé. Il met également à jour l’ID de pointeur du contrôleur de déplacement avec l’ID du pointeur actuel.

Si le pointeur est la souris ou si le pointeur tactile ne se trouve pas dans la zone du contrôleur de déplacement, il doit se trouver dans la zone du contrôleur de vue. Il affecte à m_lookLastPoint la position actuelle où l’utilisateur a appuyé sur le bouton de la souris, ou touché et appuyé, réinitialise le delta, et met à jour l’ID de pointeur du contrôleur de vue avec l’ID du pointeur actuel. Il conserve ou définit également l’état actif du contrôleur de vue.

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 );
    }
}

Le gestionnaire d’événements OnPointerMoved se déclenche à chaque mouvement du pointeur (dans ce cas, si le pointeur tactile est glissé sur l’écran ou celui de la souris est déplacé avec le bouton gauche maintenu). Si l’ID de pointeur est le même que l’ID de pointeur du contrôleur de déplacement, il s’agit du pointeur de déplacement. Sinon, il convient de vérifier si le pointeur actif est le contrôleur de vue.

S’il s’agit du contrôleur de déplacement, il suffit de mettre à jour la position du pointeur. La position est mise à jour tant que l’événement PointerMoved continue de se déclencher, car nous voulons comparer la position finale à la première qui a été capturée à l’aide du gestionnaire d’événements OnPointerPressed.

S’il s’agit du contrôleur de vue, les choses sont un peu plus compliquées. Comme nous devons calculer un nouveau point de mire et centrer la caméra dessus, nous calculons le delta entre le dernier point de mire et la position à l’écran, puis le multiplions par le facteur d’échelle que nous pouvons modifier pour augmenter ou réduire les mouvements de vue par rapport à la distance du mouvement d’écran. Cette valeur nous permet de calculer les tangage et lacet.

Enfin, nous devons désactiver les comportements du contrôleur de déplacement ou de vue lorsque le joueur cesse de déplacer la souris ou de toucher l’écran. Nous utilisons OnPointerReleased, que nous appelons lorsque PointerReleased est déclenché, pour affecter à m_moveInUse ou m_lookInUse la valeur FALSE et désactiver le mouvement panoramique de la caméra, et pour mettre à zéro l’ID de pointeur.

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;
    }
}

Jusqu’ici, nous avons géré tous les événements d’écran tactile. Nous allons à présent gérer les événements d’entrée par touche pour un contrôleur de déplacement basé sur clavier.

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;
}

Tant que l’une de ces touches est enfoncée, ce gestionnaire d’événements affecte la valeur True à l’état de déplacement directionnel correspondant.

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;
}

Lorsque la touche est relâchée, ce gestionnaire d’événements lui réaffecte la valeur False. Lorsque nous appelons Update, ces états de déplacement directionnel sont vérifiés et la caméra est déplacée en conséquence. Cela est un peu plus simple que l’implémentation des contrôles tactiles !

Initialiser les contrôles tactiles et l’état du contrôleur

Rassemblons à présent les événements et initialisons tous les champs des états du contrôleur.

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 fait référence à l’instance CoreWindow de l’application en tant que paramètre et inscrit les gestionnaires d’événements développés dans les événements appropriés sur ce CoreWindow. Il initialise les ID des pointeurs de déplacement et de vue, affecte la valeur zéro au vecteur de commande pour l’implémentation du contrôleur de déplacement d’écran tactile, puis définit la direction droit devant de la caméra au démarrage de l’application.

Obtention et définition de la position et de l’orientation de la caméra

Définissons certaines méthodes pour obtenir et définir la position de la caméra par rapport à la fenêtre d’affichage.


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 );
}

Mise à jour des informations sur l’état du contrôleur

Effectuons maintenant nos calculs pour convertir les informations de coordonnées du pointeur suivies dans m_movePointerPosition en nouvelles informations de coordonnées respectives de notre système de coordonnées universelles. Notre application appelle cette méthode à chaque actualisation de la boucle principale de l’application. C’est donc ici que nous calculons les nouvelles informations de position du point de mire à transmettre à l’application pour la mise à jour de la matrice globale avant projection dans la fenêtre d’affichage.



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 );

}

Étant donné que nous ne voulons pas de sautillements lorsque le joueur utilise le contrôleur de déplacement tactile, nous définissons une zone morte virtuelle autour du pointeur avec un diamètre de 32 pixels. Nous ajoutons également la vitesse qui est la valeur de commande plus un rendement de mouvement. (Vous pouvez ajuster ce comportement selon votre goût, pour ralentir ou accélérer la vitesse de mouvement en fonction de la distance de déplacement du pointeur dans la zone du contrôleur de déplacement.)

Lorsque nous calculons la vitesse, nous traduisons également les coordonnées reçues des contrôleurs de déplacement et de vue en mouvement du point de mire réel que nous envoyons à la méthode qui calcule notre matrice globale pour la scène. Nous inversons d’abord la coordonnée x car, si nous effectuons un clic/déplacement ou un glisser vers la gauche ou la droite avec le contrôleur de déplacement, le point de mire pivote dans la direction opposée dans la scène, car une caméra peut osciller autour de son axe central. Nous échangeons ensuite les axes Y et Z, car une touche haut/bas enfoncée ou un mouvement de glisser tactile (interprété comme un comportement d’axe Y) sur le contrôleur de déplacement doit être traduit en une action de caméra qui déplace le point de mire à l’intérieur et à l’extérieur de l’écran (l’axe Z).

La position finale du point de mire pour le joueur est la dernière position plus la vitesse calculée et c’est ce qui est lu par le convertisseur lorsqu’il appelle la méthode get_Position (probablement pendant l’installation de chaque trame). Après cela, la commande de déplacement est réinitialisée à zéro.

Mise à jour de la matrice globale avec la nouvelle position de la caméra

Nous pouvons obtenir une coordonnée d’espace de scène sur laquelle la caméra fait le point et qui est mise à jour chaque fois que vous demandez à l’application de le faire (toutes les 60 secondes dans la boucle principale de l’application, par exemple). Ce pseudo code suggère le comportement d’appel à implémenter :


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
                 );	


Félicitations ! Vous avez implémenté des contrôles de déplacement/vue de base à la fois pour les écrans tactiles et les contrôles d’entrée par souris/clavier dans C++ Windows Store !

 

 

Afficher:
© 2014 Microsoft