2010-05-24 6 views
11

Hey alle. Ich habe gerade angefangen, in die cocos2d-Bibliothek zu schauen. Ich habe gehört, dass es eine einfache Bibliothek ist, in die man sich einarbeiten kann, wenn man es gewohnt ist, mit ActionScript zu programmieren, und ich habe festgestellt, dass viele Konzepte tatsächlich ähnlich sind.Best Practices für die Behandlung von Berührungen zu einem CCSprite mit cocos2d

Ich fing an, durch Beispielprojekte zu schauen (die Beispielspiele verbunden here waren besonders hilfreich) und ich sah, dass die Behandlung von Berührungen normalerweise nicht in einem CCSprite getan wird. Der CCLayer, der CCSprites instanziiert, reagiert vielmehr auf ein Berührungsereignis und iteriert durch die erstellten Sprites, um festzustellen, welcher CCSprite berührt wurde (falls vorhanden).

Ich möchte CCSprites behandeln, ob sie selbst berührt wurden, und rufen Sie bis, um zu benachrichtigen, dass es berührt wurde (falls erforderlich). Die Klasse Paddle, die unter/tests/TouchesTest gefunden wird, macht genau das - sie behandelt selbst Berührungen.

Also, die Frage, die ich habe, ist: Was gilt als beste Praxis dafür? Ist es besser, Berührungen an einem zentralen Ort zu behandeln und durch Kinder zu gehen, um zu sehen, was berührt wurde? Oder sollte jedes Kind seine eigenen Berührungsereignisse behandeln? Oder spielt es keine Rolle?

Ich würde es vorziehen, dass jedes Kind seine eigenen Touch-Ereignisse behandelt, aber ich würde gerne die Best Practices zu diesem Thema (falls vorhanden) befolgen. Vielen Dank!

+0

Ich denke, ich sollte über Best Practices im Allgemeinen hinzufügen, wenn es zu so etwas kommt (d. H., Sollten wir im Elternteil 'schedule' aufrufen oder jedes Kind selbst behandeln). – donkim

Antwort

17

Ich denke, es ist eine Frage der Vorliebe, aber ich mag es, das Sprite erkennen, wenn es von Unterklassen CCSprite berührt wurde. Ich mache eine Getter-Methode in meiner CCSprite-Unterklasse, die die Statusvariable aus der Unterklasse abruft und dann kann das Hauptprogramm entsprechend handeln.

Hier ist ein Beispiel Header-Datei für meine CCSprite Unterklasse "spuButton":

#import "cocos2d.h" 

    typedef enum tagButtonState { 
     kButtonStatePressed, 
     kButtonStateNotPressed 
    } ButtonState; 

    typedef enum tagButtonStatus { 
     kButtonStatusEnabled, 
     kButtonStatusDisabled 
    } ButtonStatus; 

    @interface spuButton : CCSprite <CCTargetedTouchDelegate> { 
    @private 
     ButtonState state; 
     CCTexture2D *buttonNormal; 
     CCTexture2D *buttonLit; 
     ButtonStatus buttonStatus; 

    } 

    @property(nonatomic, readonly) CGRect rect; 

    + (id)spuButtonWithTexture:(CCTexture2D *)normalTexture; 

    - (void)setNormalTexture:(CCTexture2D *)normalTexture; 
    - (void)setLitTexture:(CCTexture2D *)litTexture; 
    - (BOOL)isPressed; 
    - (BOOL)isNotPressed; 

    @end 

und hier ist ein Beispiel für die .m-Datei:

