Добавить SKReferenceNode программно

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

Это конкретная часть кода:

if let nextPart = SKReferenceNode(fileNamed: "Scene2_city2") {
        if self.childNodeWithName("Scene2_city2") == nil {
            self.addChild(nextPart)
        }
    }

«Scene2_city2» — это имя файла .sks, а также имя сцены внутри файла.

Запустив код, я получаю сообщение об ошибке:

*** Завершение работы приложения из-за необработанного исключения «Невозможно добавить тело, оно уже существует в мире», причина: «Невозможно добавить тип тела: представленный объект: [имя: 'Scene2_city2' кадр: {{-0, -0}, {1024 , 768}} привязка:{0, 0}], уже существует в мире'

Это очень странно, потому что я сначала проверяю, прежде чем добавлять.

Вопрос: Как программно добавить SKReferenceNode в SKScene?

РЕДАКТИРОВАТЬ: Вот простой пример проекта на битбакете. Эталонная сцена добавлена ​​для крана.


person jendan    schedule 03.04.2016    source источник
comment
Если вы случайно сможете сделать минимальный пример, который может воспроизвести проблему, о которой вы говорите, и загрузить репо на Github, вы, вероятно, получите лучший ответ.   -  person Whirlwind    schedule 03.04.2016
comment
Кроме того, это не то же самое, что вы испытываете, но, возможно, стоит прочитать, потому что это связано с той же ошибкой, которую вы видите: forums.developer.apple.com/thread/19583, stackoverflow.com/questions/21745797/skphysicsbody-malloc-error... Вероятно, есть еще несколько тем, я видел еще несколько на StackOverflow по этому поводу.   -  person Whirlwind    schedule 03.04.2016
comment
Спасибо за информацию. Я не думаю, что делаю те же ошибки. Вот простой пример проекта на битбакете.   -  person jendan    schedule 04.04.2016
comment
Это вообще компилируется для вас if let nextPart = SKReferenceNode(fileNamed: "Scene2_city2") ? Я думаю, вам не нужна дополнительная привязка...   -  person Whirlwind    schedule 04.04.2016
comment
Да, компилируется. Необязательный там не нужен, но я поместил его в необязательный, чтобы проверить, правильно ли он инициализирован.   -  person jendan    schedule 04.04.2016


Ответы (4)


Я нашел обходной путь, оказалось, что при создании SKReferenceNode методом URL проблем нет. Например:

let path = NSBundle.mainBundle().pathForResource("SpaceShip", ofType: "sks")
let spaceShip = SKReferenceNode (URL: NSURL (fileURLWithPath: path!))
addChild(spaceShip)

Я немного покопался, и он появляется в 7.3.1 по сравнению с 7.2.1 при создании SKReferenceNode с использованием fileNamed теперь возвращает необязательное значение. При разворачивании вы получаете SKScene, который, конечно же, выдаст ошибки, если вы попытаетесь добавить его как дочерний элемент в существующую сцену.

Добавлен быстрый тестовый проект 7.3 https://github.com/cocojoe/SKReferenceNodeIssue/tree/workaround

Обратите внимание, что вы сослались на мой пост на форуме Apple. Я заполнил отчет об ошибке около месяца назад, судя по прошлому опыту, на его рассмотрение может уйти некоторое время.

person cocojoe    schedule 01.05.2016

Вы проверили, находится ли узел в иерархии сцены. Эта ошибка связана с миром физики и не имеет ничего общего с тем, что узел уже добавлен в сцену.

Лично я не мог воспроизвести то, что вы говорите, используя SKReferenceNode, но это, вероятно, потому, что я не полностью осведомлен о вашей текущей настройке.

Эта ошибка может произойти, если два узла указывают на один и тот же экземпляр SKPhysicsBody, например:

