Проблема с обновлением оценки на основе обнаружения столкновений в SpriteKit - PullRequest
0 голосов
/ 29 апреля 2018

Я работаю над игрой SpriteKit, где в одной из сцен мне нужно обновить счет, основываясь на столкновении двух спрайтов. Я намерен увеличить счет на 1 всякий раз, когда эти два узла SKSpriteNode сталкиваются друг с другом. В SpriteKit есть метод обнаружения столкновений, который сам занимается обнаружением столкновений. Я использую этот метод по умолчанию didBeginContact: чтобы обнаружить столкновение, удалите один из объектов, участвующих в столкновении, и увеличьте его на 1. Есть несколько объектов одного типа, падающих сверху, и есть объект, подобный корзине, который игрок может перемещать горизонтально, чтобы поймать эти падающие предметы. При столкновении с корзиной предметы, падающие сверху, удаляются, и оценка увеличивается. Вопрос очень прост: счет увеличивается не только на 1, но и на 2,3,4,5. Это означает, что вместо обнаружения отдельного столкновения, как это и должно быть, он обнаруживает более одного столкновения и, следовательно, увеличивает счет соответственно.
Я рассматривал здесь другой вопрос, подобный этому, но это решение никогда не может относиться к моему. В моей игре в течение ограниченного времени подобные объекты падают сверху, пока не закончится время. Есть ли возможный способ решить эту проблему. Я пытался использовать переменную bool, такую ​​как didCollide, внутри метода обнаружения столкновений и даже в отдельном методе увеличения оценки, но проблема не решается.
Вот код, который я пробую в методе обнаружения столкновений.

-(void)didBeginContact:(SKPhysicsContact *)contact {

if (contact.bodyA.categoryBitMask == Stones) {
    [contact.bodyA.node removeFromParent];

    if (contactOccurred == NO) {
     contactOccurred = YES;
     [self updateScore:contactOccurred];
     }

}
else {
    [contact.bodyB.node removeFromParent];

    if (contactOccurred == NO) {
    ContactOccurred = YES;
    [self updateScore:contactOccurred];
     }        
  }
}  

Фрагмент кода для метода увеличения оценки здесь.

-(void)updateScore:(BOOL)collisionOccurred {

if (collisionOccurred == YES) {

    contactOccurred = NO;
    self.score= self.score + 1;
}

}

Ответы [ 2 ]

0 голосов
/ 03 мая 2018

Я решил проблему сам, прочитав документацию Apple и поэкспериментировав с различными вариантами. Проблема заключалась в том, что метод didBeginContact, который является методом по умолчанию, предоставляемым SpriteKit для обнаружения контактов и столкновений, вызывался несколько раз, как Джерн пытался объяснить в своем ответе. Но объекты, участвующие в столкновении в моей игре, не имеют неправильной формы. Один тип объектов имеет овальную форму, в то время как другой тип имеет более или менее прямоугольную форму. Однако метод вызывался более одного раза при каждом контакте между двумя объектами.

Как я решил это?
Я попытался применить технику, предложенную Джерн, хотя я знал, что это было не настоящее решение, которое я искал, а скорее временное прикрытие. Но на удивление это не сработало для моей игры, так как счет все равно будет увеличиваться случайным образом. Я удалил свои спрайты овальной формы и заменил их простыми круглыми спрайтами сплошного цвета на случай, если мои спрайты овальной формы не будут гладкими по краям. Даже тогда проблема продолжалась, что привело меня к документации Apple по этой ссылке ссылка . Я узнал, что для достижения наилучших характеристик физического тела и большей точности обнаружения столкновений следует по возможности использовать более простые физические тела. Круглое физическое тело наиболее эффективно с точки зрения производительности, поскольку оно довольно быстрое и простое в обработке. Далее следует прямоугольное физическое тело, за которым следует многоугольное физическое тело и физическое тело из текстуры изображения на последней. Чем сложнее физическое тело, тем больше будут вычислительные затраты и вероятность потери точности возрастет. Я создал физические тела моих сталкивающихся объектов, используя текстуру изображения. Физические тела, созданные из текстуры, каким-то образом были причиной (или, по крайней мере, в моем случае), почему методContactMethod вызывался несколько раз. Даже физическое тело простого круглого спрайта, созданного из текстуры, увеличивало счет на 2 вместо 1. Я изменил код, чтобы создать физические тела круглой формы для моих спрайтов овальной формы, и теперь все идеально, не нужно менять категорию для удаления. узлы или любой логический флаг.

Избежание нескольких вызовов метода didBeginContact с использованием логических флагов или любым другим способом может быть прикрытием, но не решением, которое работает в нескольких случаях, но не работает в других. Попробуйте использовать простейшие физические тела, где это возможно, особенно когда вы начинаете получать неточные результаты от столкновений и контактов.

0 голосов
/ 29 апреля 2018

Когда вы используете узлы SKSpriteNode, чьи тела SKPhysics имеют неправильную форму, они могут иметь более одной точки контакта, когда они касаются. Вот почему didBeginContact можно вызывать несколько раз для одних и тех же двух узлов SKSpriteNode, прежде чем узел будет удален из его родителя.

См. Этот пример для контакта с 2 точками контакта (в результате чего didBeginContact вызывается дважды для одних и тех же двух объектов):

enter image description here

Чтобы избежать этого, вы можете изменить физику тела categoryBitMask в didBeginContact, чтобы все последующие контакты больше не распознавались:

-(void)didBeginContact:(SKPhysicsContact *)contact {

    if (contact.bodyA.categoryBitMask == Stones) {
        contact.bodyA.categoryBitMask = None
        [contact.bodyA.node removeFromParent];
        self.score= self.score + 1;
    } else if (contact.bodyB.categoryBitMask == Stones) {
        contact.bodyB.categoryBitMask = None
        [contact.bodyB.node removeFromParent];
        self.score= self.score + 1;
    }       
}

Очевидно, вам нужно определить значение None битовой маски и исключить его из contactTestBitMask вашей корзины, например, SKSpriteNode. Таким образом, после изменения categoryBitMask вашего Stone SKSpriteNode с Stones на None все дальнейшие контакты будут игнорироваться.

...