#import "spuButton.h" 
    #import "cocos2d.h" 

    @implementation spuButton 

    - (CGRect)rect 
    { 
     CGSize s = [self.texture contentSize]; 
     return CGRectMake(-s.width/2, -s.height/2, s.width, s.height); 
    } 

    + (id)spuButtonWithTexture:(CCTexture2D *)normalTexture 
    { 
     return [[[self alloc] initWithTexture:normalTexture] autorelease]; 
    } 

    - (void)setNormalTexture:(CCTexture2D *)normalTexture { 
     buttonNormal = normalTexture; 
    } 
    - (void)setLitTexture:(CCTexture2D *)litTexture { 
     buttonLit = litTexture; 
    } 

    - (BOOL)isPressed { 
     if (state == kButtonStateNotPressed) return NO; 
     if (state == kButtonStatePressed) return YES; 
     return NO; 
    } 

    - (BOOL)isNotPressed { 
     if (state == kButtonStateNotPressed) return YES; 
     if (state == kButtonStatePressed) return NO; 
     return YES; 
    } 

    - (id)initWithTexture:(CCTexture2D *)aTexture 
    { 
     if ((self = [super initWithTexture:aTexture])) { 

      state = kButtonStateNotPressed; 
     } 

     return self; 
    } 

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

    - (void)onExit 
    { 
     [[CCTouchDispatcher sharedDispatcher] removeDelegate:self]; 
     [super onExit]; 
    } 

    - (BOOL)containsTouchLocation:(UITouch *)touch 
    { 
     return CGRectContainsPoint(self.rect, [self convertTouchToNodeSpaceAR:touch]); 
    } 

    - (BOOL)ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event 
    { 
     if (state == kButtonStatePressed) return NO; 
     if (![self containsTouchLocation:touch]) return NO; 
     if (buttonStatus == kButtonStatusDisabled) return NO; 

     state = kButtonStatePressed; 
     [self setTexture:buttonLit]; 

     return YES; 
    } 

    - (void)ccTouchMoved:(UITouch *)touch withEvent:(UIEvent *)event 
    { 
     // If it weren't for the TouchDispatcher, you would need to keep a reference 
     // to the touch from touchBegan and check that the current touch is the same 
     // as that one. 
     // Actually, it would be even more complicated since in the Cocos dispatcher 
     // you get NSSets instead of 1 UITouch, so you'd need to loop through the set 
     // in each touchXXX method. 

     if ([self containsTouchLocation:touch]) return; 
     //if (buttonStatus == kButtonStatusDisabled) return NO; 

     state = kButtonStateNotPressed; 
     [self setTexture:buttonNormal]; 

    } 

    - (void)ccTouchEnded:(UITouch *)touch withEvent:(UIEvent *)event 
    { 

     state = kButtonStateNotPressed; 
     [self setTexture:buttonNormal]; 


    } 

@end 

Hope this Codierung und glücklich hilft!

ADDITION der tick-Methode und Erklärung (für Stephan Frage unten):

Um den Status der Tasten zu überprüfen Ich habe einen Tick: Methode, die im Grunde jeden Frame feuert und überprüft den Status aller meiner Tasten.

-(void)tick:(ccTime)dt { 

do my button checks here.... 

} 

ich den Status meiner Tasten durch eine IsPressed oder isNotPressed Funktion aufrufen, die ein Teil meiner spuButton Klasse.

for (spuButton *aButton in _fourButtonsArray) { 
    if ([aButton isNotPressed]) continue; //this button is not pressed 
    .....otherwise record that it is pressed..... 
} 

Dann mache ich die gleiche Art von Überprüfung, um zu sehen, ob es freigegeben wurde und entsprechend reagieren. Ich mache es auf diese Weise, weil ich auf mehrere Tastenkombinationen reagieren kann, und ich möchte etwas tun, wenn es gedrückt wird, und dann etwas anderes, wenn es freigegeben wird. Ich verwende ccTouchBegan und ccTouchEnded, um die Texturen (das Sprite-Bild) zu ändern und die Statusvariable entsprechend zu ändern.

+0

Super, das sieht gut aus! Danke für das Code-Snippet, da gibt es einige gute Übungen/Muster, von denen ich lernen kann. – donkim

+0

Kein Problem - Sie sind willkommen. Danke, wie ich es gerne auslege - jeder hat seinen eigenen Stil. 8) Hier ein paar Links zu guten Quellen: http://stackoverflow.com/questions/2293457/cocos2d-resources/4061868#4061868 http://stackoverflow.com/questions/4104124/need-2d-iphone-graphics- designed/4111974 # 4111974 – Mark7777G

+0

