Versi pendek
Apakah ada pola desain untuk mendistribusikan label kendaraan dengan cara yang tidak tumpang tindih, menempatkannya sedekat mungkin dengan kendaraan yang dimaksud? Jika tidak, adakah metode yang saya sarankan dapat digunakan? Bagaimana Anda menerapkannya sendiri?
Versi diperpanjang
Dalam game yang saya tulis ini, saya memiliki visi mata-burung dari kendaraan udara saya. Saya juga memiliki label kecil dengan kunci-data di samping masing-masing kendaraan. Ini adalah tangkapan layar aktual:
Sekarang, karena kendaraan bisa terbang di ketinggian yang berbeda, ikon mereka bisa tumpang tindih. Namun saya tidak ingin label mereka tumpang tindih (atau label dari kendaraan 'A' tumpang tindih dengan ikon kendaraan 'B').
Saat ini, saya dapat mendeteksi tabrakan antara sprite dan saya cukup menjauhkan label yang menyinggung ke arah yang berlawanan dengan sprite yang tumpang tindih . Ini berfungsi dalam sebagian besar situasi, tetapi ketika wilayah udara penuh sesak, label dapat didorong sangat jauh dari kendaraannya, bahkan jika ada alternatif "cerdas" alternatif. Misalnya saya mendapatkan:
B - label
A -----------label
C - label
di mana akan lebih baik (= label lebih dekat ke kendaraan) untuk mendapatkan:
B - label
label - A
C - label
EDIT: Ini juga harus dipertimbangkan bahwa di samping kasus kendaraan yang tumpang tindih, mungkin ada konfigurasi lain di mana label kendaraan bisa tumpang tindih (contoh ASCII-art menunjukkan misalnya tiga kendaraan yang sangat dekat di mana label A
akan tumpang tindih dengan ikon B
dan C
).
Saya punya dua ide tentang bagaimana memperbaiki situasi saat ini, tetapi sebelum menghabiskan waktu untuk mengimplementasikannya, saya berpikir untuk meminta saran kepada masyarakat (setelah semua itu kelihatannya seperti "masalah yang cukup umum" sehingga pola desain untuk itu bisa ada).
Untuk apa nilainya, inilah dua ide yang saya pikirkan:
Slot-isasi ruang label
Dalam skenario ini saya akan membagi semua layar menjadi "slot" untuk label. Kemudian, setiap kendaraan akan selalu menempatkan labelnya di tempat kosong terdekat (kosong = tidak ada sprite lain di lokasi itu).
Pencarian spiral
Dari lokasi kendaraan di layar, saya akan mencoba untuk menempatkan label pada sudut yang meningkat dan kemudian pada peningkatan radius, sampai lokasi yang tidak tumpang tindih ditemukan. Sesuatu di baris:
try 0°, 10px
try 10°, 10px
try 20°, 10px
...
try 350°, 10px
try 0°, 20px
try 10°, 20px
...
Jawaban:
Pada dasarnya masalah ini mirip dengan masalah penghindaran tabrakan. Ya, pesawat bisa terbang di ketinggian berbeda, tetapi label mereka semua pada "ketinggian" yang sama.
Ada algoritma seperti Unaligned Collision Avoidance , yang akan menjadi langkah ke arah yang tepat untuk Anda. Tentu saja untuk situasi Anda, label "ditambatkan" ke pesawat mereka, sehingga mereka memiliki rentang gerakan terbatas.
Jika Anda melihat Perilaku Berkelompok , Anda ingin menerapkan "aturan" pertama dalam berkelompok: tolakan jarak pendek. Namun, alih-alih "mengarahkan" ke arah yang jauh dari tetangga terdekat, Anda akan menggunakan vektor "jauh" sebagai lokasi penempatan label Anda.
Sebagai contoh:
Lingkaran hitam besar mewakili area pengaruh Anda, lingkaran hijau mewakili penempatan yang valid untuk label, titik hijau tengah adalah bidang yang saat ini Anda pertimbangkan, titik hijau kecil adalah titik pada lingkaran yang dipilih untuk penempatan label.
Sekarang titik-titik hitam bisa mewakili label lain, atau bidang lain. Saya tidak yakin yang mana yang akan bekerja paling baik, Anda mungkin mendapatkan penghindaran yang lebih baik jika mereka label lain, tapi saya tidak yakin. Jelas panah "force" adalah vektor arah antara pesawat Anda saat ini dan "objek pengaruh". Akhirnya, kotak adalah labelnya.
Jadi menggunakan contoh Anda di atas, saya pikir ini akan menghasilkan sesuatu seperti:
Menggunakan metode ini ada beberapa situasi Anda harus membuat kasus khusus, seperti tiga pesawat sejajar secara vertikal:
Ketiga label dapat flip flop dari kanan ke kiri, tergantung pada bagaimana Anda menentukan sudut label Anda. Pada dasarnya, Anda hanya perlu berhati-hati terhadap sudut-sudut di sekitar lingkaran tempat label Anda dapat beralih dari sudut mana mereka diambil: 0, 90, 180, 270.
Saya pikir pada akhirnya, ini akan terlihat agak rapi, menonton label saling menghindari. Jika terlalu mengganggu, mungkin Anda bisa membulatkan ke 10 derajat terdekat untuk gerakan yang kurang sering.
Maaf untuk detail aneh, sebagian besar dari hal ini saya pikirkan ketika saya membuat menu radial untuk permainan saya, tapi saya pikir dalam bentuk "dinamis" ini akan bekerja dengan cukup baik.
sumber
Setelah beberapa pemikiran, saya akhirnya memutuskan untuk menerapkan metode pencarian spiral yang saya jelaskan secara singkat dalam pertanyaan asli.
Alasannya adalah bahwa metode Byte56 membutuhkan perawatan khusus untuk kondisi tertentu, sedangkan pencarian spiral tidak, dan kode dengan cara yang sangat kompak . Juga, pencarian spriralling menekankan menemukan tempat yang lebih dekat ke kendaraan untuk menempatkan label, yang IMO adalah faktor utama dalam membuat peta dapat dibaca.
Namun tolong terus upvote jawabannya, karena ini tidak hanya berguna, tetapi juga ditulis dengan sangat baik!
Berikut screenshot dari hasil yang dicapai dengan kode spiral:
Dan inilah kode yang - meskipun tidak mandiri - memberikan ide tentang seberapa sederhana implementasinya:
Catatan 1 -
tag.place()
mengembalikan True jika tag sepenuhnya pada area layar / radar yang terlihat. Jadi baris itu berbunyi seperti "terus berputar jika tag berada di luar radar atau tumpang tindih dengan yang lain ..."Catatan 2 -
tag.connector.update
adalah metode yang menggambar garis yang menghubungkan ikon pesawat ke label / tag dengan informasi teks.sumber