Jak ograniczyć ruch Click'n'drag do obszaru?


11

Przepraszam za dość ogólny tytuł. Naprawdę nie mam pojęcia, jak osiągnąć to, co próbuję zrobić, co utrudnia nawet znalezienie możliwego rozwiązania.

Próbuję zaimplementować rodzaj znacznika ścieżki (być może jest dla niego najbardziej odpowiednia nazwa, ale jest to najlepsze, co mogłem wymyślić).

Przed graczem pojawi się znacznik ścieżki, który określi, w jaki sposób gracz poruszy się, gdy skończy planowanie swojej tury. Gracz może kliknąć i przeciągnąć znacznik do wybranej przez siebie pozycji, ale znacznik można przesunąć tylko w obrębie określonego obszaru roboczego (szary bit).

Schemat markera ścieżki

Więc teraz mam dwa problemy:

Po pierwsze, jak dokładnie powinienem zdefiniować ten wykonalny obszar? Mogę sobie wyobrazić, że może dwa wektory, w których gracz jest punktem początkowym do uformowania wykonalnego kąta, i może te dwa łuki mogą pochodzić z okręgów, które mają środek w miejscu, w którym znajduje się gracz, ale zdecydowanie nie wiem, jak to wszystko ułożyć razem.

Po drugie, jak zdefiniowałem obszar, w którym można umieścić znacznik, jak mogę wymusić, że znacznik powinien pozostać tylko w tym obszarze? Na przykład, jeśli gracz kliknie i przeciągnie znacznik, może on swobodnie poruszać się w obszarze roboczym, ale nie może opuszczać granic obszaru. Na przykład, jeśli gracz zacznie przeciągać znacznik w górę, przesunie się w górę, aż uderzy w koniec obszaru roboczego (pierwszy schemat poniżej), ale jeśli następnie gracz zacznie przeciągać w bok, znacznik musi podążać za przeciągnięciem w obrębie obszaru (drugi schemat poniżej).

Pierwszy schemat: Poruszanie się w górę Drugi schemat: Po przeciągnięciu

Mam nadzieję, że nie było to zbyt mylące. Dzięki chłopaki.

Edycja: W przypadku, gdy robi to różnicę, używam C ++ z Marmalade SDK.


Myślę, że szukany termin to „waypoint” i czy możesz matematycznie zdefiniować szary obszar? Rozwiązanie twojego problemu będzie prawdopodobnie o wiele łatwiejsze.
John McDonald,

Arent waypoints związane z wyszukiwaniem ścieżek i takie? Również matematyczne zdefiniowanie szarego obszaru jest jednym z moich problemów: PI sądzę, że mógłbym wymyślić coś w rodzaju prostokąta lub nawet koła, ale taki kształt, z dwoma łukami dla boków i dwoma innymi bokami pod kątem ... trochę ponad moją głową.
Vexille,

Musisz także określić, jakiego języka i / lub zestawu narzędzi używasz, ponieważ rozwiązania zależą przede wszystkim od platformy.
Raceimaztion

Naprawdę? Uznałem, że pomocne może być rozwiązanie algorytmiczne lub nawet pseudokod. Zresztą i tak edytuję pytanie, na wszelki wypadek.
Vexille,

Zdefiniuj kształt we współrzędnych biegunowych (maksymalny kąt od kąta znaków i min / maks odległość od znaku). Następnie zaktualizuj punkt orientacyjny tylko w miejscu, w którym znajduje się mysz, jeśli mysz znajduje się w tych granicach. Jeśli przekroczy którykolwiek z tych ekstremów, przyciągnij go do najwyższej możliwej wartości. Rozpocznij aktualizację po kliknięciu w obszarze i zatrzymaj po zwolnieniu myszy.
ClassicThunder

Odpowiedzi:


8

Możesz zdefiniować działający obszar, taki jak ten w pytaniu, za pomocą trzech wartości:

float innerRadius;
float outerRadius;
float maxAngle;

Wartości te będą oparte na punkcie środkowym, który może, ale nie musi, być pozycją gracza. Kształt działającego obszaru zależy od tego, gdzie umieścisz ten punkt.

wprowadź opis zdjęcia tutaj

W powyższym przykładzie pozycji środkowej leży w pewnej odległości (powiedzmy 50 jednostek) z tyłu odtwarzacza. Można to łatwo obliczyć jako:

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

Aby ograniczyć pozycję znacznika do tego możliwego do użycia obszaru, najpierw przesuń znacznik w normalny sposób. Następnie sprawdź odległość między punktem środkowym a znacznikiem:

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

Na koniec sprawdź poprawność kąta znacznika do określonego zakresu. Użyję pseudokodu dla tego:

- 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

Rozejrzyj się, jak obrócić punkt wokół drugiego. Można to zrobić za pomocą trygonometrii lub macierzy transformacji.

Możesz również wziąć pod uwagę rozmiar znacznika i zmniejszyć promień i kąt, aby to zrekompensować.

Edycja: Z drugiej strony może wyglądać bardziej naturalnie, jeśli najpierw zweryfikujesz kąt, a następnie odległość, więc wypróbuj obie alternatywy!


