C # / XNA ottiene la posizione del mouse hardware


10

Sto usando C # e sto cercando di ottenere la posizione del mouse hardware. La prima cosa che ho provato è stata la semplice funzionalità XNA che è semplice da usare

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

Dopo di che faccio anche il disegno del mouse, e confrontandolo con il mouse hardware di Windows, questo nuovo mouse con le coordinate fornite da xna si sta "allentando". Con questo voglio dire, che è dietro di pochi fotogrammi. Ad esempio, se il gioco viene eseguito a 600 fps, la maledizione sarà reattiva, ma a 60 fps il ritardo del mouse del software non è più accettabile. Quindi ho provato ad usare quello che pensavo fosse un mouse hardware,

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

ma il risultato è stato esattamente lo stesso. Ho anche provato a ottenere il cursore del modulo di Windows, ed è stato anche un vicolo cieco - ha funzionato, ma con lo stesso ritardo. Divertiti con la funzionalità xna:

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

ha cambiato il tempo di ritardo per ragioni piuttosto ovvie, ma la linea di fondo è che, indipendentemente da ciò, era ancora dietro il mouse predefinito di Windows. Ho visto in alcuni giochi che forniscono un'opzione per il mouse con accelerazione hardware e in altri (penso) è già di default. Qualcuno può dare qualche indizio su come raggiungere questo obiettivo.


2
Non penso Mouse.GetState()sia rotto. Sei sicuro di ottenere la posizione del mouse nella stessa cornice mentre la disegni? Ricorda inoltre che il cursore di Windows ha accelerazione / decelerazione abilitata, quindi sembra più reattivo. Se vuoi avvicinarti all'hardware, dovresti premere DirectInput, che ti darà delta di movimento invece di posizioni assolute del mouse. Ma credo che Mouse.GetState()sia ancora il modo corretto di farlo in XNA.
Panda Pajama,

No, Mouse.GetState()non è rotto e fintanto che le IsFixedTimeStep == truepersone non dovrebbero essere in grado di vedere il ritardo se non confrontato direttamente con il mouse Windows visibile. Tuttavia, impostando IsFixedTimeStep su false al framerate inferiore, diventa visibile a tutti. A proposito di input diretto ho considerato una posabilità (ultima risorsa).
Sunder,

Non sei sicuro che sia quello che vuoi, ma che ne dici di cambiare lo sprite del cursore mentre è nella tua finestra, e quindi renderlo sempre visibile?
William Mariager,

Questo è esattamente quello che sto facendo, il fatto è che non voglio solo mostrarlo, ma anche conoscere la posizione esatta del mouse. Ma quello che sto ottenendo è leggermente indietro rispetto a quello che dovrebbe essere.
Sunder,

Risposte:


17

Quello che stai vedendo non è il ritardo di input.

Per ottenere la posizione del cursore in Windows puoi usare WM_MOUSEMOVEo GetCursorPos. Entrambi forniscono la posizione del cursore dopo che Windows lo ha elaborato, applicando cose come l'accelerazione. Questa è la posizione del cursore utilizzata da Windows, incluso per il disegno. E quasi sempre anche quello che vuoi usare.

Questo è ciò che utilizza XNA . In particolare GetCursorPos( MSDN ). Ciò significa che, quando chiami Mouse.GetState, stai ottenendo la vera posizione del cursore come Windows lo vede, con un ritardo praticamente pari a zero.

Ora puoi usare WM_INPUT(o DirectInput, anche se è obsoleto). Questo ti dà i dati del puntatore non elaborati. Questo è prima che Windows possa applicare cose come l'accelerazione e di solito non è quello che vuoi.

Quello che stai vedendo è l' output lag.

Ciò è dovuto al " cursore hardware ". Questo è un piccolo sprite che viene disegnato sullo schermo dalla GPU al molto fine della sua pipeline. E intendo la fine . Viene dopo il frame buffer: viene inserito nel flusso di dati mentre l'immagine viene inviata al monitor. Il motivo per cui reagisce così rapidamente è perché la sua posizione è impostata impostando direttamente i registri GPU. Non c'è nessuna attesa in giro per la pipeline.

Il tuo gioco, d'altra parte, deve passare attraverso la pipeline GPU. Questo aggiunge molti ritardi da solo. Il più problematico di questi per te è il doppio buffering - che (ne sono abbastanza sicuro) non puoi disattivare in XNA 4. Non disegni direttamente sul frame buffer - disegni sul backbuffer. Che viene presentato ogni ~ 16ms (a 60FPS). Ciò significa che stai osservando un minimo di circa 16 ms tra la ricezione del risultato diMouse.GetState ottenere qualcosa in base a quel risultato sullo schermo. Probabilmente più a lungo. Sicuramente molto più lento del cursore hardware.

Quindi quali sono le soluzioni?

Uno è da usare SetCursor( MSDN ) per cambiare l'immagine che viene visualizzata dal cursore hardware, per essere l'immagine che si adatta meglio al tuo gioco (o semplicemente vivere con il cursore di Windows).

E l'altro (molto più semplice) è semplicemente accettare il ritardo e impostare Game.IsMouseVisible = falseper nascondere il ritardo relativo. Mostra il tuo cursore nel gioco. Sarà 16ms più lento del cursore nascosto di Windows - ma a chi importa? I giocatori ci sono abituati. E 16ms è quasi visivamente impercettibile comunque (è per questo che rendiamo le cose a 60FPS).


Grazie per la spiegazione dettagliata della questione. Molto probabilmente mi limiterò a rimanere con il mouse XNA. Andare ad aspettare un po 'prima di accettare nel caso in cui qualcuno abbia qualche soluzione aggiuntiva per questo.
Sunder,

Suppongo che accettare il ritardo o meno sia una domanda a cui dovrebbe essere data una risposta dal playtest.
Zonko,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.