触摸检测问题

发布于 2024-12-26 19:50:16 字数 1504 浏览 0 评论 0原文

我刚刚学习 Cocos2d 和 Objective-C,触摸检测方面存在一些问题。

我在 HelloWorldLayer 中有几个精灵和一些draggableSprites (NSMutableArray)。两个可拖动的精灵相互重叠(底部的较大)。

然后我有一些代码可以摇动触摸的精灵:

- (void)selectSpriteForTouch:(CGPoint)touchLocation {
    CCSprite *touchSprite = nil;
    for (CCSprite *sprite in dragableSprites) {
        if (CGRectContainsPoint(sprite.boundingBox, touchLocation)) {            
            touchSprite = sprite;
            break;
        }
    }    
    if (touchSprite != selSprite) {
        [selSprite stopAllActions];
        [selSprite runAction:[CCRotateTo actionWithDuration:0.1 angle:0]];
        CCRotateTo * rotLeft = [CCRotateBy actionWithDuration:0.1 angle:-1.0];
        CCRotateTo * rotCenter = [CCRotateBy actionWithDuration:0.1 angle:0.0];
        CCRotateTo * rotRight = [CCRotateBy actionWithDuration:0.1 angle:1.0];
        CCSequence * rotSeq = [CCSequence actions:rotLeft, rotCenter, rotRight, rotCenter, nil];
        [touchSprite runAction:[CCRepeatForever actionWithAction:rotSeq]];            
        selSprite = touchSprite;
    }
}

- (BOOL)ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event {
    CGPoint touchLocation = [self convertTouchToNodeSpace:touch];
    [self selectSpriteForTouch:touchLocation];   
    return TRUE;
}

但是当我触摸顶部或底部的精灵时,只有底部的精灵在摇动(它是在 init 中首先添加的)。

我认为我需要替换代码 CGRectContainsPoint(sprite.boundingBox, touchLocation),但我只是不知道如何替换。

我在论坛上呆了几个晚上,但我仍然不明白如何让顶部精灵摇动......

I'm just learning Cocos2d and Objective-C, and I have some problems with touch detection.

I have several sprites in HelloWorldLayer and some draggableSprites (NSMutableArray). Two of the draggableSprites are located one over another (the bottom one is bigger).

Then i have some code that shakes a touched sprite:

- (void)selectSpriteForTouch:(CGPoint)touchLocation {
    CCSprite *touchSprite = nil;
    for (CCSprite *sprite in dragableSprites) {
        if (CGRectContainsPoint(sprite.boundingBox, touchLocation)) {            
            touchSprite = sprite;
            break;
        }
    }    
    if (touchSprite != selSprite) {
        [selSprite stopAllActions];
        [selSprite runAction:[CCRotateTo actionWithDuration:0.1 angle:0]];
        CCRotateTo * rotLeft = [CCRotateBy actionWithDuration:0.1 angle:-1.0];
        CCRotateTo * rotCenter = [CCRotateBy actionWithDuration:0.1 angle:0.0];
        CCRotateTo * rotRight = [CCRotateBy actionWithDuration:0.1 angle:1.0];
        CCSequence * rotSeq = [CCSequence actions:rotLeft, rotCenter, rotRight, rotCenter, nil];
        [touchSprite runAction:[CCRepeatForever actionWithAction:rotSeq]];            
        selSprite = touchSprite;
    }
}

- (BOOL)ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event {
    CGPoint touchLocation = [self convertTouchToNodeSpace:touch];
    [self selectSpriteForTouch:touchLocation];   
    return TRUE;
}

But when I touch the top or bottom sprites, only bottom one is shaking (it was added first in init).

I think that I need to replace the code CGRectContainsPoint(sprite.boundingBox, touchLocation), but I just don't know how.

I spent several nights on forums but I still can't understand how to make the top sprite shake...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

挽袖吟 2025-01-02 19:50:16

尝试更像这样的事情(注意它是 ccTouchesBegan 而不是 ccTouchBegan):

- (void)startShakingSprite:(CCSprite*)sprite {

    [sprite stopAllActions];
    [sprite runAction:[CCRotateTo actionWithDuration:0.1 angle:0]];
    CCRotateTo* rotLeft = [CCRotateBy actionWithDuration:0.1 angle:-1.0];
    CCRotateTo* rotCenter = [CCRotateBy actionWithDuration:0.1 angle:0.0];
    CCRotateTo* rotRight = [CCRotateBy actionWithDuration:0.1 angle:1.0];
    CCSequence* rotSeq = [CCSequence actions:rotLeft, rotCenter, rotRight, rotCenter, nil];
    [sprite runAction:[CCRepeatForever actionWithAction:rotSeq]];  
}