Świetne rozwiązanie! Natknąłem się na coś, co obejmowało dwa koła i trójkąt, ale twoje rozwiązanie elegancko to upraszcza. Jeśli chodzi o sprawdzanie poprawności kąta, pomyślałem o czymś w rodzaju posiadania znormalizowanego wektora, który stał w maxAngle (i innym w -maxAngle) od playerForward, który mógłby zostać pomnożony przez długość C-> M, gdyby był on ograniczony , pod kątem. Zakładam, że twoje rozwiązanie obracania M wokół C byłoby mniej kosztowne, prawda?
Vexille,

@Vexille Dobrze, obracanie wymaga cosi do sinpracy, więc nie jestem pewien. Ale aby obliczyć te dwa wektory, musisz je również obrócić, chociaż musisz to zrobić tylko wtedy, gdy zmienia się wektor do przodu. Zresztą nie powinno to mieć większego znaczenia, wybierz ten, który wolisz wdrożyć.
David Gouveia

10

Zastanawiałem się, jak rozwiązać ten problem, gdyby kształt był nieregularny i nie da się go zdefiniować matematycznie. Ostrzeżenie: to brudne rozwiązanie, nie dla osób o słabym sercu.

1. Weź swój obszar:

wprowadź opis zdjęcia tutaj

2. I przekonwertuj go na monochromatyczną bitmapę:

wprowadź opis zdjęcia tutaj i nazwij go scale_0

3. Sklonuj mapę bitową i przeskaluj ją do 50%:

wprowadź opis zdjęcia tutaj i nazwij go scale_1

4. I tak dalej, aż pojawi się mapa bitowa o szerokości / wysokości mniejszej niż 4 piksele:

wprowadź opis zdjęcia tutaj wprowadź opis zdjęcia tutaj wprowadź opis zdjęcia tutaj wprowadź opis zdjęcia tutaj wprowadź opis zdjęcia tutaj skala: 2, 3, 4, 5, 6

5. Teraz mamy nasz obszar jako monochromatyczne bitmapy o różnych rozdzielczościach: wprowadź opis zdjęcia tutaj

6. Zrób ostatnie zdjęcie (tutaj „scale_6”) i powtórz wszystkie piksele.

  • przetłumacz współrzędne każdego piksela na współrzędne ekranu: x = Math.pow ( 2, scale_level );gdzie skala_poziom jest liczbą dodaną po „skala_”. Możemy to również nazwać poziomem drzewa quad, chociaż tak naprawdę nie pracujemy z drzewem quad. Zrób to samo z y.
  • sprawdź, czy piksel w przetłumaczonym x i y jest czarny. Jeśli nie, to nie jest to część kształtu i powinieneś continueprzejść do następnego kroku pętli
  • sprawdź, czy piksel jest bliżej kursora myszy niż poprzednio sprawdzony piksel - jeśli tak, zapisz współrzędne piksela - użyj współrzędnych przed tłumaczeniem, czyli współrzędnych wewnątrz mapy bitowej.
  • na końcu pętli pomnóż te współrzędne przez 2: x *= 2; y*=2;aby przełożyć je na współrzędne na następnym obrazie (poprzednia skala)

7. Zrób poprzednie zdjęcie (tutaj „scale_5”), ale nie przechodź przez wszystkie piksele; zaczynają się od x = zapisano_x i kończą się x = zapisano_x + 2, tak samo jak y. To znaczy, ponieważ teraz będziesz przechodzić przez 4 piksele na każdym poziomie! Reszta jest jak w p. 6.

8. Zrób pierwszy obraz (największy = ten o największej rozdzielczości), ponownie wykonaj pętlę przez 4 piksele, a na końcu dostaniesz piksel najbliższy kursorowi myszy:

wprowadź opis zdjęcia tutaj

wprowadź opis zdjęcia tutaj

wprowadź opis zdjęcia tutaj

9. Jednak traktuję tutaj „M” jako punkt. Jeśli chcesz, aby było to koło całkowicie pasujące, musisz najpierw skurczyć (zmniejszyć) kształt o circle.radiuspiksele.

Pomyślałem, że dodam, że ten algorytm będzie działał tylko wtedy, gdy użyjesz obrazów nie monochromatycznych, ale w skali szarości i potraktujesz piksel jako „pełny”, jeśli nie jest biały, i jako „pusty”, jeśli jest dokładnie biały ... LUB jeśli zmienisz rozmiar algorytm zmienia każdą grupę 4 pikseli na 1 czarny piksel za każdym razem, gdy co najmniej jeden z tych 4 pikseli nie był biały.


2
+1 za odpowiedź na kształty, które są trudne (jeśli nie niemożliwe) do wyrażenia matematycznego.
Cypher,

Wow, bardzo interesujące. +1 też: D
Vexille,

Wdrożyłem to w prawdziwym projekcie i muszę powiedzieć, że pojawiły się pewne problemy. Zasadniczo musisz utworzyć listę komórek siatki, w której bierzesz najbliższą komórkę o nazwie closest, i sprawdzić odległość do najdalszego punktu w closest- nazwijmy odległość furthest_dist. Teraz musisz usunąć z listy wszystkie komórki, które mają najbliższy punkt dalej niż furthest_disti idź poziom wyżej . Więc zamiast czegoś takiego: i.imgur.com/4UuFo.png To coś takiego: i.imgur.com/dyTT3.png
Markus von Broady,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.