2010-05-31 12 views
6

Estoy escribiendo un juego para Mac usando Cocoa. Actualmente estoy implementando pruebas de impacto y he descubierto que CALayer ofrece pruebas de impacto, pero no parece implementar las propiedades alfa. Como a veces tengo muchos CALayers superpuestos, realmente necesito encontrar una forma de determinar en qué quiere hacer clic el usuario.Hit Testing con CALayer usando las propiedades alfa del contenido de CALayer

Estoy pensando que si de alguna manera pudiera obtener una matriz que contiene punteros a todos los CALayers que contienen el punto de clic, podría filtrarlos de alguna forma. Sin embargo, la única manera que tengo hasta ahora para crear la matriz es:

NSMutableArray* anArrayOfLayers = [NSMutableArray array]; 
    for (CALayer* aLayer in mapLayer.sublayers) 
    { 
     if ([aLayer containsPoint:mouseCoord]) 
      [anArrayOfLayers addObject:aLayer]; 
    } 

Luego, ordenar la matriz por valores z de la CALayer luego ir a través de comprobar si el píxel en la ubicación es alfa o no. Sin embargo, entre el género y el control alfa, parece ser un cerdo de rendimiento increíble. (¿Cómo comprobaría incluso el alfa?)

¿Hay alguna forma de hacerlo?

Respuesta

10

Algo que tropezó mientras que rascarse la cabeza sobre un problema similar es que CALayer utiliza containsPoint: cuando lo envía hitTest:

Su comportamiento por defecto es poner a prueba contra los límites, pero podemos anular y conseguir que se compruebe la alfa canal, y sólo tiene que utilizar de CALayer construido en el éxito de pruebas para manejar el resto:

- (BOOL) containsPoint:(CGPoint)p 
{ 
    return CGRectContainsPoint(self.bounds, p) && !ImagePointIsTransparent(self.contents, p)) return YES; 
} 

Hay una discusión de las pruebas para la alfa de un solo píxel en Retrieving a pixel alpha value for a UIImage

T su trabajaron para mis propósitos:

static BOOL ImagePointIsTransparent(CGImageRef image, CGPoint p) 
{ 
    uint8_t alpha; 

    CGContextRef context = CGBitmapContextCreate(&alpha, 1, 1, 8, 1, NULL, kCGImageAlphaOnly); 
    CGContextDrawImage(context, CGRectMake(-p.x, -p.y, CGImageGetWidth(image), CGImageGetHeight(image)), image); 
    CGContextRelease(context); 

    return alpha == 0; 
} 

(Si está utilizando renderInContext: señalar a la CALayer en lugar de establecer su propiedad contenidos, entonces va a ser más complicado. Esto podría ser útil en ese caso: http://www.cimgf.com/2009/02/03/record-your-core-animation-animation/)

+0

Chris, ¡esto es fantástico! Pregunta para usted: Al pasar en el punto, parece requerir que su origen esté en la parte inferior izquierda vs. arriba a la derecha. Sospecho que es algo que debe pasar antes de pasar el punto aquí, ¿no? (Además de usar la altura de la imagen para dar la vuelta). Creo que estoy tratando de determinar dónde está el lugar correcto para poner ese ajuste: en ImagePointIsTransparent, o en el gestor de gestos/toque. –

+0

Da la casualidad, creo que la pregunta a la que me refería era sobre lo que estás preguntando: Core Graphics y UIKit tienen diferentes ejes Y, así que supongo que querrás convertir en la interfaz entre los dos. También hay una discusión sobre el impacto en el rendimiento de las diferentes formas de renderizar la capa (representando todo una vez frente a solo un píxel en repetidas ocasiones), lo que también es posible que desee verificar. –

+0

Chris, me acabo de dar cuenta: estás escribiendo una aplicación para Mac. Estoy escribiendo una aplicación para iOS. Resulta que, al usar una pantalla Retina, esta prueba no funciona (en el iPhone 4 o el Simulador en modo Retina). La Guía de programación 2D de Quartz recomienda que use UIGraphicsBeginImageContextWithOptions en comparación con las funciones de cuarzo de nivel inferior, así que tendré que ver si eso ayuda con la CTM, y así sucesivamente. (Esto también podría explicar por qué la respuesta parece "por todas partes" en Retina). Http://stackoverflow.com/questions/7506248/alpha-detection-in-layer-ok-on-simulator-not-iphone –