Суставы ломаются при масштабировании

В последнее время я репетировал Sprite Kit и столкнулся с очень странной проблемой. При масштабировании (изменении масштаба) родительского узла тела, которые соединяются вместе с помощью SKPhysicsJointPin, постепенно отделяются друг от друга, а затем соединения ломаются. Позвольте мне показать вам изображения.

Это для нормального состояния: Вот нормальное состояние

Вот при увеличении: Увеличено

А вот при уменьшении: Уменьшено

Если вы спросите, как я соединяю тела: я соединяю коричневые палочки с синими узлами в центре синих узлов. Есть идеи, в чем моя проблема?

РЕДАКТИРОВАТЬ: Недавно я обнаружил, что суставы не ломаются, и все работает, как и ожидалось, когда соединяющиеся тела не являются динамическими. Например, если я использую [SKPhysicsBody bodyWithEdgleLoopFromRect] вместо [SKPhysicsBody bodyWithRectangleOfSize] для создания физического тела спрайта, проблем не возникает. Но мне нужно, чтобы тела были динамичными.

Вот код, который я использую для привязки физики к узлам. Конечно, все это делается динамически. Я просто жестко закодировал для краткости.

 -(void)attachPhysics{
    //fixedComponentLeft & fixedComponentRight are two SKSprites
    fixedComponentLeft.physicsBody=[SKPhysicsBody bodyWithCircleOfRadius:fixedComponentLeft.frame.size.width];
    fixedComponentRight.physicsBody=[SKPhysicsBody bodyWithCircleOfRadius:fixedComponentLeft.size.width];
    beam1.physicsBody=[SKPhysicsBody bodyWithRectangleOfSize:beam1.size];
    joiningBody.physicsBody=[SKPhysicsBody bodyWithCircleOfRadius:joiningBody1.size.width];
    [self.scene.physicsWorld addJoint:[SKPhysicsJointPin jointWithBodyA:fixedComponentLeft.physicsBody bodyB:beam1.physicsBody anchor:fixedComponentLeft.position]];
    [self.scene.physicsWorld addJoint:[SKPhysicsJointPin  jointWithBodyA:joiningBody.physicsBody bodyB:beam1.physicsBody anchor:beam1.endPoint]];
    beam2.physicsBody=[SKPhysicsBody bodyWithRectangleOfSize:beam2.size];
    [self.scene.physicsWorld addJoint:[SKPhysicsJointPin  jointWithBodyA:joiningBody.physicsBody bodyB:beam2.physicsBody anchor:beam2.position]];
    [self.scene.physicsWorld addJoint:[SKPhysicsJointPin jointWithBodyA:fixedComponentRight.physicsBody bodyB:beam2.physicsBody anchor:beam2.endPoint]];
 }

В приведенном выше коде луч1 и луч2 являются экземплярами подкласса SKSpriteNode. По умолчанию точка привязки равна (0,0,5), и я добавил свойство endPoint, которое служит крайней правой точкой спрайта.


person Mikayil Abdullayev    schedule 19.02.2014    source источник


Ответы (3)


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

  1. Масштабируйте саму сцену, а не дочерние узлы: когда я попробовал это, неудивительно, что у меня возникла очень большая проблема. Поскольку сцена обычно является корневым узлом для всех узлов в игре, это означает, что все будет масштабироваться соответственно вверх или вниз. Это также включает в себя панель управления. Так что не лучшая идея

  2. Вы можете попытаться создать подкласс SKNode, чтобы он реализовал свой собственный экземпляр SKPhysicsWrold и добавить все в этот мир: К сожалению, по некоторым причинам Apple сделала невозможным создание собственного физического мира. Да, вы можете добавить свои суставы в любой мир, какой захотите. Но суставам нужны тела, чтобы жить в одном мире. Я помню, что из чистого, развернутого Box2D тела также нужно было добавить в физический мир. Итак, я предполагаю, что Apple сделала это автоматически, когда вы устанавливаете физическое тело, оно добавляется в scene.physicsWorld. И если вы попытаетесь добавить соединения в специально созданный физический мир, вы получите ошибку Box2D, указывающую, что емкость соединения меньше количества соединений. :))

  3. Кажется, что единственный реальный способ — перестроить физические тела и суставы. Но это настоящая боль, и я тоже не преуспел в этом. Помимо потенциального влияния на производительность, этот подход требует очень точного порядка воссоздания тел и суставов, установки их предыдущих скоростей и т. д.

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

person Community    schedule 10.03.2014

Я не уверен, как выглядит ваш код, но я столкнулся с похожей проблемой, когда у меня была веревка в игре-платформере (например, супер марио), с использованием тайловых карт, и если я добавил веревку в начале уровня, все работало нормально, и связь между суставами держалась, но когда я помещал эту веревку в середине или в конце уровня, суставы становились более эластичными, и веревка разрывалась, в то же время отправляя физический мир в бесконечный цикл, останавливающий все.

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

Когда я использовал

 CGPoint positionInScene = [self convertPoint:nodeB.position  fromNode:self.map];

следующий код для преобразования положения узла в координаты сцены, а затем использовал эту переменную positionInScene для присоединения соединения в качестве привязки следующим образом:

[SKPhysicsJointFixed jointWithBodyA: nodeA.physicsBody
                              bodyB: nodeB.physicsBody
                             anchor: CGPointMake(positionInScene.x, positionInScene.y)];

все стало работать корректно.

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

person Andrew    schedule 11.03.2014
comment
Спасибо @Andrew за понимание. Я добавил немного кода. - person Mikayil Abdullayev; 11.03.2014
comment
Вы пытались использовать [yourScene convertPoint:fromNode:] для позиций привязки при их установке? - person Andrew; 11.03.2014
comment
Я просто сделал это после вашего предложения, и на самом деле я, вероятно, пробовал это раньше. Но это не помогает - person Mikayil Abdullayev; 12.03.2014

Столкнулись с подобными проблемами с панорамированием мира.

Мировые координаты больше не совпадают с физическими координатами.

Таким образом, вы должны использовать вызовы [scene convertPoint:pt fromNode:pannedWorld].

Я переопределил applyForce:atPoint: и applyTorque:atPoint:, чтобы абстрагироваться от этого и убедиться, что код остается разборчивым.

Я также обнаружил, что если вы добавляете объекты в сцену, находясь в didBeginContact: (например, осколки от взрывов), то любые созданные объекты должны иметь координаты в абсолютной системе координат физического мира, а не в относительном панорамированном/масштабированном мире.

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

person RikMaxSpeed    schedule 04.04.2014
comment
Спасибо за вклад, но я пришел к выводу, что Sprite Kit все еще незрелый с множеством ошибок / предполагаемого поведения, которые мешают созданию передовой игры. Так что я вернулся к старому доброму Cocos2D. Теперь в него интегрирована физика с V3. - person Mikayil Abdullayev; 05.04.2014