2011-03-07 14 views
19

He estado ocupado durante unos días tratando de entender cómo manejar el tacto en mi proyecto Cocos2d. La situación es un poco diferente, como es normal. Tengo un par de capas de juego diferentes que tienen elementos en él que tengo que controlar con un toque:Cocos2d manejo táctil con varias capas

  • ControlLayer: Mantiene el juego controla (movimiento, botón de acción). Esta capa está en la parte superior.
  • GameplayLayer: Sostiene los objetos del juego (CCSprites). Esta capa está directamente debajo del ControlLayer.

Ahora mis toques funcionan bien en el ControlLayer, puedo mover mi personaje jugable y hacer que salte y haga otras tonterías. Sin embargo, no puedo entender cómo implementar los toques en algunos de mis CCSprites.

La información que he reunido hasta ahora me hace pensar que necesito obtener toda mi entrada táctil desde la capa de control. Luego, de alguna manera, necesito 'poner en cascada' la información táctil en GameplayLayer para poder manejar la entrada allí. Otra opción sería que obtuviera la información de CGRect de mis sprites de alguna manera creando una matriz con punteros a los objetos que deberían ser tocados. Debería poder usar esa información en el ControlLayer para verificar cada ítem en esa lista si se tocó el ítem.

¿Cuál es la mejor opción para hacer esto y cómo lo implemento? Soy un poco nuevo en la programación con Cocoa y Objective C, así que no estoy seguro de cuál es la mejor opción para este idioma y cómo acceder a la información de sprites CGRect ([mySpriteName boundingBox]) en otra clase y luego a la capa que está prestados en.

Por el momento, la única manera en que estoy seguro de hacerlo funcionar es crear CGRects duplicados para cada posición de CCSprite y poder consultarlos, pero sé que esta no es la manera correcta de hacerlo.

Lo que tengo hasta el momento (a prueba) es la siguiente: ControlLayer.m

- (void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { 
UITouch *touch = [touches anyObject]; 
CGPoint location = [touch locationInView: [touch view]]; 

CGRect rect = CGRectMake(0.0f, 0.0f, 100.0f, 100.0f); 

//Tried some stuff here to get see if I could get a sprite by tagname so I could use it's bounding box but that didn't work 

// Check for touch with specific location 
if (CGRectContainsPoint([tree boundingBox], location)) { 
    CCLOG(@"CGRect contains the location, touched!"); 
} 

CCLOG(@"Layer touched at %@", NSStringFromCGPoint(location)); 

}

Gracias de antemano por ayudarme!

Respuesta

27

La manera más fácil y sencilla de resolver su problema, OMI, es mediante el uso ccTouchBegan/Moved/Ended en lugar de ccTouchesBegan/Moved/Ended. Es decir, está manipulando un solo toque en un momento determinado para evitar confundirse en varios toques, además la característica más importante de ccTouchBegan es que un CCLayer puede 'consumir' el toque y evitar que se propague a las siguientes capas. Más explicación después de ejemplos de código a continuación.

Aquí hay pasos para hacerlo. Poner en práctica estos conjuntos de métodos en todas las subclases CCLayer que deben controlar los eventos táctiles:

En primer lugar, se registra en el CCTouchDispatcher:

- (void)registerWithTouchDispatcher { 
    [[CCTouchDispatcher sharedDispatcher] addTargetedDelegate:self priority:0 swallowsTouches:YES]; 
} 

A continuación, poner en práctica ccTouchBegan, ejemplo siguiente es de un juego que he creado (alguna parte omitido por supuesto):

- (BOOL)ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event { 
    if (scene.state != lvlPlaying) { 
     // don't accept touch if not playing 
     return NO; 
    } 
    CGPoint location = [self convertTouchToNodeSpace:touch]; 
    if (scene.mode == modePlaying && !firstTouch) { 
     if (CGRectContainsPoint(snb_putt.sprite.boundingBox, location)) { 
      touchOnPutt = touch.timestamp; 

      // do stuff 

      // return YES to consume the touch 
      return YES; 
     } 
    } 
    // default to not consume touch 
    return NO; 
} 

y, por último aplicar ccTouchMoved y ccTouchEnded como los ccTouches * homólogos, excepto que manejan solo toque en lugar de toques.El toque que se transfiere a estos métodos se restringe al que se consume en ccTouchBegan, por lo que no es necesario realizar la validación en estos dos métodos.

Básicamente así es como funciona. CCScene pasa un evento táctil a cada uno de sus CCLayers uno por uno en función del orden z (es decir, comienza desde la capa superior hasta la capa inferior), hasta que cualquiera de las capas consuma el toque. Por lo tanto, si una capa en la parte superior (por ejemplo, la capa de control) consume el toque, el toque no se propagará a la siguiente capa (por ejemplo, la capa de objeto). De esta forma, cada capa solo tiene que preocuparse por sí misma para decidir si consumir el toque o no. Si decide que no se puede usar el toque, simplemente no debe consumir el toque (devolver NO desde ccTouchBegan) y el toque se propagará automáticamente por las capas.

Espero que esto ayude.

+0

Muchas gracias, me ayudaron a descubrir lo que hice mal y ahora estoy positivamente obteniendo respuesta táctil en mis objetos. –

+0

Gracias por esta excelente explicación. Me ayudo mucho. La mejor respuesta a este tema que he encontrado hasta ahora. –

+4

'[CCTouchDispatcher sharedDispatcher]' está en desuso. Puede usar '[[CCDirector sharedDirector] touchDispatcher]' en su lugar. – Hlung