PS: Vergessen Sie nicht, die Antworten (und auch die Kommentare) zu wählen, die nützlich waren, damit das Poster dafür gutgeschrieben wird. Danke, dass Sie dies als gute Antwort gewählt haben. 8) – Mark7777G

0

nur zu diesem Thema hinzufügen.Mark stellen auch ein Beispiel, wie der spuButton instanziiert, die hilfreich ist:

Problem with cocos2d and orientation changes, textures are deformed

Sie können auch dieses Beispiel gehen in modifizieren in normalen und beleuchtete Taste Bildern wie so passieren:

+ (id)spuButtonWithTexture:(CCTexture2D *)normalTexture lit:(CCTexture2D *)litTexture 

und dann das gleiche tun zu:

- (id)initWithTexture:(CCTexture2D *)normalTexture lit:(CCTexture2D *)litTexture 

und innerhalb dieser Methode können Sie beiden Texturen gesetzt:

[self setNormalTexture:normalTexture]; 
[self setLitTexture:litTexture]; 
0

Hier ist meine Lösung, basierend auf CCSprite hoffen, dass es für jemanden

dies Protokoll für gesteuerte Objekt (wie Player oder etwas) nützlich sein:

@class AGSensitiveButton; 

@protocol AGSensitiveButtonControlledObjectProtocol <NSObject> 
@required 
- (void)sensitiveButtonTouchDown:(AGSensitiveButton *)sButton; 
- (void)sensitiveButtonTouchUp:(AGSensitiveButton *)sButton; 
@optional 
- (void)sensitiveTouchButtonKeepPressed:(AGSensitiveButton *)sButton forTime:(ccTime)pressTime; 
@end 

.h-Datei:

#import "CCSprite.h" 
#import "cocos2d.h" 
#import "AGSensitiveButtonControlledObjectProtocol.h" 

typedef enum { 
    AGSensitiveButtonStateNormal = 0, 
    AGSensitiveButtonStateHighlighted, 
    AGSensitiveButtonStateDisabled 
} AGSensitiveButtonState; 

@interface AGSensitiveButton : CCSprite <CCTargetedTouchDelegate> 

@property (nonatomic, assign, getter = isEnabled) BOOL enabled; 
@property (nonatomic, assign) ccTime maximumTouchDuration; 
@property (nonatomic, weak) id <AGSensitiveButtonControlledObjectProtocol> controlledObject; 
@property (nonatomic, copy) void (^touchDownHandler)(); 
@property (nonatomic, copy) void (^touchUpHandler)(); 

+ (id)buttonWithNormalTexture:(CCTexture2D *)normalTexture 
      highlightedTexture:(CCTexture2D *)highTexture; 

+ (id)buttonWithNormalTexture:(CCTexture2D *)normalTexture 
      highlightedTexture:(CCTexture2D *)highTexture 
       disabledtexture:(CCTexture2D *)disabledTexture; 

+ (id)buttonWithNormalTexture:(CCTexture2D *)normalTexture 
      highlightedTexture:(CCTexture2D *)highTexture 
      controllerObject:(id <AGSensitiveButtonControlledObjectProtocol>)controlledObject; 

+ (id)buttonWithNormalTexture:(CCTexture2D *)normalTexture 
      highlightedTexture:(CCTexture2D *)highTexture 
       disabledtexture:(CCTexture2D *)disabledTexture 
      controlledObject:(id <AGSensitiveButtonControlledObjectProtocol>)controlledObject; 

+ (id)buttonWithNormalTexture:(CCTexture2D *)normalTexture 
      highlightedTexture:(CCTexture2D *)highTexture 
       disabledtexture:(CCTexture2D *)disabledTexture 
      controlledObject:(id <AGSensitiveButtonControlledObjectProtocol>)controlledObject 
      touchDownHandler:(void(^)(void))touchDownHandler 
       touchUpHandler:(void(^)(void))touchUpHandler; 

- (void)setTexture:(CCTexture2D *)texture forState:(AGSensitiveButtonState)state; 

- (BOOL)isHighlighted; 

@end 

Implementierung .m-Datei:

