He pasado innumerables horas leyendo tutoriales y examinando todas las preguntas relacionadas con multiTouch desde aquí y Stackoverflow. Pero no puedo entender cómo hacer esto correctamente. Utilizo un bucle para obtener mi pointerId
, no veo mucha gente haciendo esto, pero es la única forma en que he logrado que funcione.
Tengo dos joysticks en mi pantalla, uno para moverme y otro para controlar la rotación de mis sprites y el ángulo en el que dispara, como en Monster Shooter. Ambos funcionan bien.
Mi problema es que cuando muevo mi sprite al mismo tiempo que estoy disparando, mi touchingPoint
movimiento se establece en el touchingPoint
de mi disparo, ya que x
y y
es más alto en touchingPoint
mi disparo ( moving-stick
en el lado izquierdo de la pantalla, shooting-stick
en el lado derecho) , mi sprite se acelera, esto crea un cambio no deseado en la velocidad de mi sprite.
¡Así es como lo resolví con tu ayuda! Esto es para cualquier persona que pueda tener un problema similar:
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);
No publicaría tanto código si no tuviera una pérdida absoluta de lo que estoy haciendo mal. Simplemente no puedo entender bien cómo funciona el MultiTouching.
básicamente movingPoint
cambia para mi primer y segundo dedo. Lo ato a un cuadro, pero mientras sostengo un dedo dentro de este cuadro, cambia su valor en función de donde toca mi segundo dedo. Se mueve en la dirección correcta y nada da un error, el problema es el cambio de velocidad, es casi como si sumara los dos puntos de contacto.
fuente
Casi lo está haciendo bien, pero debe usar su identificación de puntero para solicitar la X / Y en lugar de
i
De la documentación de MotionEvent:
event.getX/Y
requieren una identificación de puntero, noi
, porque no hay garantía de que estén en el mismo orden.Además, hay otro problema sutil pero importante. Observe cómo la familia de funciones getAction () no toma un parámetro. Eso es un poco raro, ¿verdad? Obtener X / Y requiere la identificación del puntero, pero no la acción realizada. Eso insinúa un par de cosas importantes:
Eso significa que recibe una llamada a su controlador táctil por acción de puntero (abajo / mover / arriba). Entonces dos dedos en movimiento = 2 llamadas. Un efecto secundario desagradable de su código es que aplica la acción de un evento a todos los punteros ...
Entonces, en lugar de recorrer las trazas, simplemente obtenga la acción pid / x / y / solo para el evento actual (para el movimiento simultáneo, recibirá otra llamada a su controlador un poco más tarde, como dije)
Aquí está mi código para manejar eventos:
}
Para volver a su código, debería poder simplificarlo de la siguiente manera. El ciclo se ha ido; de lo contrario, si tiene otras restricciones que no mencionó, siempre puede agregarlo nuevamente. Funciona al rastrear qué ID de puntero se utiliza para qué control (mover / disparar) cuando se activa DOWN y restablecerlos en UP. Como no usa gestos, puede restringir su interruptor () a ABAJO, ARRIBA, MOVER y FUERA.
fuente
sendTouchToGameEngine(pid, actionCode, (int)event.getX(pid), (int)event.getY(pid));
y cuándo la llama?int pid = action >> MotionEvent.ACTION_POINTER_ID_SHIFT;
eclipse me dice que agregue un supressWarning, ¿es eso normal? Perdón por todas las preguntas después de una respuesta tan detallada. MotionEvent es muy nuevo para mí, y no puedo entender la lógica por alguna razónpid
, y el bucle sigue ahí, no funcionará sin él, ya que necesito obtenerloi
.Hay un poco de rareza con este código. No uso Android, así que tal vez estoy pensando que esto es algo que no es. Sin embargo, noté que obtienes el puesto dos veces, de dos maneras diferentes:
Primero lo obtienes así al comienzo de tu
pointerCount
ciclo:Luego, dentro de su declaración de cambio, lo obtiene así:
Observe que cambia de usar
i
a usarid
.Supongo que se supone que es el método anterior. Recomiendo reemplazar todas las instancias
(int) event.getX(id)
y usar el valorx
que estableció al principio. Del mismo modo cambiar(int) event.getY(id)
ay
.Intente intercambiar estas partes:
Luego, dentro de su interruptor, use esto:
fuente
x
yy
, pero aún está obteniendo la posiciónid
más tarde.x=event.getX(i)
), entoncesx
tendré que almacenar 2 valores siempre quepointerCount
sea más de 1, ¿correcto? Y ese dosificador se siente bien.event
es realmente una lista de eventos. Accede a los diferentes eventos al revisar la lista como lo estás haciendo. Entonces, para acceder a lax
posición para el segundo evento que usaevent.getX(1)
(ya que comenzamos en 0). Hay varios correosx
electrónicos, está utilizando el parámetro para indicarle cuál desea. Estás recorriendo todos los eventos con tufor
ciclo, así que usa ese número como el evento actual que te interesa. Consulta mi sugerencia de cambio de código.Tuve un problema similar una vez en un Huawei U8150. El multitoque de dos dedos en ese dispositivo era realmente malo, usando una aplicación de prueba multitáctil (tal vez era "Phone Tester" pero no estoy seguro) pude ver que tocar con el segundo dedo movía el primer punto táctil de muchos píxeles . Si ese es su problema, está relacionado con el hardware y no creo que pueda hacer mucho por ello :(
Perdón por mi mal ingles
fuente
Creo que su problema es que está asumiendo que, entre actualizaciones, el orden en que se organizan los punteros se mantiene igual. Es muy probable que ese no sea el caso.
Imagine una situación en la que toca con el dedo A. Habrá un pointerCount () de 1, y A será el único elemento sobre el que puede preguntar. Si agrega un segundo dedo, pointerCount () será 2, A estará en el índice 0, B estará en el índice 1. Si levanta el dedo A, pointerCount () volverá a ser 1 y B estará en el índice 0 . Si vuelve a tocar con el dedo A, A estará en el índice 1 y B estará en el índice 0 .
Esta es la razón por la cual se proporciona la ID del puntero, para que pueda rastrear toques individuales entre actualizaciones. Entonces, si al primer toque del dedo B se le asigna la ID 12, siempre tendrá esa ID, incluso cuando el dedo A se quite y se vuelva a agregar.
Entonces, si su código identifica un toque cerca de su joystick de disparo, debe verificar si ya hay un toque de 'disparo' en progreso. De lo contrario, la identificación del toque de disparo debe recordarse en alguna variable miembro que persista hasta la próxima actualización. En las actualizaciones posteriores, si tiene un toque de 'disparo' en progreso, repita los punteros y busque el puntero con la ID correcta, y es ese puntero el que necesita usar para rastrear actualizaciones, y todos los demás pueden ignorarse. Lo mismo para el movimiento táctil. Cuando se suelta el toque, borra la ID asociada con ese joystick para que un nuevo toque pueda tomar el control.
Incluso si un toque que comienza cerca de un joystick se aleja mucho de la posición táctil original, por su ID aún puede identificar correctamente qué joystick está controlando. Y como un buen efecto secundario, un segundo dedo perdido cerca de un joystick en particular no tendrá ningún efecto, ya que el joystick se unirá al primer dedo que lo activó hasta que se suelte.
fuente