2009-05-26 8 views
14

Tengo una pregunta rápida en relación con toques de seguimiento en el iPhone y me parece no ser capaz de llegar a una conclusión sobre este tema, por lo que cualquier sugerencia/ideas son muy apreciados:iPhone: Seguimiento/Identificación de toques individuales

I quiere ser capaz de rastrear e identificar toques en el iphone, es decir. básicamente, cada toque tiene una posición inicial y una posición actual/movida. Los toques se almacenan en un std :: vector y se eliminarán del contenedor cuando terminen. Su posición se actualizará una vez que se muevan, pero todavía quiero hacer un seguimiento de dónde empezaron inicialmente (reconocimiento de gestos).

Estoy obteniendo los toques de [event allTouches], es decir, el NSSet no está clasificado y parece que no puedo identificar los toques que ya están almacenados en el std :: vector y me refiero a los toques en el NSSet (entonces sé cuáles terminaron y se eliminarán, o se han movido, etc.)

Aquí está mi código, que funciona perfectamente con solo un dedo en la pantalla táctil, por supuesto, pero con más de uno , Obtengo resultados impredecibles ...

- (void) touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event 
{ 
    [self handleTouches:[event allTouches]]; 
} 

- (void) touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event 
{ 
    [self handleTouches:[event allTouches]]; 
} 

- (void) touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event 
{ 
    [self handleTouches:[event allTouches]]; 
} 

- (void) touchesCancelled:(NSSet*)touches withEvent:(UIEvent*)event 
{ 
    [self handleTouches:[event allTouches]]; 
} 

- (void) handleTouches:(NSSet*)allTouches 
{ 
    for(int i = 0; i < (int)[allTouches count]; ++i) 
    { 
     UITouch* touch = [[allTouches allObjects] objectAtIndex:i]; 
     NSTimeInterval timestamp = [touch timestamp]; 

     CGPoint currentLocation = [touch locationInView:self]; 
     CGPoint previousLocation = [touch previousLocationInView:self]; 

     if([touch phase] == UITouchPhaseBegan) 
     { 
      Finger finger; 
      finger.start.x = currentLocation.x; 
      finger.start.y = currentLocation.y; 
      finger.end = finger.start; 
      finger.hasMoved = false; 
      finger.hasEnded = false; 

      touchScreen->AddFinger(finger); 
     } 
     else if([touch phase] == UITouchPhaseEnded || [touch phase] == UITouchPhaseCancelled) 
     { 
      Finger& finger = touchScreen->GetFingerHandle(i); 

      finger.hasEnded = true; 
     } 
     else if([touch phase] == UITouchPhaseMoved) 
     { 
      Finger& finger = touchScreen->GetFingerHandle(i); 

      finger.end.x = currentLocation.x; 
      finger.end.y = currentLocation.y; 
      finger.hasMoved = true; 
     } 
    } 

    touchScreen->RemoveEnded(); 
} 

¡Gracias!

Respuesta

7

Para solucionar el problema, elimine el método "handleTouches". Lo primero que debe hacer en su método handleTouches es cambiarlo en la TouchPhase, pero eso ya se le ha asignado. Si recibes el toque en touchesBegan, sabes que el toque está en UITouchPhaseBegan. Al canalizar los toques de los cuatro métodos táctiles en un método, está derrotando el propósito de tener cuatro métodos delegados.

En cada uno de esos métodos, Apple te brinda la oportunidad de manejar una fase diferente del toque actual.

Lo segundo es que no necesita buscar el evento para el toque actual, se le asigna como un parámetro: toca.

Un evento se compone de conjuntos de toques. Por conveniencia, se le dan los toques actuales a pesar de que también se puede encontrar dentro del evento.

Entonces, en touchesBegan, comienzas a rastrear un toque.

- (void) touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event{ 


     NSString *startPoint = NSStringFromCGPoint([[touches anyObject] locationInView:self]); 

     NSDictionary * touchData = [NSDictionary dictionaryWithObjectsandKeys: startPoint, @"location", touches, @"touch"] 

     [startingLocations addObject:touchData]; 

     } 

Estoy usando una variedad de diccionarios para guardar mis datos táctiles.

Trate de separar su código y moverlo al método táctil apropiado. En cuanto a la dirección, Apple tiene un par de proyectos de muestra que se centran en los toques y le muestran cómo configurar esos métodos.

Recuerde, se llamará automáticamente a estos métodos para cada toque durante cada fase, no necesita pasar por el evento para averiguar qué sucedió.

El puntero a cada conjunto de toques permanece constante, solo los datos cambian.

Además, leería la sección de la guía de programación de SO del iPhone sobre el manejo de eventos que profundiza más en lo que dije anteriormente con varios diagramas que explican la relación de los toques con los eventos en el tiempo.

