Tıklama hareketi ile bir alanı nasıl sınırlayabilirim?


11

Biraz genel bir başlık için özür dilerim. Yapmaya çalıştığım şeyi nasıl yapacağım konusunda pek bir fikrim yok, bu da olası bir çözümü araştırmayı bile zorlaştırıyor.

Ben bir çeşit yol işaretleyici uygulamaya çalışıyorum (belki de bunun için en uygun isim var, ama bu ben gelebilir en iyisidir).

Oyuncunun önünde, oyuncunun sırasını planlamayı bitirdiğinde nasıl hareket edeceğini belirleyecek bir yol işaretçisi olacaktır. Oynatıcı işaretçiyi tıklatıp seçtiği konuma sürükleyebilir, ancak işaretleyici yalnızca tanımlı bir çalışma alanı (gri bit) içinde taşınabilir.

Yol İşaret Şeması

Şimdi iki sorunla karşılaştım:

Her şeyden önce, bu uygulanabilir alanı tam olarak nasıl tanımlamalıyım? Oynatılabilir açıyı oluşturmak için oyuncuya bir başlangıç ​​noktası olan iki vektör hayal edebilirim ve belki de bu iki yay, oynatıcının bulunduğu merkezi olan çevrelerden gelebilir, ama kesinlikle bunların nasıl koyacağını bilmiyorum birlikte.

İkincisi, işaretçinin yerleştirilebileceği alanı tanımladıktan sonra, işaretçinin yalnızca bu alanda kalmasını nasıl zorlayabilirim? Örneğin, oyuncu işaretleyiciyi tıklayıp sürüklerse, çalışma alanı içinde serbestçe hareket edebilir, ancak alanın sınırlarını terk etmemelidir. Örneğin, oyuncu işaretleyiciyi yukarı doğru sürüklemeye başlarsa, çalışma alanının sonuna gelinceye kadar yukarı doğru hareket edecektir (aşağıdaki ilk diyagram), ancak bundan sonra oyuncu yanlara doğru sürüklemeye başlarsa, işaretçi hareketsizken sürüklemeyi takip etmelidir. (aşağıdaki ikinci diyagram).

İlk Diyagram: Yukarı Doğru İkinci Diyagram: Sürüklemeyi takiben

Umarım bu çok kafa karıştırıcı değildir. Teşekkürler beyler.

Düzenleme: Bu bir fark yaratıyorsa, Marmalade SDK ile C ++ kullanıyorum.


Bence aradığınız terim "ara nokta" ve gri alanı matematiksel olarak tanımlayabilir misiniz? Sorununuzun çözümü muhtemelen çok daha kolay olacaktır.
John McDonald

Yol bulma ve benzeri ile ilgili olmayan ara noktalar? Ayrıca, gri alanı matematiksel olarak tanımlamak benim problemlerimden biri: PI, bir dikdörtgen veya bir daire gibi bir şey bulabileceğimi düşünüyorum, ancak bu tür bir şekil, yanlar için iki yay ve bir açıda diğer iki taraf ... biraz kafamın üstünde.
Vexille

Çözümler öncelikle platforma bağlı olduğundan, hangi dili ve / veya araç setini kullandığınızı da belirtmeniz gerekir.
Raceimaztion

Gerçekten mi? Ben bir algoritmik çözüm ya da sahte kod bile yardımcı olacağını düşündüm. Her halükarda soruyu yine de düzenleyeceğim.
Vexille

Şekli kutupsal koordinatlarda tanımlayın (karakter açısından maksimum açı ve karakterden minimum / maksimum mesafe). Ardından yol noktasını yalnızca fare bu sınırlar içindeyse, farenin bulunduğu yere güncelleyin. Bu extreem'lerden herhangi birini aşarsa, onu mümkün olan en extreem değerine yaslayın. Alanın içine tıklandığında güncellemeye başlayın ve fare serbest bırakıldığında durdurun.
ClassicThunder

Yanıtlar:


8

Sorunuzdaki gibi çalışılabilir bir alanı üç değerle tanımlayabilirsiniz:

float innerRadius;
float outerRadius;
float maxAngle;

Bu değerler , oyuncunun pozisyonu olabilecek veya olmayabilecek bir merkez noktaya dayanacaktır . Çalışılabilir alanın şekli, bu noktayı nereye yerleştirdiğinize bağlıdır.

resim açıklamasını buraya girin

Yukarıdaki örnekte, orta konum , oynatıcının arkasında belirli bir mesafe (diyelim ki 50 birim) bulunmaktadır . Bu kolayca şu şekilde hesaplanabilir:

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

İşaretçinin konumunu çalışılabilir alanla sınırlamak için, önce işaretçiyi normal şekilde hareket ettirin . Ardından , merkez nokta ile işaretçi arasındaki mesafeyi doğrulayın :

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

Son olarak, işaretçinin açısını belirtilen aralığa doğrulayın . Bunun için sözde kod kullanacağım:

- 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

Etrafında bir noktayı nasıl döndüreceğinize bakın. Trigonometri veya bir dönüşüm matrisi ile yapılabilir.

Ayrıca işaretçinin boyutunu dikkate almak ve telafi etmek için yarıçapı ve açıyı biraz daha küçük yapmak isteyebilirsiniz.

Düzenleme: İkinci düşüncede, önce açıyı, sonra mesafeyi doğrularsanız daha doğal görünebilir, bu yüzden her iki alternatifi de deneyin!


