使用cocos2d处理触摸一个CCSprite的最佳实践 [英] Best practices for handling touches to a CCSprite with cocos2d

查看:97
本文介绍了使用cocos2d处理触摸一个CCSprite的最佳实践的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

嘿,所有。我刚开始研究cocos2d库。我听说这是一个容易的库,如果你习惯于在ActionScript编程,我发现很多的概念是相似的。



我开始查看示例项目(示例游戏与此处特别有用),我看到触摸的处理通常不是在CCSprite中完成。相反,实例化CCSprites的CCLayer对触摸事件做出反应,并通过它创建的sprite迭代,以检测哪个CCSprite被触摸(如果有)。



我想CCSprites处理他们是否已经触摸了自己,并且呼叫向上通知它被触摸(如果需要)。 / tests / TouchesTest下的 Paddle 类只是这样 - 它处理触摸本身。



问题我有:什么是认为最佳实践?是否最好在中央位置处理触摸,并迭代通过孩子看到什么被触摸?还是每个孩子应该处理自己的触摸事件?或者没关系吗?



我希望每个孩子都能处理自己的触摸事件,但我想遵循这个(如果存在)的最佳做法。谢谢!

解决方案

我认为这是一个偏好的问题,但我喜欢sprite检测如果它被子类CCSPrite 。我在我的CCSprite子类中获取一个getter方法,从子类中检索状态变量,然后主程序可以相应地执行。



这里是一个示例头文件子类别spuButton:

  #importcocos2d.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文件的示例:

  #importspuButton.h
#importcocos2d.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)
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
{
//如果不是TouchDispatcher ,你需要保持一个引用
//到touchBegan的触摸,并检查当前触摸是否与该触摸相同
//。
//实际上,它会更复杂,因为在Cocos分派器
//你得到NSSets而不是1 UITouch,所以你需要循环通过set
//每个touchXXX方法。

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

state = kButtonStateNotPressed;
[self setTexture:buttonNormal];

}

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

state =无效。
[self setTexture:buttonNormal];


}

@end



< <>



要检查按钮的状态,我有一个tick:方法,基本上每帧激发,并检查所有我的按钮的状态。

   - (void)tick:(ccTime)dt {

我的按钮在这里检查....

}

我通过调用isPressed或isNotPressed函数检查我的按钮的状态,这是我的spuButton类的一部分。

  for(spuButton * aButton in _fourButtonsArray){
if([aButton isNotPressed])continue; //此按钮未被按下
.....否则记录它被按下.....
}

然后我做同样的检查,看看它是否已被释放,并作出相应的响应。我这样做,因为我想要能够对多个按钮按组合作出反应,我想做的事情,当它被按下,然后什么东西,当它被释放。我使用ccTouchBegan和ccTouchEnded更改纹理(sprite图像),并相应地更改状态变量。


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.

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).

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.

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!

解决方案

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.

Here is an example header file for my CCSprite subclass "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:

    #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):

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.

    -(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.

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.

这篇关于使用cocos2d处理触摸一个CCSprite的最佳实践的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