C # / XNA erhalten die Position der Hardware-Maus

10

Ich verwende C # und versuche, die Position der Hardware-Maus zu ermitteln. Als erstes habe ich versucht, eine einfache XNA-Funktionalität zu verwenden

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

Danach zeichne ich auch die Maus und vergleiche sie mit der Windows-Hardware-Maus. Diese neue Maus mit den von xna bereitgestellten Koordinaten lässt nach. Damit meine ich, dass es nur wenige Frames hinter sich hat. Wenn das Spiel beispielsweise mit 600 fps läuft, reagiert es fluchend, aber mit 60 fps ist eine Software-Mausverzögerung nicht mehr akzeptabel. Deshalb habe ich versucht, eine Hardware-Maus zu verwenden.

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

aber das Ergebnis war genau das gleiche. Ich habe auch versucht, den Windows-Formularcursor abzurufen, und das war auch eine Sackgasse - funktioniert, aber mit der gleichen Verzögerung. Mit der xna-Funktionalität herumspielen:

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

Ich habe die Verzögerungszeit aus etwas offensichtlichen Gründen geändert, aber das Fazit ist, dass sie sich immer noch hinter der Standard-Windows-Maus befand. Ich habe in einigen Spielen gesehen, dass sie eine Option für hardwarebeschleunigte Mäuse bieten, und in anderen (glaube ich) ist dies bereits standardmäßig der Fall. Kann jemand einen Hinweis geben, wie dies erreicht werden kann?

Sunder
quelle
2
Ich glaube nicht, dass Mouse.GetState()es kaputt ist. Sind Sie sicher, dass Sie die Mausposition im selben Rahmen erhalten, in dem Sie sie zeichnen? Denken Sie auch daran , dass die Windows - Cursor haben Beschleunigung / Verzögerung aktiviert, so dass es fühlt sich mehr ansprechbar. Wenn Sie näher an die Hardware heranrücken möchten, sollten Sie DirectInput drücken, um Bewegungsdeltas anstelle der absoluten Mauspositionen zu erhalten. Aber ich glaube, es Mouse.GetState()ist immer noch der richtige Weg, dies in XNA zu tun.
Panda Pyjama
Nein, Mouse.GetState()ist nicht kaputt und solange die IsFixedTimeStep == trueLeute keine Verzögerung sehen können, es sei denn, sie werden direkt mit der sichtbaren Windows-Maus verglichen. Wenn Sie IsFixedTimeStep jedoch bei niedrigerer Framerate auf false setzen, wird es für alle sichtbar. Über direkte Eingabe hielt ich das für eine Beweglichkeit (letzter Ausweg).
Sunder
Sie sind sich nicht sicher, ob es das ist, was Sie wollen, aber wie wäre es, wenn Sie das Cursor-Sprite ändern, während es sich in Ihrem Fenster befindet, und es dann immer sichtbar machen?
William Mariager
Das ist genau das, was ich tue. Die Sache ist, dass ich es nicht nur zeigen möchte, sondern auch die genaue Position der Maus kennen möchte. Aber was ich bekomme, ist etwas hinter dem zurück, was es sein sollte.
Sunder

Antworten:

16

Was Sie sehen, ist keine Eingangsverzögerung.

Um die Position des Cursors in Windows zu ermitteln, können Sie WM_MOUSEMOVEoder verwenden GetCursorPos. Beide geben die Position des Cursors an, nachdem Windows ihn verarbeitet hat, und wenden beispielsweise Beschleunigung an. Dies ist die Cursorposition, die Windows verwendet, auch zum Zeichnen. Und fast immer das, was Sie auch verwenden möchten.

Dies ist, was XNA verwendet . Speziell GetCursorPos( MSDN ). Dies bedeutet, dass Sie beim Aufrufen Mouse.GetStatedie wahre Position des Cursors erhalten, wie Windows sie sieht - praktisch ohne Verzögerung.

Jetzt können Sie WM_INPUT(oder DirectInput, obwohl das veraltet ist) verwenden. Dies gibt Ihnen die rohen Zeigerdaten. Dies ist, bevor Windows Dinge wie Beschleunigung anwenden kann, und ist normalerweise nicht das, was Sie wollen.

Was Sie sehen, ist die Ausgangsverzögerung.

Dies liegt am " Hardware-Cursor ". Dies ist ein kleiner Sprit , das über den Bildschirm von der GPU an dem gezogen wird sehr Ende seiner Pipeline. Und ich meine das Ende . Es kommt nach dem Bildspeicher - es wird in den Datenstrom eingefügt, während das Bild an den Monitor gesendet wird. Der Grund, warum es so schnell reagiert, ist, dass seine Position durch direktes Einstellen der GPU-Register festgelegt wird. Es gibt überhaupt kein Warten in der Pipeline.

Ihr Spiel muss dagegen die GPU-Pipeline durchlaufen. Dies führt zu zahlreichen Verzögerungen. Das problematischste davon ist für Sie die Doppelpufferung - die Sie (da bin ich mir ziemlich sicher) in XNA 4 nicht deaktivieren können. Sie zeichnen nicht direkt in den Frame-Puffer - Sie zeichnen in den Backbuffer. Was alle ~ 16ms (bei 60FPS) präsentiert wird. Das bedeutet, dass zwischen dem Empfang des Ergebnisses Mouse.GetState, das auf diesem Ergebnis basiert, mindestens 16 ms liegen . Wahrscheinlich länger. Sicher viel langsamer als der Hardware-Cursor.

Was sind die Lösungen?

Eine Möglichkeit besteht darin, SetCursor( MSDN ) zu verwenden, um das Bild, das vom Hardware-Cursor angezeigt wird, in ein Bild zu ändern, das besser zu Ihrem Spiel passt (oder einfach mit dem Windows-Cursor zu leben).

Und das andere (weitaus einfacher) ist, einfach die Verzögerung zu akzeptieren und Game.IsMouseVisible = falsedie relative Verzögerung auszublenden. Zeigen Sie Ihren eigenen Cursor im Spiel an. Es wird 16 ms langsamer sein als der versteckte Windows-Cursor - aber wen interessiert das? Spieler sind daran gewöhnt. Und 16 ms sind sowieso visuell kaum wahrnehmbar (deshalb rendern wir Dinge mit 60 fps).

Andrew Russell
quelle
Vielen Dank für die ausführliche Erklärung der Angelegenheit. Höchstwahrscheinlich bleibe ich bei der XNA-Maus. Warten Sie etwas, bevor Sie akzeptieren, falls jemand eine zusätzliche Problemumgehung dafür hat.
Sunder
Ich denke, die Verzögerung zu akzeptieren oder nicht, ist eine Frage, die durch Spieltests beantwortet werden sollte.
Zonko