- (void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent*)event {
    //get the touch
    UITouch* touch = [touches anyObject];
    //get its location
    CGPoint location = [touch locationInView:[touch view]];
    //convert location to cocos2d coordinates
    CGPoint point = CGPointMake(location.x, 480 - location.y);

    //now we go through your array of objects and see which contains the touch
    for(id sprite in draggableSprites) {
        if(CGRectContainsPoint(sprite.boundingBox, point)) {
            [self startShakingSprite:sprite];
        }
    }
}

selectSpriteForTouch 中设置 for 循环的方式只会导致第一个由于您的 break 语句,要选择 draggableSprites 中的对象。使用这个新代码,其边界框包含触摸的每个精灵都将被动画化。该代码可能并不完美,因为我直接将其输入 Chrome,但您明白了。

另一件需要注意的重要事情是,您不能在两个不同的精灵上运行相同的操作,如下所示:

id action = [CCScaleTo actionWithDuration:1 scale:1.0];
[someSprite runAction:action];
[someOtherSprite runAction:action];
[oneMoreSprite runAction:action];

此代码将无法按预期工作;只有最后一个 sprite(oneMoreSprite) 才会被动画化。为了在多个精灵中重复使用 CC 动画,请使用以下代码:

id action = [CCScaleTo actionWithDuration:1 scale:1.0];
[someSprite runAction:action];
[someOtherSprite runAction:[[action copy] autorelease]];
[oneMoreSprite runAction:[[action copy] autorelease]];

我们复制该动作,以便它可以由另一个精灵运行(someOtherSpriteoneMoreSprite)而不将其从原始精灵 someSprite 中删除。然后,我们自动释放它,这样就不会出现内存泄漏。

Try something more like this (notice it is ccTouchesBegan not ccTouchBegan):

- (void)startShakingSprite:(CCSprite*)sprite {

    [sprite stopAllActions];
    [sprite runAction:[CCRotateTo actionWithDuration:0.1 angle:0]];
    CCRotateTo* rotLeft = [CCRotateBy actionWithDuration:0.1 angle:-1.0];
    CCRotateTo* rotCenter = [CCRotateBy actionWithDuration:0.1 angle:0.0];
    CCRotateTo* rotRight = [CCRotateBy actionWithDuration:0.1 angle:1.0];
    CCSequence* rotSeq = [CCSequence actions:rotLeft, rotCenter, rotRight, rotCenter, nil];
    [sprite runAction:[CCRepeatForever actionWithAction:rotSeq]];  
}

- (void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent*)event {
    //get the touch
    UITouch* touch = [touches anyObject];
    //get its location
    CGPoint location = [touch locationInView:[touch view]];
    //convert location to cocos2d coordinates
    CGPoint point = CGPointMake(location.x, 480 - location.y);

    //now we go through your array of objects and see which contains the touch
    for(id sprite in draggableSprites) {
        if(CGRectContainsPoint(sprite.boundingBox, point)) {
            [self startShakingSprite:sprite];
        }
    }
}

The way the for loop is set up in selectSpriteForTouch will cause only the first object in draggableSprites to be selected, because of your break statement. With this new code, each sprite whose bounding box contains the touch will be animated. The code might not be perfect because I typed it straight into Chrome, but you get the idea.

Another important thing to note is that you cannot run the same action on two different sprites, like this:

id action = [CCScaleTo actionWithDuration:1 scale:1.0];
[someSprite runAction:action];
[someOtherSprite runAction:action];
[oneMoreSprite runAction:action];

This code will not work as intended; only the last sprite(oneMoreSprite) will be animated. In order to re-use CC animations with multiple sprites, use this code:

id action = [CCScaleTo actionWithDuration:1 scale:1.0];
[someSprite runAction:action];
[someOtherSprite runAction:[[action copy] autorelease]];
[oneMoreSprite runAction:[[action copy] autorelease]];

We make a copy of the action so it can be run by another sprite (someOtherSprite, oneMoreSprite) without removing it from the original sprite, someSprite. Then, we autorelease it so we don't have a memory leak.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文