Bagaimana cara membatasi gerakan click'n'drag ke suatu area?

11

Saya minta maaf untuk judul yang agak umum. Saya benar-benar tidak memiliki banyak petunjuk tentang bagaimana mencapai apa yang saya coba lakukan, yang membuatnya semakin sulit untuk meneliti solusi yang mungkin.

Saya mencoba menerapkan semacam penanda jalur (mungkin ada nama yang paling cocok untuk itu, tapi ini yang terbaik yang bisa saya dapatkan).

Di depan pemain akan ada penanda jalur, yang akan menentukan bagaimana pemain akan bergerak begitu dia selesai merencanakan gilirannya. Pemain dapat mengklik dan menarik penanda ke posisi yang mereka pilih, tetapi penanda hanya dapat dipindahkan dalam area kerja yang ditentukan (bit abu-abu).

Diagram Jalur Penanda

Jadi saya sekarang terjebak dengan dua masalah:

Pertama-tama, bagaimana tepatnya saya harus mendefinisikan area yang bisa diterapkan itu? Saya bisa membayangkan mungkin dua vektor yang memiliki pemain sebagai titik awal untuk membentuk sudut yang bisa diterapkan, dan mungkin dua busur itu bisa berasal dari lingkaran yang memiliki pusat di mana pemain berada, tetapi saya pasti tidak tahu bagaimana meletakkan semua ini bersama.

Dan kedua, setelah saya menentukan area di mana marker dapat ditempatkan, bagaimana saya bisa menegakkan bahwa marker hanya boleh berada di dalam area itu? Misalnya, jika pemain mengklik dan menyeret penanda di sekitar, itu dapat bergerak bebas di dalam wilayah kerja, tetapi tidak boleh meninggalkan batas-batas daerah tersebut. Jadi misalnya, jika pemain mulai menyeret penanda ke atas, ia akan bergerak ke atas sampai menyentuh ujung area kerja (diagram pertama di bawah), tetapi jika setelah itu pemain mulai menyeret ke samping, penanda harus mengikuti seret saat masih dalam area (diagram kedua di bawah).

Diagram Pertama: Bergerak Ke Atas Diagram Kedua: Mengikuti seret

Saya harap ini tidak terlalu membingungkan. Terima kasih kawan

Sunting: Dalam hal ini membuat perbedaan, saya menggunakan C ++ dengan Marmalade SDK.

Vexille
sumber
Saya pikir istilah yang Anda cari adalah "waypoint", dan dapatkah Anda secara matematis mendefinisikan area abu-abu? Solusi untuk masalah Anda mungkin akan jauh lebih mudah jika itu.
John McDonald
Arpoint waypoint terkait dengan pathfinding dan semacamnya? Juga, secara matematis mendefinisikan area abu-abu adalah salah satu masalah saya: PI pikir saya bisa mengetahui sesuatu seperti persegi panjang atau bahkan lingkaran, tetapi bentuk semacam itu, dengan dua lengkungan untuk sisi dan dua sisi lainnya pada sudut ... Ini sedikit di atas kepalaku.
Vexille
Anda juga perlu menentukan bahasa dan / atau alat bantu apa yang Anda gunakan, karena solusinya tergantung pada platform.
Raceimaztion
Betulkah? Saya pikir solusi algoritme atau bahkan kodesemu akan membantu. Saya akan mengedit pertanyaannya, untuk berjaga-jaga.
Vexille
Tentukan bentuk dalam koordinat polar (sudut maks dari sudut karakter dan jarak min / maks dari karakter). Maka hanya perbarui titik arah ke tempat mouse berada jika mouse berada dalam batas tersebut. Jika melebihi salah satu dari extreem itu, snap ke nilai ekstreem sebanyak mungkin. Mulai perbarui ketika diklik di dalam area dan berhenti ketika mouse dilepaskan.
ClassicThunder

Jawaban:

8

Anda dapat mendefinisikan area yang bisa diterapkan seperti yang ada di pertanyaan Anda dengan tiga nilai:

float innerRadius;
float outerRadius;
float maxAngle;

Nilai-nilai ini akan didasarkan pada titik tengah yang mungkin atau tidak mungkin posisi pemain. Bentuk area yang bisa diterapkan tergantung pada tempat Anda menempatkan titik ini.

masukkan deskripsi gambar di sini

Pada contoh di atas posisi tengah terletak jarak tertentu (misalkan 50 unit) di belakang pemain. Ini dapat dengan mudah dihitung sebagai:

float offset = -50;
Vector2 centerPosition = playerPosition + offset * playerForward;

Untuk membatasi posisi marker pada area yang bisa dikerjakan, pertama-tama pindahkan marker seperti biasa. Kemudian validasi jarak antara titik pusat dan penanda:

Vector2 direction = markerPosition - centerPosition;
float distance = direction.Length();
direction.Normalize();
markerPosition = centerPosition + direction * clamp(distance, innerRadius, outerRadius);

Terakhir, validasikan sudut marker ke rentang yang ditentukan. Saya akan menggunakan pseudocode untuk yang satu ini:

- Find angle between vector C->M and vector playerForward
- If abs(angle) <= maxAngle Then do nothing
- Else If angle > 0 Then rotate M around C by maxAngle-angle
- Else If angle < 0 Then rotate M around C by -maxAngle-angle

Lihatlah ke sekeliling tentang cara memutar titik di sekitar titik lainnya. Ini dapat dilakukan dengan trigonometri atau matriks transformasi.

Anda mungkin juga ingin mempertimbangkan ukuran marker dan membuat jari-jari dan sudut sedikit lebih kecil untuk mengimbanginya.

