C # / XNA obtient la position de la souris matérielle


10

J'utilise C # et j'essaie d'obtenir la position de la souris matérielle. La première chose que j'ai essayée était une fonctionnalité XNA simple qui est simple à utiliser

Vector2 position = new Vector2(Mouse.GetState().X, Mouse.GetState().Y);

Après cela, je fais aussi le dessin de la souris, et en comparant avec la souris matérielle Windows, cette nouvelle souris avec les coordonnées fournies par xna "se relâche". J'entends par là qu'il est en retard de quelques images. Par exemple, si le jeu tourne à 600 fps, il sera bien sûr réactif, mais à 60 fps, le retard de la souris logicielle n'est plus acceptable. J'ai donc essayé d'utiliser ce que je pensais être une souris matérielle,

[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetCursorPos(out POINT lpPoint);

mais le résultat était exactement le même. J'ai également essayé d'obtenir le curseur de formulaire Windows, et c'était une impasse aussi bien - mais avec le même retard. Jouer avec la fonctionnalité xna:

GraphicsDeviceManager.SynchronizeWithVerticalRetrace = true/false
Game.IsFixedTimeStep = true/fale

a changé le temps de retard pour des raisons quelque peu évidentes, mais l'essentiel est qu'indépendamment, il était toujours derrière la souris Windows par défaut. J'ai vu dans certains jeux, qu'ils fournissent une option pour la souris accélérée matériellement, et dans d'autres (je pense) c'est déjà par défaut. Quelqu'un peut-il nous montrer comment y parvenir?


2
Je ne pense pas que ce Mouse.GetState()soit cassé. Êtes-vous sûr d'obtenir la position de la souris dans le même cadre que celui que vous dessinez? Rappelez-vous également que le curseur Windows a activé l'accélération / décélération, donc il se sent plus réactif. Si vous voulez vous rapprocher du matériel, vous devez appuyer sur DirectInput, qui vous donnera des deltas de mouvement au lieu de positions absolues de la souris. Mais je crois que Mouse.GetState()c'est toujours la bonne façon de le faire dans XNA.
Panda Pyjama

Non, Mouse.GetState()n'est pas cassé, et tant que les IsFixedTimeStep == truegens ne devraient pas pouvoir voir le retard à moins d'être comparés directement avec la souris Windows visible. Cependant, en définissant IsFixedTimeStep sur false à un débit d'images inférieur, cela devient visible pour tout le monde. À propos de l'entrée directe, j'ai considéré que c'était une posabilité (dernier recours).
Sunder

Vous ne savez pas si c'est ce que vous voulez, mais qu'en est-il de changer l'image-objet du curseur alors qu'il est dans votre fenêtre, puis de le rendre toujours visible?
William Mariager

C'est exactement ce que je fais, le fait est que je ne veux pas seulement le montrer, mais aussi connaître la position exacte de la souris. Mais ce que je reçois est légèrement en retard par rapport à ce qu'il devrait être.
Sunder

Réponses:


17

Ce que vous voyez n'est pas un décalage d'entrée.

Pour obtenir la position du curseur dans Windows, vous pouvez utiliser WM_MOUSEMOVEou GetCursorPos. Ils fournissent tous deux la position du curseur une fois que Windows l'a traité, en appliquant des choses comme l'accélération. Il s'agit de la position du curseur utilisée par Windows, y compris pour le dessin. Et presque toujours aussi ce que vous voulez utiliser.

C'est ce que XNA utilise . Plus précisément GetCursorPos( MSDN ). Cela signifie que, lorsque vous appelez Mouse.GetState, vous obtenez la position réelle du curseur telle que Windows la voit - avec un délai pratiquement nul.

Maintenant, vous pouvez utiliser WM_INPUT(ou DirectInput, bien que ce soit obsolète). Cela vous donne les données brutes du pointeur. C'est avant que Windows puisse appliquer des choses comme l'accélération, et ce n'est généralement pas ce que vous voulez.

Ce que vous voyez, c'est un décalage de sortie.

Cela est dû au " curseur matériel ". Il s'agit d'un petit sprite qui est dessiné sur l'écran par le GPU à la toute fin de son pipeline. Et je veux dire la fin . Il vient après le tampon de trame - il est inséré dans le flux de données lorsque l'image est envoyée au moniteur. La raison pour laquelle il réagit si rapidement est que sa position est définie en définissant directement les registres GPU. Il n'y a aucune attente dans le pipeline.

Votre jeu, en revanche, doit passer par le pipeline GPU. Cela ajoute beaucoup de retards en soi. Le plus problématique pour vous est la double mise en mémoire tampon - que (je suis presque sûr) vous ne pouvez pas désactiver dans XNA 4. Vous ne dessinez pas directement dans le tampon de trame - vous dessinez dans le backbuffer. Qui est présenté toutes les ~ 16 ms (à 60FPS). Cela signifie que vous regardez au moins environ 16 ms entre la réception du résultat de l' Mouse.GetStateobtention de quelque chose basé sur ce résultat à l'écran. Probablement plus. Certainement beaucoup plus lent que le curseur matériel.

Alors, quelles sont les solutions?

La première consiste à utiliser SetCursor( MSDN ) pour modifier l'image qui est affichée par le curseur matériel, pour obtenir une image qui convient mieux à votre jeu (ou tout simplement vivre avec le curseur Windows).

Et l'autre (beaucoup plus facile) consiste à simplement accepter le décalage et Game.IsMouseVisible = falseà masquer le décalage relatif. Affichez votre propre curseur dans le jeu. Il sera 16 ms plus lent que le curseur Windows caché - mais peu importe? Les joueurs y sont habitués. Et 16 ms est de toute façon presque imperceptible visuellement (c'est pourquoi nous rendons les choses à 60FPS).


Merci pour l'explication détaillée de la question. Je vais probablement rester avec la souris XNA. Je vais attendre un peu avant d'accepter au cas où quelqu'un aurait une solution de contournement supplémentaire pour cela.
Sunder

J'imagine que l'acceptation du décalage est une question à laquelle il faut répondre par playtesting.
Zonko
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.