un extracto:

En iPhone OS, un objeto UITouch representa un toque, y un objeto UIEvent representa un evento. Un objeto de evento contiene todos los objetos táctiles para la secuencia multitáctil actual y puede proporcionar objetos táctiles específicos a una vista o ventana (consulte la Figura 3-2). Un objeto táctil es persistente para un dedo dado durante una secuencia, y UIKit lo muta mientras rastrea el dedo a lo largo de él. Los atributos táctiles que cambian son la fase del toque , su ubicación en una vista, su ubicación anterior y su marca de tiempo. El código de gestión de eventos evalúa estos atributos para determinar cómo responder al evento.

+1

Estoy de acuerdo con usted. Divido mi código en los métodos apropiados. Sin embargo, mi problema es que necesito crear un enlace entre Obj-C y C++ y la arquitectura de mi juego requiere que la información sea sondeada en lugar de ser manejada una vez que se desencadenan los eventos. Es por eso que estoy almacenando los toques en un vector STL. De todos modos, su información sobre el objeto UITouch que es persistente en el tiempo ayudó mucho. Ahora, estoy usando la dirección del objeto como clave para identificar de forma única un toque. Funciona de maravilla. Gracias. – FlorianZ

+0

"Si recibes el toque en touchesBegan, sabes que el toque está en UITouchPhaseBegan" - ¿en serio? A mí me suena mal: a partir de los documentos de Apple, parecen decir lo contrario: con MultiTouch, un toque de toques podría ser de cualquier fase. – Adam

+0

@ Adam, es posible que esté malinterpretando. Aunque los toques que están contenidos dentro del evento pueden estar en otra fase. Se garantiza que todos los toques dentro del parámetro "toques" estarán en la fase especificada. De la Guía de manejo de eventos: "Si por alguna razón le interesan los toques en la secuencia multitouch actual que no han cambiado desde la última fase o que están en una fase diferente a los del conjunto pasado, puede solicitarlos del objeto UIEvent pasado ". –

0

Debería poder cotejar apropiadamente sus toques almacenando la ubicación anterior de todos los toques y luego comparando estas ubicaciones previas cuando se detectan nuevos toques.

En el método de -handleTouches, que podría poner algo como esto en su bucle for:

// ..existing code.. 
CGPoint previousLocation = [touch previousLocationInView:self]; 

// Loop through previous touches 
for (int j = 0; j < [previousTouchLocationArray count]; j++) { 
    if (previousLocation == [previousTouchLocationArray objectAtIndex:j]) { 
    // Current touch matches - retrieve from finger handle j and update position 
    } 
} 

// If touch was not found, create a new Finger and associated entry 

Obviamente tendrá que hacer algún trabajo para integrar esto en su código, pero estoy bastante seguro de que puede usar esta idea para identificar correctamente los toques a medida que se mueven por la pantalla. También me acabo de dar cuenta de que CGPoint no encajará bien en un NSArray; deberá envolverlos en objetos NSValue (o utilizar un tipo diferente de matriz).

+0

Buena idea. Por alguna razón, esto no funcionó para mí, sin embargo. Parece que las posiciones a veces están apagadas. Esto puede deberse a un rendimiento reducido, cuando estoy renderizando en el contexto de OpenGL (estoy trabajando en un juego). ¿Quizás los eventos táctiles se descartan y las ubicaciones anteriores ya no corresponden a las ubicaciones almacenadas? ¡Gracias de cualquier forma! – FlorianZ

+2

Esto también me causó un problema. Especialmente cuando mueves muchos dedos en la pantalla. A veces obtienes una ubicación que no coincide con ninguna ubicación anterior. – Nosredna

8

Parece que la forma "correcta" de realizar el seguimiento de toques múltiples es mediante el valor del puntero del evento UITouch.

Puede encontrar más detalles en la sección "La manipulación de una secuencia compleja multi-touch" de este Apple Developer Documentation

+1

Si solo hace un seguimiento de las ubicaciones anteriores y lo utiliza para encontrar toques relacionados, no tendrá éxito. A menudo, touchesEnded pasará en una ubicación que difiere de todos sus valores en caché. Google para "Manejo de una secuencia multitoque compleja" para encontrar los documentos; el enlace se mueve. Erica Sadun escribió sobre esto: http://blogs.oreilly.com/iphone/2008/10/recovering-multiple-touches.html y también proporcionó un código: http://github.com/erica/iphone-3.0 -cookbook-/blob/master/C08-Gestures/14-Resize% 20And% 20Rotate/main.m Supongo que Apple desea que se vuelva a hacer la API táctil para pasar un NSArray en lugar de NSSet. –

Cuestiones relacionadas