Ich habe unzählige Stunden damit verbracht, Tutorials zu lesen und mir alle Fragen zu multiTouch von hier und Stackoverflow anzuschauen. Aber ich kann einfach nicht herausfinden, wie ich das richtig machen soll. Ich benutze eine Schleife, um meine zu bekommen pointerId
, ich sehe nicht viele Leute, die dies tun, aber es ist die einzige Möglichkeit, es irgendwie zum Laufen zu bringen.
Ich habe zwei Joysticks auf meinem Bildschirm, einen zum Bewegen und einen zum Steuern der Sprites-Rotation und des Winkels, den er schießt, wie in Monster Shooter. Beide funktionieren gut.
Mein Problem ist, dass, wenn ich mein Sprite gleichzeitig mit dem Schießen bewege, touchingPoint
meine Bewegung auf das touchingPoint
Schießen eingestellt ist, da das x
und y
höher auf dem touchingPoint
Schießen liegt ( moving-stick
auf der linken Seite des Bildschirms, shooting-stick
auf der rechten Seite). Wenn mein Sprite schneller wird, führt dies zu einer unerwünschten Geschwindigkeitsänderung für mein Sprite.
So habe ich es mit Ihrer Hilfe gelöst! Dies ist für alle, die auf ein ähnliches Problem stoßen könnten:
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);
Ich würde nicht so viel Code posten, wenn ich nicht den absoluten Verlust dessen hätte, was ich falsch mache. Ich kann einfach nicht gut verstehen, wie MultiTouching funktioniert.
Grundlegende movingPoint
Änderungen für meinen ersten und zweiten Finger. Ich binde es an eine Box, aber solange ich einen Finger in dieser Box halte, ändert sich sein Wert je nachdem, wo mein zweiter Finger berührt. Es bewegt sich in die richtige Richtung und nichts gibt einen Fehler aus. Das Problem ist die Geschwindigkeitsänderung. Es ist fast so, als würde es die beiden Berührungspunkte addieren.
Sie haben es fast richtig gemacht, aber Sie sollten Ihre Zeiger-ID verwenden, um das X / Y anstelle von anzufordern
i
Aus der MotionEvent-Dokumentation:
event.getX/Y
benötigen eine Zeiger-ID, nichti
, da es keine Garantie gibt, dass sie in derselben Reihenfolge sind.Darüber hinaus gibt es ein weiteres subtiles, aber wichtiges Problem. Beachten Sie, dass die Funktionsfamilie getAction () keinen Parameter akzeptiert. Das ist irgendwie komisch, oder? Um X / Y zu erhalten, ist die Zeiger-ID erforderlich, nicht jedoch die ausgeführte Aktion. Das deutet auf ein paar wichtige Dinge hin:
Das bedeutet, dass Sie pro Zeigeraktion (nach unten / nach oben / nach oben) einen Anruf an Ihren Touch-Handler erhalten . Also zwei Finger bewegen sich = 2 Anrufe. Ein böser Nebeneffekt Ihres Codes ist, dass er die Aktion eines Ereignisses auf alle Zeiger anwendet ...
Anstatt die Spuren zu durchlaufen, rufen Sie einfach die Aktion pid / x / y / nur für das aktuelle Ereignis ab (bei gleichzeitiger Bewegung erhalten Sie, wie gesagt, ein kleines bisschen später einen weiteren Anruf bei Ihrem Handler).
Hier ist mein Code zur Behandlung von Ereignissen:
}}
Um zu Ihrem Code zurückzukehren, sollten Sie ihn auf folgende Weise vereinfachen können. Die Schleife ist weg, andernfalls können Sie sie jederzeit wieder hinzufügen, wenn Sie andere Einschränkungen haben, die Sie nicht erwähnt haben. Es funktioniert, indem verfolgt wird, welche Zeiger-ID für welches Steuerelement (Bewegen / Schießen) verwendet wird, wenn DOWN ausgelöst wird, und diese auf UP zurückgesetzt werden. Da Sie keine Gesten verwenden, können Sie Ihren Schalter () auf DOWN, UP, MOVE und OUTSIDE beschränken.
quelle
sendTouchToGameEngine(pid, actionCode, (int)event.getX(pid), (int)event.getY(pid));
tut und wann Sie sie nennen?int pid = action >> MotionEvent.ACTION_POINTER_ID_SHIFT;
Eclipse fordert mich auf, eine SupressWarning hinzuzufügen. Ist das normal? Entschuldigen Sie alle Fragen nach einer so detaillierten Antwort. MotionEvent ist sehr neu für mich und kann die Logik aus irgendeinem Grund nicht verstehenpid
, und die Schleife ist immer noch da, wird ohne sie nicht funktionieren, da ich bekommen mussi
.Mit diesem Code ist ein bisschen komisch. Ich benutze kein Android, also denke ich vielleicht, dass dies etwas ist, was es nicht ist. Ich habe jedoch bemerkt, dass Sie die Position zweimal bekommen, auf zwei verschiedene Arten:
Zuerst erhalten Sie es so am Anfang Ihrer
pointerCount
Schleife:Dann erhalten Sie es in Ihrer switch-Anweisung folgendermaßen:
Beachten Sie, dass Sie von using
i
zu using wechselnid
.Ich gehe davon aus, dass es die erstere Methode sein soll. Ich empfehle, alle Instanzen von zu ersetzen
(int) event.getX(id)
undx
den zu Beginn festgelegten Wert zu verwenden. Ebenso wechseln(int) event.getY(id)
zuy
.Versuchen Sie, diese Teile auszutauschen:
Verwenden Sie dann in Ihrem Switch Folgendes:
quelle
x
und entfernt habeny
, aber Sie erhalten die Positionid
später noch.x=event.getX(i)
) verwende, müssen dannx
2 Werte gespeichert werden, wennpointerCount
mehr als 1 ist. Richtig? Und das fühlt sich nicht richtig an.event
handelt es sich wirklich um eine Liste von Ereignissen. Sie greifen auf die verschiedenen Ereignisse zu, indem Sie die Liste wie gewohnt durchgehen. Um auf diex
Position für das zweite Ereignis zuzugreifen, das Sie verwendenevent.getX(1)
(da wir bei 0 beginnen). Es gibt mehrerex
s, Sie verwenden den Parameter, um anzugeben, welche auf Sie möchten. Sie durchlaufen alle Ereignisse mit Ihrerfor
Schleife. Verwenden Sie diese Nummer also als aktuelles Ereignis, an dem Sie interessiert sind. Siehe meinen Vorschlag zur Codeänderung.Ich hatte einmal ein ähnliches Problem auf einem Huawei U8150. Das Zwei-Finger-Multitouch auf diesem Gerät war wirklich schlecht. Mit einer Multitouch-Test-App (vielleicht war es "Phone Tester", aber ich bin mir nicht sicher) konnte ich sehen, dass das Berühren mit dem zweiten Finger den ersten Berührungspunkt vieler Pixel bewegte . Wenn das Ihr Problem ist, dann hängt es mit der Hardware zusammen und ich glaube nicht, dass Sie viel dafür tun können :(
Entschuldigung für mein schlechtes Englisch
quelle
Ich glaube, Ihr Problem ist, dass Sie davon ausgehen, dass zwischen den Aktualisierungen die Reihenfolge, in der die Zeiger angeordnet sind, gleich bleibt. Das wird höchstwahrscheinlich nicht der Fall sein.
Stellen Sie sich eine Situation vor, in der Sie mit Finger A berühren. Es gibt einen pointerCount () von 1, und A ist das einzige Element, nach dem Sie fragen können. Wenn Sie einen zweiten Finger hinzufügen, ist pointerCount () 2, A ist auf Index 0, B ist auf Index 1. Wenn Sie Finger A heben, ist pointerCount () wieder 1 und B ist auf Index 0 . Wenn Sie dann erneut mit Finger A berühren, befindet sich A auf Index 1 und B auf Index 0 .
Aus diesem Grund wird die Zeiger-ID bereitgestellt, damit Sie einzelne Berührungen zwischen Aktualisierungen verfolgen können. Wenn also der ersten Berührung von Finger B die ID 12 zugewiesen wird, hat sie immer diese ID, selbst wenn Finger A entfernt und erneut hinzugefügt wird.
Wenn Ihr Code also eine Berührung in der Nähe Ihres Schieß-Joysticks erkennt, muss überprüft werden, ob bereits eine Berührung mit dem Schießen ausgeführt wird. Wenn nicht, sollte die ID der Schießberührung in einer Mitgliedsvariablen gespeichert werden, die bis zum nächsten Update bestehen bleibt. Wenn Sie in nachfolgenden Aktualisierungen eine "Schießerei" ausführen, durchlaufen Sie die Zeiger und suchen Sie nach dem Zeiger mit der richtigen ID. Dieser Zeiger muss zum Verfolgen von Aktualisierungen verwendet werden. Alle anderen können ignoriert werden. Gleiches gilt für die Bewegungsberührung. Wenn die Berührung losgelassen wird, löschen Sie die ID, die diesem Joystick zugeordnet ist, damit eine neue Berührung die Kontrolle darüber übernehmen kann.
Selbst wenn eine Berührung, die in der Nähe eines Joysticks beginnt, weit von der ursprünglichen Berührungsposition entfernt ist, können Sie anhand ihrer ID immer noch korrekt identifizieren, welchen Joystick sie steuert. Und als netter Nebeneffekt hat ein zweiter streunender Finger in der Nähe eines bestimmten Joysticks keine Wirkung, da der Joystick an den ersten Finger gebunden ist, der ihn ausgelöst hat, bis er losgelassen wird.
quelle