#import "AGSensitiveButton.h" 

@interface AGSensitiveButton() 
@property (nonatomic, assign) AGSensitiveButtonState state; 
@property (nonatomic, strong) NSDictionary *stateTextures; 
@property (nonatomic, assign) ccTime currentTouchTime; 
@end 

@implementation AGSensitiveButton 

+ (id)buttonWithNormalTexture:(CCTexture2D *)normalTexture 
      highlightedTexture:(CCTexture2D *)highTexture { 
    return [self buttonWithNormalTexture:normalTexture 
         highlightedTexture:highTexture 
         controllerObject:nil]; 
} 

+ (id)buttonWithNormalTexture:(CCTexture2D *)normalTexture 
      highlightedTexture:(CCTexture2D *)highTexture 
       disabledtexture:(CCTexture2D *)disabledTexture { 
    return [self buttonWithNormalTexture:normalTexture 
         highlightedTexture:highTexture 
         disabledtexture:disabledTexture 
         controlledObject:nil]; 
} 

+ (id)buttonWithNormalTexture:(CCTexture2D *)normalTexture 
      highlightedTexture:(CCTexture2D *)highTexture 
      controllerObject:(id <AGSensitiveButtonControlledObjectProtocol>)controlledObject { 
    return [self buttonWithNormalTexture:normalTexture 
         highlightedTexture:highTexture 
         disabledtexture:nil 
         controlledObject:controlledObject]; 
} 

+ (id)buttonWithNormalTexture:(CCTexture2D *)normalTexture 
      highlightedTexture:(CCTexture2D *)highTexture 
       disabledtexture:(CCTexture2D *)disabledTexture 
      controlledObject:(id <AGSensitiveButtonControlledObjectProtocol>)controlledObject { 
    return [self buttonWithNormalTexture:normalTexture 
         highlightedTexture:highTexture 
         disabledtexture:disabledTexture 
         controlledObject:controlledObject 
         touchDownHandler:NULL 
          touchUpHandler:NULL]; 
} 

+ (id)buttonWithNormalTexture:(CCTexture2D *)normalTexture 
      highlightedTexture:(CCTexture2D *)highTexture 
       disabledtexture:(CCTexture2D *)disabledTexture 
      controlledObject:(id <AGSensitiveButtonControlledObjectProtocol>)controlledObject 
      touchDownHandler:(void(^)(void))touchDownHandler 
       touchUpHandler:(void(^)(void))touchUpHandler { 
    AGSensitiveButton *button = [[self alloc] initWithTexture:normalTexture 
                 rect:CGRectMake(0.0, 0.0, normalTexture.contentSize.width, normalTexture.contentSize.height)]; 
    [button setTexture:normalTexture forState:AGSensitiveButtonStateNormal]; 
    [button setTexture:highTexture forState:AGSensitiveButtonStateHighlighted]; 
    [button setTexture:disabledTexture forState:AGSensitiveButtonStateDisabled]; 
    button.controlledObject = controlledObject; 
    button.touchDownHandler = touchDownHandler; 
    button.touchUpHandler = touchUpHandler; 
    return button; 
} 

- (void)setEnabled:(BOOL)enabled { 
    [self setupNewState:enabled ? AGSensitiveButtonStateNormal : AGSensitiveButtonStateDisabled]; 
} 

- (BOOL)isEnabled { 
    return (self.state != AGSensitiveButtonStateDisabled); 
} 

- (BOOL)isHighlighted { 
    return (self.state == AGSensitiveButtonStateHighlighted); 
} 

- (void)toggleTextureForCurrentState { 
    CCTexture2D *textureToSet = [self.stateTextures objectForKey:[NSNumber numberWithInteger:self.state]]; 
    if (textureToSet) { 
     self.texture = textureToSet; 
     self.textureRect = CGRectMake(0.0, 0.0, textureToSet.contentSize.width, textureToSet.contentSize.height); 
    } 
} 