Harika bir çözüm! İki daire ve bir üçgen içeren bir şeyle karşılaştım, ancak çözümünüz bunu zarif bir şekilde basitleştiriyor. Açı doğrulaması hakkında, playerForward'dan maxAngle'da (ve başka bir -maxAngle'da) duran normalize edilmiş bir vektöre sahip olan çizgiler boyunca, sınır olması durumunda C-> M uzunluğu ile çarpılabilecek bir şey düşündüm. , açılı olarak. M'yi C etrafında döndürme çözümünüzün daha az maliyetli olacağını varsayıyorum, doğru mu?
Vexille

@Vexille Dönen bir cosve bir sinişlem içerir , bu yüzden emin değilim. Ancak bu iki vektörü hesaplamak için de döndürmeniz gerekir, ancak yalnızca ileri vektör değiştiğinde bunu yapmanız gerekir. Yine de çok önemli değil, uygulamayı tercih ettiğiniz birini seçin.
David Gouveia

10

Şeklin düzensiz olması ve sorunun matematiksel olarak tanımlanmaması durumunda sorunun nasıl çözülebileceğini düşünüyordum. Uyarı: Bu, kalp zayıflığı için değil, kirli bir çözümdür.

1. Bölgenizi alın:

resim açıklamasını buraya girin

2. Ve tek renkli bir bitmap'e dönüştürün:

resim açıklamasını buraya girin ve ölçek_0 olarak adlandır

3. Bitmap'i klonlayın ve% 50'ye kadar ölçeklendirin:

resim açıklamasını buraya girin ve ölçek olarak adlandırın

4. 4 piksel genişlik / yükseklikten daha küçük bir bitmap olana kadar:

resim açıklamasını buraya girin resim açıklamasını buraya girin resim açıklamasını buraya girin resim açıklamasını buraya girin resim açıklamasını buraya girin ölçek: 2, 3, 4, 5, 6

5. Şimdi farklı çözünürlüklerde monokrom bitmapler olarak alanımız var: resim açıklamasını buraya girin

6. Son görüntüyü (burada "scale_6") alın ve tüm pikselleri arasında yineleyin.

  • her pikselin koordinatlarını ekran koordinatlarına x = Math.pow ( 2, scale_level );çevirir : burada scale_level "scale_" dan sonra eklediğimiz sayıdır. Dörtlü bir ağaç seviyesi olarak da çalışmamıza rağmen, buna dörtlü bir ağaç seviyesi de diyebiliriz. Aynı işlemi y ile yapın.
  • çevrilmiş x & y'deki pikselin siyah olup olmadığını kontrol edin. Değilse, o zaman şeklin bir parçası değildir ve sadece continuedöngünün bir sonraki adımına geçmelisiniz
  • pikselin fare imlecine daha önce kontrol edilen pikselden daha yakın olup olmadığını kontrol edin - evet ise, pikselin koordinatlarını kaydedin - çevirmeden önce, bitmap içindeki koordinatlar olan koordinatları kullanın.
  • döngünün sonunda, bu koordinatları 2 ile çarpın: x *= 2; y*=2;sonraki görüntüdeki koordinatlara dönüştürmek için (önceki ölçek)

7. Önceki görüntüyü çekin (burada "scale_5"), ancak tüm piksellerde döngü yapmayın; x = kaydedilmiş_x ile başlar ve x = kaydedilmiş_x + 2 ile biter, y ile aynıdır. Yani, şimdi her seviye için sadece 4 piksel döngü olacak! Gerisi s. 6.

8. İlk resmi çekin (en büyüğü = en büyük çözünürlüğe sahip olanı), tekrar 4 piksel arasında döngü yapın ve sonunda fare imlecine en yakın piksele sahip olun:

resim açıklamasını buraya girin

resim açıklamasını buraya girin

resim açıklamasını buraya girin

9. Ancak, "M" yi burada bir nokta olarak ele alıyorum. Tamamen uyan bir daire olmasını istiyorsanız, önce şekli circle.radiuspiksel olarak daraltmanız (daraltmanız) gerekir .

Bu algoritmanın yalnızca tek renkli değil, gri tonlamalı görüntüler kullanacağınız ve bir pikseli beyaz değilse "dolu" ve tam olarak beyazsa "boş" olarak kullanacağınız zaman işe yarayacağını düşündüm. VEYA yeniden boyutlandırıyorsanız algoritma, bu 4 pikselden en az birinin beyaz olmadığı her seferinde 4 piksellik her grubu 1 siyah piksele dönüştürür.


2
Matematiksel olarak ifade edilmesi zor (imkansız değilse) şekiller için bir cevap için +1.
Cypher

Vay canına, çok ilginç. +1 de: D
Vexille

Gerçek projede uyguladım ve bazı problemlerin ortaya çıktığını söylemeliyim. Temel olarak, adlandırılmış en yakın ızgara hücreyi almak ızgara hücreleri, bir listesini yapmak gerekir closest, ve mesafe için kontrol uzak noktaya closestedelim ismi mesafesi - furthest_dist. Şimdi listeden en yakın noktası olan tüm hücreleri kaldırmanız furthest_distve daha derine inmeniz gerekiyor. Yani böyle bir şey yerine: i.imgur.com/4UuFo.png Bunun gibi bir şey: i.imgur.com/dyTT3.png
Markus von Broady
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.