Apakah ide yang buruk untuk "memetakan" posisi mouse di layar sehingga deteksi tabrakan berfungsi terlepas dari resolusi?

16

Pertimbangkan gim yang memiliki resolusi standar 800x600. Objek dengan topeng tabrakan ditempatkan di dunia game berukuran 800x600. Topeng tabrakan dapat mendeteksi ketika mouse bertabrakan dengan mereka.

Sekarang, pertimbangkan untuk menskala permainan hingga 1024x768 (anggap kita menskala grafik dengan hanya merender semuanya menjadi satu lapisan dan kemudian menaikkan seluruh lapisan sekaligus). Kami memiliki dua opsi untuk membuat tabrakan dengan mouse berfungsi dengan baik dalam resolusi baru ini:

A.) Skala dunia ke 1024x768 dan skala topeng tabrakan setiap objek sesuai.

B.) "Peta" posisi mouse ke dunia asli (800x600).

Yang saya maksud dengan "memetakan" hanyalah skala posisi mouse ke dunia 800x600 asli. Jadi misalnya, jika posisi mouse di layar adalah (1024, 768), maka posisi mouse di dunia adalah (800, 600).

Sekarang jelas, opsi B membutuhkan cara komputasi yang lebih sedikit dan mungkin kurang rentan terhadap kesalahan geometrik, tetapi juga terasa agak "meretas" bagi saya, seperti ada konsekuensi yang tidak terduga dengan menggunakan metode ini yang akan sangat sulit untuk diperbaiki nanti.

Metode mana yang harus saya gunakan: A, B, atau yang lainnya?

pengguna3002473
sumber
2
Seperti yang ditunjukkan oleh Classic Thunder, tampilan koordinat tidak boleh sama dengan koordinat dunia, atau koordinat objek. Biasanya Anda ingin memiliki transformasi (pada dasarnya, seperti yang Anda katakan pemetaan , tetapi biasanya dilakukan dengan matematika matriks).
Dan

Jawaban:

38

Biasanya (bahkan untuk game 2d) ada sistem koordinat terpisah untuk game yang independen dari resolusi, ini biasanya disebut sebagai ruang dunia. Ini memungkinkan Anda untuk skala ke resolusi sewenang-wenang.

Cara termudah untuk mencapai ini adalah menggunakan Kamera 2D, yang pada dasarnya adalah sebuah matriks yang mendefinisikan transisi dari ruang dunia (unit sewenang-wenang Anda) ke ruang layar (piksel pada layar). Ini membuat berurusan dengan hal-hal sepele matematika.

Lihatlah bagian di bawah ini di XNA 2d Camera Scrolling - mengapa menggunakan matriks transformasi?

Itu membuatnya sangat mudah untuk mengkonversi antara definisi sistem koordinat

Untuk beralih dari layar ke ruang dunia cukup gunakan Vector2.Transform. Ini biasanya digunakan untuk mendapatkan lokasi mouse di dunia untuk pengambilan objek.

Vector2.Transform(mouseLocation, Matrix.Invert(Camera.TransformMatrix));

Untuk pergi dari dunia ke ruang layar cukup lakukan sebaliknya.

Vector2.Transform(mouseLocation, Camera.TransformMatrix);

Tidak ada kekurangan untuk menggunakan matriks selain butuh sedikit pembelajaran.

Klasik
sumber
... dan memang, secara umum, perangkat keras modern dirancang untuk operasi matriks melalui arsitektur vektorisasi seperti SSE, NEON, dll. Jadi itu adalah pilihan cerdas - Anda akan menghemat siklus CPU melalui pendekatan non-vektor.
Insinyur
1
Penafian ringan: XNA dihentikan oleh microsoft, tetapi Monogame menggunakan API yang sama.
Pharap
1
Tentu, pintar menggunakan matriks untuk menerjemahkan antara dua sistem koordinat. Tetapi bagaimana hal itu menjawab pertanyaan? Anda masih harus memutuskan, apakah Anda ingin memetakan dari sistem A ke sistem B atau dari B ke A dan apa konsekuensinya, jika ada.
mastov
"Apakah itu ide buruk untuk" memetakan "posisi mouse di layar sehingga deteksi tabrakan bekerja terlepas dari resolusi?" dijawab oleh "pintar menggunakan matriks untuk menerjemahkan antara dua sistem koordinat" ...
ClassicThunder
Saya juga menjawab, "Anda masih harus memutuskan, apakah Anda ingin memetakan dari sistem A ke sistem B atau dari B ke A dan apa konsekuensinya, jika ada." dengan mengatakan Anda harus menggunakan yang sewenang-wenang yang tidak terikat pada resolusi dan skala darinya. Jadi C -> A atau C -> B tergantung pada apakah A atau B adalah resolusi. Tentu saja Anda dapat memiliki C sama dengan resolusi dasar yang Anda desain dan skala dari sana. Intinya adalah semua matematika terjadi dalam sistem koordinat yang sama dan Anda hanya mengukur untuk rendering.
ClassicThunder
2

