Cocos2d работает с несколькими слоями - PullRequest
19 голосов
/ 07 марта 2011

Я несколько дней был занят, пытаясь понять, как справиться с касанием в моем проекте Cocos2d.Ситуация немного отличается от обычной.У меня есть несколько разных игровых слоев, на которых есть элементы, которыми нужно управлять с помощью касания:

  • ControlLayer: удерживает игровые элементы управления (движение, кнопка действия).Этот слой находится сверху.
  • GameplayLayer: содержит игровые объекты (CCSprites).Этот слой находится прямо под ControlLayer.

Теперь мои прикосновения отлично работают в ControlLayer, я могу перемещать моего играбельного персонажа, заставлять его прыгать и делать другие глупые вещи.Тем не менее, я не могу понять, как реализовать прикосновения к некоторым из моих CCSprites.

Информация, которую я собрал до сих пор, заставляет меня думать, что мне нужно получить весь сенсорный ввод от контрольного уровня.Затем мне нужно как-то «каскадировать» сенсорную информацию в GameplayLayer, чтобы я мог обрабатывать вводимые данные.Другой вариант для меня - получить информацию CGRect от моих спрайтов, каким-то образом создавая массив с указателями на объекты, которые должны быть сенсорными.Я должен быть в состоянии использовать эту информацию в ControlLayer для проверки каждого элемента в этом списке, если элемент был затронут.

Каков наилучший вариант, чтобы сделать это, и как мне реализовать это?Я новичок в программировании с какао и Objective C, так что я не совсем уверен, что лучший вариант для этого языка и как получить доступ к информации CGRect спрайтов ([mySpriteName boundingBox]) в другом классе, а затем в слое

На данный момент единственный способ заставить его работать - создать дубликаты CGRect для каждой позиции CCSprite, поэтому я могу их проверить, но я знаю, что это неправильный способэто.

То, что я до сих пор (для проверки) это: 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));

}

Заранее спасибо за помощь!

1 Ответ

27 голосов
/ 08 марта 2011

Самый простой и простой способ решить вашу проблему, IMO, это использовать ccTouchBegan / Moved / Ended вместо ccTouchesBegan / Moved / Ended. Это означает, что вы обрабатываете одно касание в определенный момент, чтобы избежать путаницы при нескольких касаниях, плюс самая важная особенность ccTouchBegan - это то, что CCLayer может «потреблять» касание и останавливать его распространение на следующие слои. Более подробное объяснение после примеров кода ниже.

Вот шаги, чтобы сделать это. Реализуйте эти наборы методов во всех подклассах CCLayer, которые должны обрабатывать сенсорные события:

Сначала зарегистрируйтесь в CCTouchDispatcher:

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

Далее, реализуйте ccTouchBegan, пример ниже взят из созданной мной игры (часть, конечно, пропущена):

- (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, поэтому нет необходимости выполнять проверку в этих двух методах.

По сути, так оно и есть. Событие касания передается CCScene каждому из его слоев CCLay по одному на основе z-порядка (т. Е. Начинается с верхнего слоя до нижнего слоя) до тех пор, пока какой-либо из слоев не будет поглощать касание. Таким образом, если слой наверху (например, управляющий слой) потребляет касание, касание не будет распространено на следующий уровень (например, объектный слой). Таким образом, каждый слой должен заботиться о себе, чтобы решить, использовать ли сенсорный экран или нет. Если он решает, что касание не может быть использовано, то он просто не должен потреблять касание (вернуть NO из ccTouchBegan), и касание будет автоматически распространяться по слоям.

Надеюсь, это поможет.

...