override func didMoveToView(view: SKView) {

        let sprite = SKSpriteNode(color: .purpleColor(), size: CGSize(width: 20, height: 20))
        let sprite2 = SKSpriteNode(color: .purpleColor(), size: CGSize(width: 20, height: 20))

        sprite.position =  CGPoint(x:frame.midX, y:frame.midY)
        sprite2.position = CGPoint(x:frame.midX, y:frame.midY + 100)

        let sharedPhysicsBody = SKPhysicsBody(rectangleOfSize: CGSize(width: -10, height: -10))

        sprite.physicsBody = sharedPhysicsBody
        sprite2.physicsBody = sharedPhysicsBody

        addChild(sprite)
        addChild(sprite2)
    }

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

person Whirlwind    schedule 03.04.2016
comment
Спасибо за ответ. См. мой простой проект. - person jendan; 04.04.2016
comment
@jendan У меня этот проект не падает. - person Whirlwind; 04.04.2016
comment
SKReferenceNode добавляется по крану. Вместо серой области справа должна появиться зеленоватая. Если у вас не происходит сбой при нажатии, какие версии Xcode вы используете? Я нашел эту ветку. - person jendan; 04.04.2016
comment
@jendan Да, это именно то, что я делаю, и это происходит, и это не падает. Я использую Xcode 7.1.1. - person Whirlwind; 04.04.2016
comment
Итак, кажется, я постукиваю каким-то нехорошим способом. Или я использую плохой Xcode. - person jendan; 04.04.2016
comment
Не могли бы вы обновить до последней версии Xcode, чтобы подтвердить проблему. Мне кажется странным, что я единственный, кто использует последнюю версию Xcode с SKReferenceNode. - person jendan; 29.04.2016

У меня такая же проблема. Если я использую SKReferenceNode(fileNamed:) для создания нового спрайта из спрайта, существующего в файле scene.sks, я получаю сообщение об ошибке

«Не могу добавить тело, оно уже существует в мире»

Похоже, это связано с физикой и происходит, когда объект добавляется на сцену с помощью addChild. Ошибка исчезнет, ​​если вы установите для физического тела значение nil. Что-то типа:

let newBox = SKReferenceNode(fileNamed: "Box")
newBox?.physicsBody = nil
newBox?.position = location
addChild(newBox!)

Что интересно, ошибка появляется, даже если для параметра физики установлено значение none. Приведенное выше решение работает в этом случае, но вы теряете свое физическое тело.

Мне показалось, что для меня сработало создание объекта для использования в качестве исходного объекта и использование skNode.copy() для создания его копии.

person Mitchell Hudson    schedule 01.05.2016

Я нашел другой обходной путь, который не заставляет вас устанавливать для physicsBody значение nil.

В моем случае я заменил SKReferenceNode на SKScene.

Сначала я убедился, что в моей сцене .sks все SKSpriteNodes являются дочерними элементами одного основного узла. Это не обязательно должна быть прямая ссылка, вы все равно можете уважать иерархии вашей сцены, но важно, чтобы в конце «дерева иерархии» они были связаны с одним узлом, который в моем случае является фоном, но это также может быть пустой узел.

введите здесь описание изображения

В моем файле GameScene я написал следующий код:

class GameScene: SKScene {
    var mainNode: SKNode? = nil
    override func didMove(to view: SKView) {
        var mySksScene = SKScene(fileNamed: "Caribbeans")
        mainNode = upperBackground?.childNode(withName: "backgroundCaribbean")
        mainNode?.removeFromParent()
        mySksScene = nil
        addChild(mainNode)
    }
}

Сначала я объявил необязательную переменную SKNode. Затем внутри didMove(:to:) я загрузил свой файл .sks в дополнительную переменную SKScene(). Затем я устанавливаю SKNode в качестве основного узла, узла, который является родителем всех остальных узлов (в моем случае: backgroundCaribbean). Затем я удалил свой mainNode из его родительской сцены, ТОГДА обнулил переменную, которая раньше содержала сцену .sks, и только ТОГДА я добавил свой mainNode в качестве дочернего элемента моей GameScene.

person gionti    schedule 12.01.2017