Cocos2d处理多层触摸 [英] Cocos2d handling touch with multiple layers

查看:80
本文介绍了Cocos2d处理多层触摸的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经忙了几天试图弄清楚如何在我的Cocos2d项目中处理触摸。情况跟正常情况有点不同。我有几个不同的游戏图层,上面有我需要触摸控制的项目:

I've been busy for a few days trying to figure out how to handle touch in my Cocos2d project. The situation is a bit different as normal. I have a few different game layers that have items on it that I need to control with touch:


  • ControlLayer:持有游戏控件
    (动作,动作按钮)。这一层位于顶层。

  • GameplayLayer:持有游戏对象
    (CCSprites)。这个图层位于ControlLayer的正下方。

现在我的触控在ControlLayer中工作正常,我可以移动我的可玩角色并让他跳,做其他傻事。然而,我无法理解如何实现我的一些CCSprites的触摸。

Now my touches work fine in the ControlLayer, I can move my playable character around and make him jump and do other silly stuff. Yet I cannot grasp how to implement the touches to some of my CCSprites.

到目前为止我收集的信息让我觉得我需要从我的所有触摸输入控制层。然后我不知何故需要将触摸信息级联到GameplayLayer,以便我可以在那里处理输入。另一个选择是让我通过某种方式创建一个指向应该可触摸的对象的指针来从我的精灵中获取CGRect信息。如果项目被触摸,我应该能够在ControlLayer中使用该信息来检查该列表中的每个项目。

The information I've gathered so far makes me think I need get all my touch input from the control layer. Then I somehow need to 'cascade' the touch information to the GameplayLayer so I can handle the input there. Another option would be for me to get the CGRect information from my sprites by somehow creating an array with pointers to the objects that should be touchable. I should be able to use that information in the ControlLayer to check for each item in that list if the item was touched.

执行此操作的最佳选择是什么,以及我该如何实现呢?我对使用cocoa和Objective C进行编程是个新手,所以我不确定这个语言的最佳选择是什么,以及如何在另一个类中访问sprite CGRect信息([mySpriteName boundingBox])然后它是渲染中。

What is the best option to do this, and how do I implement this? I'm kind of new to programming with cocoa and Objective C so I'm not really sure what the best option is for this language and how to access the sprites CGRect information ([mySpriteName boundingBox]) in another class then the layer it is rendered in.

目前,我确定让它工作的唯一方法是为每个CCSprite位置创建重复的CGRects,所以我可以检查它们,但是我知道这不是正确的方法。

At the moment the only way I'm sure to get it to work is create duplicate CGRects for each CCSprite position and so I can check them, but I know this is not the right way to do it.

我到目前为止(测试)是这样的:
ControlLayer.m

What I have so far (to test) is this: ControlLayer.m

- (void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInView: [touch view]];

CGRect rect = CGRectMake(0.0f, 0.0f, 100.0f, 100.0f);

//Tried some stuff here to get see if I could get a sprite by tagname so I could use it's bounding box but that didn't work

// Check for touch with specific location
if (CGRectContainsPoint([tree boundingBox], location)) {
    CCLOG(@"CGRect contains the location, touched!");
}

CCLOG(@"Layer touched at %@", NSStringFromCGPoint(location));

}

提前感谢您的帮助我!

推荐答案

解决问题最容易,最简单的方法是IMO,使用 ccTouchBegan / 已移动 / 已结束而不是 ccTouchesBegan / 已移动 / 。这意味着,你在特定时刻处理一次触摸,这样你就可以避免混淆多次触摸,加上 ccTouchBegan 最重要的功能是CCLayer可以消耗触摸并阻止它传播到下一层。下面的代码示例后的更多解释。

The easiest and simplest way to solve your problem, IMO, is by using ccTouchBegan/Moved/Ended instead of ccTouchesBegan/Moved/Ended. Meaning, you are handling a single touch at a particular moment so you avoid getting confuses over multiple touches, plus the most important feature of ccTouchBegan is a CCLayer can 'consume' the touch and stop it from propagating to the next layers. More explanation after code samples below.

以下是执行此操作的步骤。在应该处理触摸事件的所有CCLayer子类中实现这些方法集:

Here are steps to do it. Implement these sets of methods in all CCLayer subclasses that should handle touch events:

首先,注册CCTouchDispatcher:

First, register with CCTouchDispatcher:

- (void)registerWithTouchDispatcher {
    [[CCTouchDispatcher sharedDispatcher] addTargetedDelegate:self priority:0 swallowsTouches:YES];
}

接下来,实施ccTouchBegan,下面的示例来自我创建的游戏(当然省略了一些部分):

Next, implement ccTouchBegan, example below is from a game I've created (some part omitted of course):

- (BOOL)ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event {
    if (scene.state != lvlPlaying) {
        // don't accept touch if not playing
        return NO;
    }
    CGPoint location = [self convertTouchToNodeSpace:touch];
    if (scene.mode == modePlaying && !firstTouch) {
        if (CGRectContainsPoint(snb_putt.sprite.boundingBox, location)) {
            touchOnPutt = touch.timestamp;

            // do stuff

            // return YES to consume the touch
            return YES;
         }
    }
    // default to not consume touch
    return NO;
}

最后实施ccTouchMoved和ccTouchEnded,就像ccTouches *对应物一样,除了它们处理单触而不是触摸。传递给这些方法的触摸仅限于ccTouchBegan中使用的触摸,因此无需在这两种方法中进行验证。

And finally implement ccTouchMoved and ccTouchEnded like the ccTouches* counterparts, except that they handle single touch instead of touches. The touch that is passed to these methods is restricted to the one that is consumed in ccTouchBegan so no need to do validation in these two methods.

基本上这就是它的工作原理。触摸事件由CCScene基于z排序逐个传递到其每个CCLayer(即从顶层到底层开始),直到任何层消耗触摸。因此,如果顶部的层(例如控制层)消耗触摸,则触摸将不会传播到下一层(例如,对象层)。这样每个层只需要担心自己决定是否消耗触摸。如果它决定不能使用触摸,那么它只需要不消耗触摸(从ccTouchBegan返回NO)并且触摸将自动向下传播。

Basically this is how it works. A touch event is passed by CCScene to each of its CCLayers one by one based on the z-ordering (i.e starts from the top layer to the bottom layer), until any of the layers consume the touch. So if a layer at the top (e.g. control layer) consume the touch, the touch won't be propagated to the next layer (e.g. object layer). This way each layer only has to worry about itself to decide whether to consume the touch or not. If it decides that the touch cannot be used, then it just has to not consume the touch (return NO from ccTouchBegan) and the touch will automatically propagate down the layers.

希望这会有所帮助。

这篇关于Cocos2d处理多层触摸的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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