The short answer: You can't.
The long answer: You can get the same effect, but not in the same way.
CCSpriteBatchNode works by drawing all of its CCSprite children in a single glDrawElements call with a common texture (sprite sheet), which is what gives it such good performance. But as a result, every child MUST be a sprite, and if you add a child to a sprite, it will be ignored.
So, your only recourse at this point is to subclass CCSprite as a button and duplicate a lot of functionality, like so:
ButtonSprite.h:
//
// ButtonSprite.h
// TestButtonSprite
//
// Created by Karl Stenerud on 9/1/11.
//
#import "cocos2d.h"
@class ButtonSprite;
typedef void (^ButtonPressCallback)(ButtonSprite* button);
/**
* A sprite that can respond to touches.
* Most of this code was taken from CCLayer.
*/
@interface ButtonSprite : CCSprite <CCStandardTouchDelegate, CCTargetedTouchDelegate>
{
BOOL touchEnabled_;
int touchPriority_;
BOOL swallowTouches_;
BOOL registeredWithDispatcher_;
BOOL touchInProgress_;
BOOL buttonWasDown_;
ButtonPressCallback onButtonPressedCallback_;
}
/** Priority position in which this node will be handled (lower = sooner) */
@property(nonatomic,readwrite,assign) int touchPriority;
/** If true, no other node will respond to touches this one responds to */
@property(nonatomic,readwrite,assign) BOOL swallowTouches;
/** If true, this node responds to touches. */
@property(nonatomic,readwrite,assign) BOOL touchEnabled;
/** Called whenever a full touch completes */
@property(nonatomic,readwrite,copy) ButtonPressCallback onButtonPressedCallback;
/** Called when a button press is detected. */
- (void) onButtonPressed;
/** Called when a button is pushed down. */
- (void) onButtonDown;
/** Called when a button is released. */
- (void) onButtonUp;
- (BOOL) touchHitsSelf:(UITouch*) touch;
- (BOOL) touch:(UITouch*) touch hitsNode:(CCNode*) node;
@end
ButtonSprite.m:
//
// ButtonSprite.m
// TestButtonSprite
//
// Created by Karl Stenerud on 9/1/11.
//
#import "ButtonSprite.h"
@interface ButtonSprite ()
- (void) registerWithTouchDispatcher;
- (void) unregisterWithTouchDispatcher;
@end
@implementation ButtonSprite
@synthesize touchEnabled = touchEnabled_;
@synthesize touchPriority = touchPriority_;
@synthesize swallowTouches = swallowTouches_;
@synthesize onButtonPressedCallback = onButtonPressedCallback_;
- (id) init
{
if(nil != (self = [super init]))
{
touchPriority_ = 0;
swallowTouches_ = YES;
touchEnabled_ = YES;
self.isRelativeAnchorPoint = YES;
self.anchorPoint = ccp(0.5, 0.5);
}
return self;
}
- (void) dealloc
{
[self unregisterWithTouchDispatcher];
[onButtonPressedCallback_ release];
[super dealloc];
}
- (void) registerWithTouchDispatcher
{
[self unregisterWithTouchDispatcher];
[[CCTouchDispatcher sharedDispatcher] addTargetedDelegate:self priority:self.touchPriority swallowsTouches:self.swallowTouches];
registeredWithDispatcher_ = YES;
}
- (void) unregisterWithTouchDispatcher
{
if(registeredWithDispatcher_)
{
[[CCTouchDispatcher sharedDispatcher] removeDelegate:self];
registeredWithDispatcher_ = NO;
}
}
- (void) setSwallowTouches:(BOOL) value
{
if(swallowTouches_ != value)
{
swallowTouches_ = value;
if(isRunning_ && touchEnabled_)
{
[self registerWithTouchDispatcher];
}
}
}
- (void) setTouchPriority:(int) value
{
if(touchPriority_ != value)
{
touchPriority_ = value;
if(isRunning_ && touchEnabled_)
{
[self registerWithTouchDispatcher];
}
}
}
-(void) setTouchEnabled:(BOOL)enabled
{
if( touchEnabled_ != enabled )
{
touchEnabled_ = enabled;
if( isRunning_ )
{
if( touchEnabled_ )
{
[self registerWithTouchDispatcher];
}
else
{
[self unregisterWithTouchDispatcher];
}
}
}
}
- (void)cleanup
{
self.touchEnabled = NO;
}
#pragma mark TouchableNode - Callbacks
-(void) onEnter
{
// register 'parent' nodes first
// since events are propagated in reverse order
if (self.touchEnabled)
{
[self registerWithTouchDispatcher];
}
// then iterate over all the children
[super onEnter];
}
-(void) onExit
{
if(self.touchEnabled)
{
[self unregisterWithTouchDispatcher];
}
[super onExit];
}
-(BOOL) ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event
{
if([self touchHitsSelf:touch])
{
touchInProgress_ = YES;
buttonWasDown_ = YES;
[self onButtonDown];
return YES;
}
return NO;
}
-(void) ccTouchMoved:(UITouch *)touch withEvent:(UIEvent *)event
{
if(touchInProgress_)
{
if([self touchHitsSelf:touch])
{
if(!buttonWasDown_)
{
[self onButtonDown];
}
}
else
{
if(buttonWasDown_)
{
[self onButtonUp];
}
}
}
}
-(void) ccTouchEnded:(UITouch *)touch withEvent:(UIEvent *)event
{
if(buttonWasDown_)
{
[self onButtonUp];
}
if(touchInProgress_ && [self touchHitsSelf:touch])
{
touchInProgress_ = NO;
[self onButtonPressed];
}
}
-(void) ccTouchCancelled:(UITouch *)touch withEvent:(UIEvent *)event
{
if(buttonWasDown_)
{
[self onButtonUp];
}
touchInProgress_ = NO;
}
- (void) onButtonDown
{
buttonWasDown_ = YES;
}
- (void) onButtonUp
{
buttonWasDown_ = NO;
}
- (void) onButtonPressed
{
self.onButtonPressedCallback(self);
}
- (BOOL) touchHitsSelf:(UITouch*) touch
{
return [self touch:touch hitsNode:self];
}
- (BOOL) touch:(UITouch*) touch hitsNode:(CCNode*) node
{
CGRect r = CGRectMake(0, 0, node.contentSize.width, node.contentSize.height);
CGPoint local = [node convertTouchToNodeSpace:touch];
return CGRectContainsPoint(r, local);
}
@end
Use it like so:
ButtonSprite* myButton = [ButtonSprite spriteWithFile:@"button_image.png"];
myButton.onButtonPressedCallback = ^(ButtonSprite* button)
{
NSLog(@"Pressed!");
};
[self addChild: myButton];
Note that if you use this class in a batch node, it MUST NOT have any children of its own!