Hey all. I just started looking into the cocos2d library. I've heard that it's an easy library to get into if you're used to programming in ActionScript and I've found that a lot of the concepts are indeed similar.
大家好。我刚开始研究cocos2d库。我听说如果你习惯用ActionScript编程,这是一个很容易进入的库,我发现很多概念确实很相似。
I started looking through sample projects (the sample games linked here were especially helpful) and I saw that handling of touches usually isn't done in a CCSprite. Rather, the CCLayer that instantiates CCSprites reacts to a touch event and iterates through the sprites it created to detect which CCSprite was touched (if any).
我开始查看示例项目(此处链接的示例游戏特别有用),我看到触摸的处理通常不在CCSprite中完成。相反,实例化CCSprites的CCLayer会对触摸事件作出反应,并迭代它创建的精灵以检测触摸了哪个CCSprite(如果有的话)。
I want CCSprites to handle whether they've been touched themselves, and call up to notify that it's been touched (if needed). The Paddle
class found under /tests/TouchesTest does just this - it handles touches by itself.
我希望CCSprites能够处理他们是否已被触摸过,并打电话通知它已被触摸(如果需要)。在/ tests / TouchesTest下找到的Paddle类就是这样 - 它自己处理触摸。
So, the question I have is: What's considered best practice for this? Is it better to have touches handled in a central location and iterate through children to see what's been touched? Or should each child handle its own touch events? Or does it not matter?
所以,我的问题是:对此最佳做法是什么?在中心位置处理触摸并通过子节点迭代以查看触摸的内容是否更好?或者每个孩子应该处理自己的触摸事件?或者没关系?
I'd prefer each child handling its own touch events but I'd like to follow best practices on this (if they exist). Thanks!
我希望每个孩子都能处理自己的触摸事件,但我想遵循这方面的最佳实践(如果存在的话)。谢谢!
3 个解决方案
#1
17
I think it is a matter of preference but I like to have the sprite detect if it was touched by subclassing CCSprite. I make a getter method in my CCSprite subclass that retrieves the state variable from the subclass and then the main program can act accordingly.
我认为这是一个偏好问题,但我喜欢通过子类化CCSprite来触及sprite。我在我的CCSprite子类中创建一个getter方法,从子类中检索状态变量,然后主程序可以相应地执行。
Here is an example header file for my CCSprite subclass "spuButton":
这是我的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
and here is an example of the .m file:
这是一个.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
Hope this helps and Happy coding!
希望这有助于和快乐编码!
ADDITION of tick method and explanation (for Stephan's question below):
添加滴答方法和解释(适用于Stephan的问题):
To check the status of the buttons I have a tick: method that basically fires every frame and checks the status of all my buttons.
为了检查按钮的状态,我有一个tick:方法,它基本上会触发每一帧并检查我所有按钮的状态。
-(void)tick:(ccTime)dt {
do my button checks here....
}
I check the status of my buttons by calling a isPressed or isNotPressed function that is part of my spuButton class.
我通过调用isPressed或isNotPressed函数检查我的按钮的状态,该函数是我的spuButton类的一部分。
for (spuButton *aButton in _fourButtonsArray) {
if ([aButton isNotPressed]) continue; //this button is not pressed
.....otherwise record that it is pressed.....
}
Then I do the same kind of check to see if it has been released and respond accordingly. I do it this way because I want to be able to react to multiple button press combos plus I want to do something when it gets pressed down and then something else when it gets released. I use the ccTouchBegan and ccTouchEnded to change the textures(the sprite image) and to change the state variable accordingly.
然后我做同样的检查,看它是否已被释放并做出相应的反应。我是这样做的,因为我希望能够对多个按钮按下组合做出反应,而且我想在按下它时做一些事情,然后在它被释放时做其他事情。我使用ccTouchBegan和ccTouchEnded来更改纹理(精灵图像)并相应地更改状态变量。
#2
0
just adding to this thread. Mark also provides an examples how to instantiate the spuButton which is helpful:
只是添加到这个线程。 Mark还提供了一个如何实例化spuButton的示例:
Problem with cocos2d and orientation changes, textures are deformed
cocos2d问题和方向改变,纹理变形
you can also go in modify this example to pass in both normal and lit button images like so:
您还可以修改此示例以传递正常和点亮的按钮图像,如下所示:
+ (id)spuButtonWithTexture:(CCTexture2D *)normalTexture lit:(CCTexture2D *)litTexture
and then do the same to:
然后做同样的事情:
- (id)initWithTexture:(CCTexture2D *)normalTexture lit:(CCTexture2D *)litTexture
and within this method, you can set both textures:
在此方法中,您可以设置两个纹理:
[self setNormalTexture:normalTexture];
[self setLitTexture:litTexture];
#3
0
Here is my solution, based on CCSprite hope it will be useful for somebody
这是我的解决方案,基于CCSprite希望它对某些人有用
this is protocol for controlled object (like player or something):
这是受控对象的协议(如播放器或其他东西):
@class AGSensitiveButton;
@protocol AGSensitiveButtonControlledObjectProtocol <NSObject>
@required
- (void)sensitiveButtonTouchDown:(AGSensitiveButton *)sButton;
- (void)sensitiveButtonTouchUp:(AGSensitiveButton *)sButton;
@optional
- (void)sensitiveTouchButtonKeepPressed:(AGSensitiveButton *)sButton forTime:(ccTime)pressTime;
@end
.h file:
.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
implementation .m file:
实现.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
#1
17
I think it is a matter of preference but I like to have the sprite detect if it was touched by subclassing CCSprite. I make a getter method in my CCSprite subclass that retrieves the state variable from the subclass and then the main program can act accordingly.
我认为这是一个偏好问题,但我喜欢通过子类化CCSprite来触及sprite。我在我的CCSprite子类中创建一个getter方法,从子类中检索状态变量,然后主程序可以相应地执行。
Here is an example header file for my CCSprite subclass "spuButton":
这是我的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
and here is an example of the .m file:
这是一个.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
Hope this helps and Happy coding!
希望这有助于和快乐编码!
ADDITION of tick method and explanation (for Stephan's question below):
添加滴答方法和解释(适用于Stephan的问题):
To check the status of the buttons I have a tick: method that basically fires every frame and checks the status of all my buttons.
为了检查按钮的状态,我有一个tick:方法,它基本上会触发每一帧并检查我所有按钮的状态。
-(void)tick:(ccTime)dt {
do my button checks here....
}
I check the status of my buttons by calling a isPressed or isNotPressed function that is part of my spuButton class.
我通过调用isPressed或isNotPressed函数检查我的按钮的状态,该函数是我的spuButton类的一部分。
for (spuButton *aButton in _fourButtonsArray) {
if ([aButton isNotPressed]) continue; //this button is not pressed
.....otherwise record that it is pressed.....
}
Then I do the same kind of check to see if it has been released and respond accordingly. I do it this way because I want to be able to react to multiple button press combos plus I want to do something when it gets pressed down and then something else when it gets released. I use the ccTouchBegan and ccTouchEnded to change the textures(the sprite image) and to change the state variable accordingly.
然后我做同样的检查,看它是否已被释放并做出相应的反应。我是这样做的,因为我希望能够对多个按钮按下组合做出反应,而且我想在按下它时做一些事情,然后在它被释放时做其他事情。我使用ccTouchBegan和ccTouchEnded来更改纹理(精灵图像)并相应地更改状态变量。
#2
0
just adding to this thread. Mark also provides an examples how to instantiate the spuButton which is helpful:
只是添加到这个线程。 Mark还提供了一个如何实例化spuButton的示例:
Problem with cocos2d and orientation changes, textures are deformed
cocos2d问题和方向改变,纹理变形
you can also go in modify this example to pass in both normal and lit button images like so:
您还可以修改此示例以传递正常和点亮的按钮图像,如下所示:
+ (id)spuButtonWithTexture:(CCTexture2D *)normalTexture lit:(CCTexture2D *)litTexture
and then do the same to:
然后做同样的事情:
- (id)initWithTexture:(CCTexture2D *)normalTexture lit:(CCTexture2D *)litTexture
and within this method, you can set both textures:
在此方法中,您可以设置两个纹理:
[self setNormalTexture:normalTexture];
[self setLitTexture:litTexture];
#3
0
Here is my solution, based on CCSprite hope it will be useful for somebody
这是我的解决方案,基于CCSprite希望它对某些人有用
this is protocol for controlled object (like player or something):
这是受控对象的协议(如播放器或其他东西):
@class AGSensitiveButton;
@protocol AGSensitiveButtonControlledObjectProtocol <NSObject>
@required
- (void)sensitiveButtonTouchDown:(AGSensitiveButton *)sButton;
- (void)sensitiveButtonTouchUp:(AGSensitiveButton *)sButton;
@optional
- (void)sensitiveTouchButtonKeepPressed:(AGSensitiveButton *)sButton forTime:(ccTime)pressTime;
@end
.h file:
.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
implementation .m file:
实现.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