首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >创建CCSprites为CCBatchNode子级的可触摸CCNodes时出现问题

创建CCSprites为CCBatchNode子级的可触摸CCNodes时出现问题
EN

Stack Overflow用户
提问于 2011-09-01 22:20:50
回答 2查看 986关注 0票数 4

这可能需要一些解释,但这里是这样的,真的很感谢任何见解。

简而言之:如何创建其CCSprite图像是另一个类中CCSpriteBatchNode的子级的TouchableButton (它自己检测触摸)?(通常情况下,CCSprite将是TouchableButton本身的子级)。

长版本:

我正在使用Cocos2d构建一个游戏。游戏关注的是一个充满了智能体( EnvironmentView: CCLayer类)的场景( AgentView: CCNode类),这些智能体在周围运行并相互交互。

EnvironmentView维护一个AgentView对象列表,并根据需要创建/销毁它们(取决于它们的交互方式)。

每个AgentView都有一个CCSprite @属性,该属性作为CCBatchNode的子级添加( EnvironmentView的@属性),该属性作为EnvironmentView的子级添加。

我正在尝试实现一个功能,用户可以触摸代理,并将它们从一个地方移动到另一个地方。

因为在EnvironmentView中有许多移动的代理,所以我不想使用标准的方法,即获取触摸位置并循环遍历所有AgentView CCSprites,以查看触摸是否命中其中之一(这将大大降低帧率,请:对推广此方法的答案不感兴趣)。

相反,我想让每个AgentView成为一个可触摸的节点(一个知道它何时被触摸的节点,而不是一个在它被触摸时被告知的节点(上面提到的方法))。

基本上,我想用某种TouchableButton对象替换或扩充每个AgentView的CCSprite。

我使用了一个类(让我们称之为TouchableButton),它对游戏中与UI相关的按钮使用了这种方法,它们知道什么时候被触摸,而不需要在父层中实现任何CCTouchesBegan方法。但是我一直无法使TouchableButton适应这个用例,原因如下:

TouchableButtons将CCSprite作为初始化参数。此CCSprite被设置为按钮的可触摸部分,并作为按钮本身的子项添加。因为我还将CCSprite作为CCSpriteBatchNode的子对象添加到EnvironmentView中,所以我得到了一个错误(不能将某个东西作为子对象两次添加到两个不同的父对象中)。我如何组织事物以避免这种冲突?

提前感谢您的帮助!

EN

回答 2

Stack Overflow用户

发布于 2011-09-02 00:58:40

简短的回答是:你不能。

长篇大论的答案是:你可以得到同样的效果,但不是以同样的方式。

CCSpriteBatchNode的工作原理是在单个glDrawElements调用中使用一个通用的纹理(精灵工作表)绘制所有的CCSprite子对象,这就是它具有如此好的性能的原因。但结果是,每个子对象都必须是精灵,如果您将一个子对象添加到精灵中,它将被忽略。

因此,在这一点上,您唯一的办法是将CCSprite子类化为一个按钮,并复制许多功能,如下所示:

ButtonSprite.h:

代码语言:javascript
复制
//
//  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:

代码语言:javascript
复制
//
//  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

像这样使用它:

代码语言:javascript
复制
    ButtonSprite* myButton = [ButtonSprite spriteWithFile:@"button_image.png"];
    myButton.onButtonPressedCallback = ^(ButtonSprite* button)
    {
        NSLog(@"Pressed!");
    };
    [self addChild: myButton];

请注意,如果在批处理节点中使用此类,它不能有自己的子类!

票数 2
EN

Stack Overflow用户

发布于 2011-09-01 23:36:33

我自己对此已经纠结了很多,我的结论是这是不可能的,你必须为每个按钮使用一个单独的图像文件。

我希望这个特性会出现在1.0版本中,但我不认为它会出现。

不过,希望我是错的!:)

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/7271719

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档