C # / XNA mendapatkan posisi mouse perangkat keras

10

Saya menggunakan C # dan mencoba untuk mendapatkan posisi mouse perangkat keras. Hal pertama yang saya coba adalah fungsionalitas XNA sederhana yang mudah digunakan

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

Setelah itu saya melakukan menggambar mouse juga, dan membandingkannya dengan mouse hardware windows, mouse baru ini dengan koordinat yang disediakan xna adalah "slacking off". Maksud saya, bahwa itu di belakang oleh beberapa frame. Misalnya jika game berjalan pada 600 fps, tentu saja itu akan responsif, tetapi pada 60 fps perangkat lunak penundaan mouse tidak lagi dapat diterima. Karena itu saya mencoba menggunakan apa yang saya pikir adalah mouse perangkat keras,

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

tetapi hasilnya persis sama. Saya juga mencoba mendapatkan kursor bentuk Windows, dan itu jalan buntu juga - bekerja, tetapi dengan penundaan yang sama. Berputar-putar dengan fungsionalitas xna:

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

memang mengubah waktu tunda untuk alasan yang agak jelas, tetapi intinya adalah bahwa terlepas itu masih di belakang mouse Windows default. Saya pernah melihat di beberapa permainan, bahwa mereka menyediakan opsi untuk mouse yang dipercepat perangkat keras, dan yang lain (saya pikir) sudah secara default. Adakah yang bisa memberikan petunjuk tentang cara mencapai itu.

Memisahkan
sumber
2
Saya pikir tidak Mouse.GetState()rusak. Apakah Anda yakin bahwa Anda mendapatkan posisi mouse di bingkai yang sama seperti saat Anda menggambarnya? Ingat juga bahwa kursor Windows memiliki akselerasi / deselerasi yang diaktifkan, sehingga terasa lebih responsif. Jika Anda ingin lebih dekat dengan perangkat keras, Anda harus menekan DirectInput, yang akan memberi Anda gerakan delta alih-alih posisi mouse absolut. Tapi saya percaya Mouse.GetState()masih cara yang benar untuk melakukannya di XNA.
Panda Pajama
Tidak, Mouse.GetState()tidak rusak, dan selama IsFixedTimeStep == trueorang seharusnya tidak dapat melihat penundaan kecuali dibandingkan langsung dengan windows mouse yang terlihat. Namun pengaturan IsFixedTimeStep ke false di framerate yang lebih rendah menjadi terlihat oleh semua orang. Tentang input langsung saya menganggap itu suatu kemungkinan (pilihan terakhir).
Sunder
Tidak yakin apakah itu yang Anda inginkan, tetapi bagaimana dengan mengubah sprite kursor saat berada di jendela Anda, dan kemudian membuatnya selalu terlihat?
William Mariager
Itulah tepatnya yang saya lakukan, masalahnya adalah saya tidak ingin hanya menunjukkannya, tetapi untuk mengetahui posisi pasti dari mouse juga. Tapi apa yang saya dapatkan sedikit ketinggalan dari apa yang seharusnya.
Sunder

Jawaban:

17

Apa yang Anda lihat bukan input lag.

Untuk mendapatkan posisi kursor di Windows Anda bisa menggunakan WM_MOUSEMOVEatau GetCursorPos. Keduanya menyediakan posisi kursor setelah Windows memprosesnya, menerapkan hal-hal seperti akselerasi. Ini adalah posisi kursor yang digunakan Windows, termasuk untuk menggambar. Dan hampir selalu apa yang ingin Anda gunakan juga.

Inilah yang digunakan XNA . Khususnya GetCursorPos( MSDN ). Ini berarti bahwa, ketika Anda menelepon Mouse.GetState, Anda mendapatkan posisi kursor yang sebenarnya seperti yang dilihat Windows - dengan praktis tidak ada penundaan.

Sekarang, Anda dapat menggunakan WM_INPUT(atau DirectInput, meskipun sudah usang). Ini memberi Anda data pointer mentah. Ini sebelum Windows dapat menerapkan hal-hal seperti akselerasi, dan biasanya bukan yang Anda inginkan.

Apa yang Anda lihat adalah output lag.

Ini karena " kursor perangkat keras ". Ini adalah sprite kecil yang akan ditarik lebih layar dengan GPU di sangat akhir pipa nya. Dan maksud saya akhirnya . Muncul setelah buffer bingkai - itu akan dimasukkan ke dalam aliran data saat gambar dikirim ke monitor. Alasannya bereaksi sangat cepat adalah karena posisinya diatur dengan langsung mengatur register GPU. Tidak ada menunggu di dalam pipa sama sekali.

Game Anda, di sisi lain, harus melalui jalur GPU. Ini menambahkan banyak penundaan sendiri. Yang paling bermasalah dari ini untuk Anda adalah buffering ganda - yang (saya cukup yakin) Anda tidak bisa mematikannya di XNA 4. Anda tidak langsung menggambar ke buffer frame - Anda menggambar ke backbuffer. Yang disajikan setiap ~ 16ms (at 60FPS). Itu berarti Anda melihat minimal 16ms antara menerima hasil Mouse.GetStatemendapatkan sesuatu berdasarkan hasil di layar. Mungkin lebih lama Tentunya jauh lebih lambat daripada kursor perangkat keras.

Jadi apa solusinya?

Salah satunya adalah menggunakan SetCursor( MSDN ) untuk mengubah gambar yang akan ditampilkan oleh kursor perangkat keras, untuk menjadi gambar yang lebih sesuai dengan permainan Anda (atau hanya tinggal dengan kursor Windows).

Dan yang lainnya (jauh lebih mudah) adalah dengan hanya menerima lag, dan mengatur Game.IsMouseVisible = falseuntuk menyembunyikan lag relatif. Tampilkan kursor Anda sendiri dalam game. Ini akan menjadi 16 ms lebih lambat dari kursor Windows yang tersembunyi - tetapi siapa yang peduli? Gamer sudah terbiasa dengan itu. Dan 16ms hampir tidak terlihat secara visual (itu sebabnya kami membuat hal-hal di 60FPS).

Andrew Russell
sumber
Terima kasih atas penjelasan detail masalah ini. Kemungkinan besar saya akan tetap menggunakan mouse XNA. Akan menunggu sedikit sebelum menerima jika seseorang memiliki solusi tambahan untuk itu.
Sunder
Saya kira menerima lag atau tidak adalah pertanyaan yang harus dijawab dengan playtesting.
Zonko