2010-05-24 56 views
11

嘿,所有。我剛開始研究cocos2d庫。我聽說如果您習慣使用ActionScript進行編程,那麼您可以輕鬆入門,並且我發現很多概念確實相似。使用cocos2d處理觸摸到CCSprite的最佳做法

我開始瀏覽示例項目(示例遊戲鏈接here特別有用),我發現觸摸的處理通常不會在CCSprite中完成。相反,實例化CCSprites的CCLayer會對touch事件作出反應,並遍歷它創建的精靈以檢測哪個CCSprite被觸摸(如果有的話)。

我希望CCSprites能夠處理他們是否已被觸及,並致電以上以通知其已被觸摸(如果需要)。在/ tests/TouchesTest下找到的Paddle類就是這樣做的 - 它自己處理觸摸。

所以,我的問題是:什麼被認爲是最好的做法呢?在中心位置處理觸摸並更新孩子以查看所觸及的內容會更好嗎?還是每個孩子應該處理自己的觸摸事件?或者沒有關係?

我更喜歡每個孩子處理自己的觸摸事件,但我希望按照此最佳做法(如果存在)。謝謝!

+0

我想我應該在一般情況下添加一些最佳實踐(例如,我們應該在父級調用「schedule」還是讓每個子級自己處理)。 – donkim 2010-05-24 22:54:32

回答

17

我認爲這是一個偏好問題,但我希望通過繼承CCSprite來讓Sprite檢測它是否被觸及。我在我的CCSprite子類中創建了一個getter方法,它從子類中檢索狀態變量,然後主程序可以相應地執行。

這裏是我的CCSprite子 「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 

,這裏是.m文件的例子:

#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 

希望這有助於和編碼愉快!

加成剔方法和解釋(下面斯蒂芬的問題)的:

要檢查我有一個勾號按鈕的狀態:方法基本上激發每一幀,並檢查我的所有按鈕的狀態。

-(void)tick:(ccTime)dt { 

do my button checks here.... 

} 

我通過調用isPressed或isNotPressed功能那是我spuButton類的一部分,檢查我的按鈕的狀態。

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

然後我做同樣的檢查,看它是否被釋放並作出相應的響應。我這樣做是因爲我想能夠對多個按鈕組合進行反應,另外我想在按下按鈕時執行某些操作,然後在釋放時執行其他操作。我使用ccTouchBegan和ccTouchEnded來更改紋理(精靈圖像)並相應地更改狀態變量。

+0

太棒了,看起來很棒!感謝代碼片段,我可以從中學習一些很好的練習/模式。 – donkim 2010-11-21 03:03:10

+0

沒問題 - 不客氣。感謝它,我喜歡把它展示出來 - 每個人都有自己的風格。 8)以下是一些很好的資源鏈接:http://stackoverflow.com/questions/2293457/cocos2d-resources/4061868#4061868 http://stackoverflow.com/questions/4104124/need-2d-iphone-graphics-設計/ 4111974#4111974 – Mark7777G 2010-11-21 03:37:31

+0

PS:不要忘了投票答案(和評論),這是有用的方式海報獲得信貸。感謝您選擇這個作爲一個很好的答案。 8) – Mark7777G 2010-11-21 03:40:48

0

只是添加到此線程。馬克還提供了一個例子來說明如何實例化spuButton這是有幫助的:

Problem with cocos2d and orientation changes, textures are deformed

你也可以去修改這個例子在正常和點亮的按鈕圖像通過像這樣:

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

然後做同樣的:

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

,並在此方法中,可以設置兩個紋理:

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

這裏是我的解決方案,基於CCSprite希望這將是這對控制對象協議(如播放器或東西)的人

有用:

@class AGSensitiveButton; 

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

.h文件中:

#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 

實現.m文件:

#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