Pilihan lain adalah: Pada setiap acara gerakan mouse input, pindahkan kursor mouse dalam game dengan jumlah piksel game yang sesuai dengan jumlah piksel dalam acara mouse. Ini datang secara alami untuk game 3D yang mengunci pointer mouse asli ke tengah dan memutar arah tujuan dengan jumlah yang sesuai dengan gerakan mouse input, tetapi Anda bisa melakukannya dengan cara yang sama dengan menggerakkan sprite mewakili kursor mouse dalam game.

Anda jelas harus mengabaikan setiap kejadian gerakan input mouse yang disebabkan oleh membengkokkannya ke tengah, dan jika game Anda memiliki jeda input sama sekali, kursor yang tidak responsif akan menjadi aspek yang paling menggelegar dan terlihat.

Sebagian, solusi apa yang Anda gunakan tergantung pada seberapa penting posisi mouse untuk bermain game. Jika ini adalah RTS dan pemain cukup mengklik untuk memilih unit, Anda mungkin bisa pergi dengan A atau B mana saja yang lebih mudah. Jika itu adalah penembak top-down dan mouse secara langsung mengontrol pergerakan karakter, maka Anda mungkin menginginkan solusi yang lebih mendalam yang membatasi jumlah variabilitas dalam bagaimana karakter dapat bergerak berdasarkan tidak hanya resolusi tetapi juga hal-hal seperti pergerakan mouse kecepatan. Jika mouse mengontrol arah penargetan, maka Anda akan menginginkan solusi yang berbeda, dll.

Random832
sumber
0

Jawaban ClassicThunder benar, tetapi saya ingin memberikan contoh cara alternatif / sederhana untuk mencapai efek yang diinginkan. Ini adalah solusi yang lebih sederhana untuk pembuatan prototipe cepat, kasus di mana Anda tidak memiliki akses ke perpustakaan berfitur lengkap, atau untuk kasus di mana Anda tidak memiliki akses ke GPU (misalnya dalam sistem tertanam).

Untuk melakukan pemetaan tersebut, Anda dapat menggunakan fungsi berikut (menganggapnya didefinisikan di kelas statis Helper):

static float Map(float value, float fromLow, float fromHigh, float toLow, float toHigh)
{
    return ((value - fromLow) / (fromHigh - fromLow) * (toHigh - toLow)) + toLow;
}

(Anda tidak menentukan bahasa, tetapi saya melihat Anda memiliki pengetahuan tentang C #, jadi contoh saya adalah dalam C #.)

Anda kemudian dapat menggunakan fungsi ini seperti:

float mouseXInWorld = Helper.Map(Mouse.X, 0, Screen.Width - 1, camera.Bounds.X, camera.Bounds.X + camera.Bounds.Width - 1);
float mouseYInWorld = Helper.Map(Mouse.Y, 0, Screen.Height - 1, camera.Bounds.Y, camera.Bounds.Y + camera.Bounds.Height - 1);

Dimana camera.Boundspersegi panjang yang mewakili area dunia yang dapat dilihat kamera (yaitu area yang diproyeksikan ke layar).

Jika Anda memiliki kelas Vectoratau Point, Anda bisa menyederhanakan proses ini lebih lanjut dengan membuat setara 2D dari fungsi peta, seperti:

static Vector Map(Vector value, Rectangle fromArea, Rectangle toArea)
{
    Vector result = new Vector();
    result.X = Map(value.X, fromArea.X, fromArea.X + fromArea.Width - 1, toArea.X, toArea.X + toArea.Width - 1);
    result.Y = Map(value.Y, fromArea.Y, fromArea.Y + fromArea.Height - 1, toArea.Y, toArea.Y + toArea.Height - 1);
    return result;
}

Yang akan membuat kode pemetaan Anda menjadi satu garis sederhana:

Vector mousePosInWorld = Map(Mouse.Pos, Screen.Bounds, camera.Bounds);
Pharap
sumber
-1

Opsi (C): ubah resolusi layar kembali ke 800x600.

Bahkan jika Anda tidak melakukan ini, anggap itu sebagai eksperimen pikiran. Dalam hal ini, itu adalah tanggung jawab layar untuk mengubah ukuran gambar agar sesuai dengan ukuran fisiknya, dan kemudian tanggung jawab sistem operasi untuk memberi Anda peristiwa penunjuk pada resolusi 800x600.

Saya pikir itu semua tergantung pada apakah grafik Anda adalah bitmap atau vektor. Jika bitmap, dan Anda merender ke buffer 800x600, maka ya itu jauh lebih mudah untuk memetakan kembali mouse ke ruang layar dan mengabaikan resolusi layar nyata. Namun kerugian besar dari ini adalah bahwa peningkatan dapat terlihat jelek, terutama jika Anda melakukan gaya grafis "8-bit".

pjc50
sumber