- (void)setTexture:(CCTexture2D *)texture forState:(AGSensitiveButtonState)state { 
    NSMutableDictionary *newStates = self.stateTextures.mutableCopy; 
    if (texture) { 
     [newStates setObject:texture forKey:[NSNumber numberWithInteger:state]]; 
    } else { 
     [newStates removeObjectForKey:[NSNumber numberWithInteger:state]]; 
    } 
    self.stateTextures = newStates.copy; 
} 

- (NSDictionary *)stateTextures { 
    if (!_stateTextures) { 
     _stateTextures = [[NSDictionary alloc] init]; 
    } 
    return _stateTextures; 
} 

- (void)onEnter { 
    [super onEnter]; 
    [self toggleTextureForCurrentState]; 
    [[[CCDirector sharedDirector] touchDispatcher] addTargetedDelegate:self priority:0 swallowsTouches:YES]; 
    [self scheduleUpdate]; 
} 

- (void)onExit { 
    [super onExit]; 
    [self unscheduleUpdate]; 
    [[[CCDirector sharedDirector] touchDispatcher] removeDelegate:self]; 
} 

- (void)update:(ccTime)dt { 
    if ((self.state == AGSensitiveButtonStateHighlighted) && (self.maximumTouchDuration)) { 
     self.currentTouchTime+=dt; 
     if (self.currentTouchTime >= self.maximumTouchDuration) { 
      [self ccTouchEnded:nil withEvent:nil]; 
    } else { 
     if ([self.controlledObject respondsToSelector:@selector(sensitiveTouchButtonKeepPressed:forTime:)]) { 
      [self.controlledObject sensitiveTouchButtonKeepPressed:self forTime:self.currentTouchTime]; 
     } 
    } 
    } 
} 

- (CGRect)rectForTouches { 
    return CGRectMake(-self.contentSize.width/2, -self.contentSize.height/2, 
         self.contentSize.width, self.contentSize.height); 
} 

- (void)forwardTouchDownEventIntoHandlers { 
    if ([self.controlledObject respondsToSelector:@selector(sensitiveButtonTouchDown:)]) { 
     [self.controlledObject sensitiveButtonTouchDown:self]; 
    } 
    if (self.touchDownHandler) { 
     self.touchDownHandler(); 
    } 
} 

- (void)forwardTouchUpEventIntoHandlers { 
    if ([self.controlledObject respondsToSelector:@selector(sensitiveButtonTouchUp:)]) { 
     [self.controlledObject sensitiveButtonTouchUp:self]; 
    } 
    if (self.touchUpHandler) { 
     self.touchUpHandler(); 
    } 
} 

- (void)setupNewState:(AGSensitiveButtonState)state { 
    if (self.state != state) { 
     switch (state) { 
      case AGSensitiveButtonStateHighlighted: { 
       [self forwardTouchDownEventIntoHandlers]; 
       break; 
      } 
      default: { 
       if (self.state == AGSensitiveButtonStateHighlighted) { 
        [self forwardTouchUpEventIntoHandlers]; 
       } 
       break; 
      } 
     } 
     self.state = state; 
     [self toggleTextureForCurrentState]; 
    } 
} 

#pragma mark - CCTargetedTouchDelegate 

- (BOOL)ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event { 
    if ((self.state != AGSensitiveButtonStateNormal) || (!CGRectContainsPoint([self rectForTouches], [self convertTouchToNodeSpaceAR:touch]))) { 
     return NO; 
    } 
    self.currentTouchTime = 0.0; 
    [self setupNewState:AGSensitiveButtonStateHighlighted]; 
    return YES; 
} 

- (void)ccTouchMoved:(UITouch *)touch withEvent:(UIEvent *)event { 
    if (self.state == AGSensitiveButtonStateHighlighted) { 
     if (!CGRectContainsPoint([self rectForTouches], [self convertTouchToNodeSpaceAR:touch])) { 
      [self ccTouchEnded:touch withEvent:event]; 
     } 
    } 
} 

- (void)ccTouchEnded:(UITouch *)touch withEvent:(UIEvent *)event { 
    if (self.state == AGSensitiveButtonStateHighlighted) { 
     [self setupNewState:AGSensitiveButtonStateNormal]; 
    } 
} 

@end 
Verwandte Themen