Spędziłem niezliczone godziny na czytaniu samouczków i analizowaniu każdego pytania związanego z multiTouch odtąd i Stackoverflow. Ale po prostu nie mogę wymyślić, jak to zrobić poprawnie. Używam pętli, aby uzyskać pointerId
, nie widzę wielu ludzi, którzy to robią, ale jest to jedyny sposób, w jaki udało mi się sprawić, by trochę działała.
Na ekranie mam dwa joysticki, jeden do poruszania się, drugi do kontrolowania rotacji duszków i kąta, który strzela, jak w Monster Shooter. Oba działają dobrze.
Mój problem polega na tym, że kiedy poruszam duszka w tym samym czasie, co strzelanie, mój touchingPoint
ruch jest ustawiony na touchingPoint
mój strzelanie, ponieważ x
i y
jest wyżej po touchingPoint
moim strzelaniu ( moving-stick
po lewej stronie ekranu, shooting-stick
po prawej stronie) , mój duszek przyspiesza, to powoduje niechcianą zmianę prędkości dla mojego duszka.
tak to rozwiązałem z twoją pomocą! dotyczy to każdego, kto może napotkać podobny problem:
public void update(MotionEvent event) {
if (event == null && lastEvent == null) {
return;
} else if (event == null && lastEvent != null) {
event = lastEvent;
} else {
lastEvent = event;
}
int action = event.getAction();
int actionCode = action & MotionEvent.ACTION_MASK;
int pid = action >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
int x = (int) event.getX(pid);
int y = (int) event.getY(pid);
int index = event.getActionIndex();
int id = event.getPointerId(index);
String actionString = null;
switch (actionCode)
{
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_POINTER_DOWN:
actionString = "DOWN";
try{
if(x > 0 && x < steeringxMesh + (joystick.get_joystickBg().getWidth() * 2)
&& y > yMesh - (joystick.get_joystickBg().getHeight()) && y < panel.getHeight()){
movingPoint.x = x;
movingPoint.y = y;
dragging = true;
draggingId = id;
}
else if(x > shootingxMesh - (joystick.get_joystickBg().getWidth()) && x < panel.getWidth()
&& y > yMesh - (joystick.get_joystickBg().getHeight()) && y < panel.getHeight()){
shootingPoint.x = x;
shootingPoint.y = y;
shooting=true;
shootingId=id;
}
}catch(Exception e){
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_OUTSIDE:
if(id == draggingId)
dragging = false;
if(id == shootingId)
shooting = false;
actionString = "UP";
break;
case MotionEvent.ACTION_MOVE:
for(index=0; index<event.getPointerCount(); index++) {
id=event.getPointerId(index);
int xx = (int) event.getX(index); //pro naming of variable
int yy = (int) event.getY(index);
if(dragging && id == draggingId) {
if(xx > 0 && xx < (steeringxMesh + joystick.get_joystickBg().getWidth() * 2)
&& yy > yMesh - (joystick.get_joystickBg().getHeight()) && yy < panel.getHeight()) {
movingPoint.x = xx;
movingPoint.y = yy;
}
else
dragging = false;
}
if(shooting && id == shootingId){
if(xx > shootingxMesh - (joystick.get_joystickBg().getWidth()) && xx < panel.getWidth()
&& yy > yMesh - (joystick.get_joystickBg().getHeight()) && yy < panel.getHeight()) {
shootingPoint.x = xx;
shootingPoint.y = yy;
}
else
shooting = false;
}
}
actionString = "MOVE";
break;
}
Log.d(TAG, "actionsString: " + actionString + ", pid: " + pid + ", x: " + x + ", y: " + y);
Nie opublikowałbym tak dużo kodu, gdybym nie miał absolutnej straty z tego, co robię źle. Po prostu nie mogę dobrze zrozumieć, jak działa funkcja MultiTouching.
zasadniczo movingPoint
zmienia się zarówno dla mojego pierwszego, jak i drugiego palca. Wiążę go do pudełka, ale dopóki trzymam w nim jeden palec, zmienia swoją wartość w zależności od tego, gdzie dotyka mój drugi palec. Porusza się we właściwym kierunku i nic nie daje błędu, problemem jest zmiana prędkości, to prawie tak, jakby sumuje dwa dotykające punkty.
Prawie masz rację, ale powinieneś użyć swojego identyfikatora wskaźnika, aby zażądać X / Y zamiast
i
Z dokumentacji MotionEvent:
event.getX/Y
nie wymagają identyfikatora wskaźnikai
, ponieważ nie ma gwarancji, że będą w tej samej kolejności.Ponadto istnieje inny subtelny, ale ważny problem. Zauważ, że rodzina funkcji getAction () nie przyjmuje parametru. To trochę dziwne, prawda? Uzyskanie X / Y wymaga identyfikatora wskaźnika, ale nie wykonanej akcji? Wskazuje to na kilka ważnych rzeczy:
Oznacza to, że otrzymujesz jedno wywołanie do funkcji obsługi dotykowej na akcję wskaźnika (w dół / ruch / w górę). Więc dwa palce w ruchu = 2 połączenia. Paskudnym efektem ubocznym twojego kodu jest to, że stosuje działanie jednego zdarzenia do wszystkich wskaźników ...
Więc zamiast zapętlać ślady, po prostu uzyskaj akcję pid / x / y / tylko dla bieżącego zdarzenia (w przypadku jednoczesnego ruchu dostaniesz kolejne wywołanie do twojego handlera nieco później, jak powiedziałem)
Oto mój kod do obsługi zdarzeń:
}
Aby wrócić do kodu, możesz go uprościć w następujący sposób. Pętla zniknęła, w przeciwnym razie, jeśli masz inne przeciwwskazania, o których nie wspomniałeś, zawsze możesz ją dodać z powrotem. Działa poprzez śledzenie, który identyfikator wskaźnika jest używany do sterowania (ruch / strzelanie) po uruchomieniu DÓŁ i resetowanie ich w GÓRĘ. Ponieważ nie używasz gestów, możesz ograniczyć przełącznik () do pozycji W DÓŁ, W GÓRĘ, NA PRZESUWANIE i NA ZEWNĄTRZ.
źródło
sendTouchToGameEngine(pid, actionCode, (int)event.getX(pid), (int)event.getY(pid));
robi ta linia i kiedy do niej zadzwonisz?int pid = action >> MotionEvent.ACTION_POINTER_ID_SHIFT;
zaćmienie mówi mi, żebym dodał supress Ostrzeżenie, czy to normalne? Przepraszamy za wszystkie pytania po tak szczegółowej odpowiedzi. MotionEvent jest dla mnie bardzo nowy i z jakiegoś powodu nie mogę zrozumieć logikipid
, a pętla nadal tam jest, nie będzie działać bez niej, ponieważ muszę ją pobraći
.Z tym kodem dzieje się trochę dziwności. Nie używam Androida, więc może myślę, że coś takiego nie jest. Zauważyłem jednak, że otrzymujesz pozycję dwukrotnie, na dwa różne sposoby:
Najpierw dostajesz to w ten sposób na początku swojej
pointerCount
pętli:Następnie wewnątrz instrukcji switch otrzymujesz to w następujący sposób:
Zauważ, że przełączasz się z używania
i
na używanieid
.Zakładam, że to powinna być pierwsza metoda. Zalecam zastąpienie wszystkich instancji
(int) event.getX(id)
i użycie wartościx
ustawionej na początku. Podobnie zamiana(int) event.getY(id)
nay
.Spróbuj zamienić te części:
Następnie w przełączniku użyj tego:
źródło
x
iy
, ale nadal otrzymujesz pozycję doid
później.x=event.getX(i)
), wtedyx
będę musiał przechowywać 2 wartości, ilekroćpointerCount
jest więcej niż 1, prawda? I to nie wydaje się właściwe.event
naprawdę jest lista wydarzeń. Dostęp do różnych wydarzeń można uzyskać, przeglądając listę tak, jak robisz. Aby uzyskać dostęp dox
pozycji drugiego wydarzenia, którego używaszevent.getX(1)
(ponieważ zaczynamy od 0). Istnieje wielex
s, używasz parametru, aby powiedzieć mu, który chcesz. Zapętlasz wszystkie zdarzenia za pomocą swojejfor
pętli, więc użyj tego numeru jako bieżącego wydarzenia, które Cię interesuje. Zobacz moją sugestię zmiany kodu.Miałem podobny problem raz na Huawei U8150. Wielodotykowy dotyk dwóch palców na tym urządzeniu był naprawdę zły, używając aplikacji testowej wielodotykowej (być może był to „Tester telefonu”, ale nie jestem pewien). Widziałem, że dotykanie drugim palcem przesunęło punkt pierwszego dotknięcia wielu pikseli . Jeśli to jest twój problem związany ze sprzętem i nie sądzę, że możesz na to wiele poradzić :(
Przepraszam za mój zły angielski
źródło
Uważam, że twoim problemem jest to, że zakładasz, że między aktualizacjami kolejność ułożenia wskaźników pozostaje taka sama. Najprawdopodobniej tak się nie stanie.
Wyobraź sobie sytuację, w której dotykasz palcem A. Będzie wskaźnik 1 (1), a A będzie jedynym elementem, o który możesz zapytać. Jeśli dodasz drugi palec, wskaźnik pointerCount () będzie wynosił 2, A będzie miał indeks 0, B będzie miał indeks 1. Jeśli podniesiesz palec A, pointerCount () będzie miał ponownie 1, a B będzie miał indeks 0 . Jeśli następnie ponownie dotkniesz palcem A, A będzie miało indeks 1, a B będzie pod indeksem 0 .
Dlatego podano identyfikator wskaźnika, abyś mógł śledzić poszczególne poprawki między aktualizacjami. Jeśli więc pierwsze dotknięcie palca B ma przypisany identyfikator 12, zawsze będzie on miał ten identyfikator, nawet gdy palec A zostanie usunięty i ponownie dodany.
Więc jeśli kod identyfikuje dotyk w pobliżu joysticka strzelającego, musi sprawdzić, czy już trwa dotyk „strzelający”. Jeśli nie, to identyfikator strzelającego dotyku powinien zostać zapamiętany w jakiejś zmiennej składowej, która utrzymuje się do następnej aktualizacji. W kolejnych aktualizacjach, jeśli masz dotyk „strzelania”, iteruj po wskaźnikach i szukaj wskaźnika z odpowiednim identyfikatorem, i jest to wskaźnik, którego musisz użyć do śledzenia aktualizacji, a wszystkie inne można zignorować. To samo dotyczy dotyku ruchu. Po zwolnieniu dotyku usuwasz identyfikator powiązany z tym joystickiem, aby nowy dotyk mógł przejąć nad nim kontrolę.
Nawet jeśli dotyk, który zaczyna się w pobliżu jednego joysticka, znajduje się daleko od pierwotnej pozycji dotyku, po jego identyfikatorze nadal można poprawnie zidentyfikować kontrolowany joystick. I jako przyjemny efekt uboczny, drugi zbłąkany palec w pobliżu konkretnego joysticka nie przyniesie żadnego efektu, ponieważ joystick będzie związany z pierwszym palcem, który go uruchomił, dopóki nie zostanie zwolniony.
źródło