Sunting: Setelah dipikir-pikir, mungkin terlihat lebih alami jika Anda memvalidasi sudut terlebih dahulu, lalu jarak, jadi coba kedua alternatif!

David Gouveia
sumber
Solusi hebat! Saya telah menemukan sesuatu yang melibatkan dua lingkaran dan segitiga, tetapi solusi Anda dengan elegan menyederhanakannya. Tentang validasi sudut, saya telah memikirkan sesuatu di sepanjang garis memiliki vektor dinormalisasi yang berdiri di maxAngle (dan lain di -maxAngle) dari playerForward, yang dapat dikalikan dengan panjang C-> M jika itu adalah batas , dari sudut pandang bijaksana. Saya berasumsi solusi Anda memutar M sekitar C akan lebih murah, benarkah itu?
Vexille
@Ville Ya, berputar melibatkan operasi cosdan a sin, jadi saya tidak yakin. Tetapi untuk menghitung kedua vektor tersebut, Anda juga perlu memutarnya, meskipun Anda hanya perlu melakukannya ketika vektor maju berubah. Seharusnya tidak terlalu penting, pilih yang Anda inginkan untuk diterapkan.
David Gouveia
10

Saya berpikir bagaimana masalah bisa diselesaikan jika bentuknya tidak beraturan, dan orang tidak dapat mendefinisikannya secara matematis. Peringatan: ini solusi kotor, bukan untuk yang lemah hati.

1. Ambil area Anda:

masukkan deskripsi gambar di sini

2. Dan mengubahnya menjadi bitmap monokromatik:

masukkan deskripsi gambar di sini dan beri nama scale_0

3. Mengkloning bitmap dan menurunkannya menjadi 50%:

masukkan deskripsi gambar di sini dan beri nama itu scale_1

4. Dan seterusnya, sampai ada bitmap kurang dari 4 piksel lebar / tinggi:

masukkan deskripsi gambar di sini masukkan deskripsi gambar di sini masukkan deskripsi gambar di sini masukkan deskripsi gambar di sini masukkan deskripsi gambar di sini skala: 2, 3, 4, 5, 6

5. Sekarang kami memiliki area kami sebagai bitmap monokromatik dari resolusi yang berbeda: masukkan deskripsi gambar di sini

6. Ambil gambar terakhir (di sini "scale_6") dan ulangi semua pikselnya.

  • terjemahkan koordinat setiap piksel ke koordinat layar: di x = Math.pow ( 2, scale_level );mana scale_level adalah angka yang kami tambahkan setelah "scale_". Kita juga bisa menyebutnya tingkat pohon quad, meskipun kita tidak benar-benar bekerja dengan pohon quad. Lakukan hal yang sama dengan y.
  • periksa apakah piksel pada terjemahan x & y berwarna hitam. Jika tidak, maka itu bukan bagian dari bentuk, dan Anda hanya harus continueke langkah berikutnya dari loop
  • periksa apakah pikselnya lebih dekat ke kursor mouse daripada piksel yang diperiksa sebelumnya - jika ya, simpan koordinat piksel - gunakan koordinat sebelum terjemahan, yaitu koordinat di dalam bitmap.
  • di akhir loop, kalikan koordinat ini dengan 2: x *= 2; y*=2;untuk menerjemahkannya ke koordinat di gambar berikutnya (skala sebelumnya)

7. Ambil gambar sebelumnya (di sini "scale_5"), tetapi jangan melewati semua piksel; mulai dari x = Saved_x dan akhiri dengan x = Saved_x + 2, sama dengan y. Yaitu, karena sekarang Anda hanya akan mengulangi 4 piksel untuk setiap level! Sisanya seperti pada p. 6.

8. Ambil gambar pertama (terbesar = satu dengan resolusi terbesar), lagi-lagi loop melalui 4 piksel, dan Anda akhirnya memiliki piksel yang paling dekat dengan kursor mouse:

masukkan deskripsi gambar di sini

masukkan deskripsi gambar di sini

masukkan deskripsi gambar di sini

9. Namun, saya memperlakukan "M" sebagai poin di sini. Jika Anda ingin menjadi lingkaran yang benar-benar pas, Anda harus mengontrak (mengecilkan) bentuk dengan circle.radiuspiksel terlebih dahulu.

Saya pikir saya akan menambahkan bahwa algoritma ini hanya akan bekerja jika Anda akan menggunakan bukan gambar monokromatik tetapi skala abu-abu dan memperlakukan piksel sebagai "penuh" jika tidak putih, dan sebagai "kosong" jika itu benar-benar putih ... ATAU jika ukuran Anda Algoritma mengubah setiap kelompok 4 piksel menjadi 1 piksel hitam setiap kali ketika setidaknya satu dari 4 piksel ini tidak berwarna putih.

Markus von Broady
sumber
2
Memberi +1 untuk jawaban untuk bentuk yang sulit (jika bukan tidak mungkin) untuk diekspresikan secara matematis.
Cypher
Wow, sangat menarik. +1 juga: D
Vexille
Saya menerapkannya dalam proyek nyata, dan saya harus mengatakan beberapa masalah muncul. Pada dasarnya, Anda perlu membuat daftar sel kisi, tempat Anda mengambil sel kisi terdekat bernama closest, dan memeriksa jarak ke titik terjauh di closest- mari beri nama jarak furthest_dist. Sekarang Anda perlu menghapus dari daftar semua sel yang memiliki titik terdekat lebih jauh dari furthest_distdan naik level lebih dalam. Jadi, alih-alih sesuatu seperti ini: i.imgur.com/4UuFo.png Ini seperti ini: i.imgur.com/dyTT3.png
Markus von Broady