PhysicsBody: не удалось создать физическое тело - PullRequest
0 голосов
/ 29 января 2020

У меня есть целая рабочая игра, которая была в App Store, но с iOS 13 она просто не работает. Я установил игру на свое устройство через XCode, и я получаю много ошибок, говорящих:

PhysicsBody: Не удалось создать физическое тело.

Я создавал свой SKSprite Узлы, подобные этому:

 let bird = SKSpriteNode(texture: SKTextureAtlas(named:"player").textureNamed("bird0001"))
 bird.physicsBody = SKPhysicsBody(texture: bird.texture!,
                                         size: bird.size)

Основываясь на некоторых исследованиях, это, возможно, постоянная ошибка с iOS и Xcode. Может, кто-нибудь подтвердит, если это так, поскольку это похоже на серьезную проблему для Игр в магазине приложений, которые создают свои SKSpriteNodes, используя текстуры?

Есть ли какое-то исправление, где необходимы текстуры?

Ответы [ 2 ]

1 голос
/ 01 февраля 2020

ОК, вот тест различных подходов, позволяющих избежать этой ошибки, начиная с iOS 13.3 (редактирование также теперь пробовалось на 13.3.1) и Xcode версии 11.3. Полный источник теста по этой ссылке:

https://github.com/bg2b/bugtest

Соответствующий код:

  func addShip(_ texture: SKTexture, how: String) {
    let sprite = SKSpriteNode(texture: texture)
    sprite.position = CGPoint(x: x, y: 0)
    sprite.zRotation = .pi / 4
    x += 100
    sprite.physicsBody = SKPhysicsBody(texture: texture, size: sprite.size)
    if sprite.physicsBody == nil {
      print("\(how) failed")
    } else {
      print("\(how) worked")
    }
    addChild(sprite)
  }

  override func didMove(to view: SKView) {
    // The atlas version of a texture
    addShip(SKTexture(imageNamed: "ship_blue"), how: "simple atlas reference")
    // From an atlas, but call size() to force loading
    let texture = SKTexture(imageNamed: "ship_blue")
    _ = texture.size()
    addShip(texture, how: "atlas force load")
    // Reconstruct via CGImage (size would be wrong because of 2x)
    let cgTexture = SKTexture(cgImage: texture.cgImage())
    addShip(cgTexture, how: "reconstruct via cgImage")
    // Re-render using view
    let renderedTexture = view.texture(from: SKSpriteNode(texture: texture))!
    addShip(renderedTexture, how: "re-render using view")
    // Non-atlas texture
    addShip(SKTexture(imageNamed: "nonatlas_ship_blue"), how: "not in atlas")
  }

Резюме:

  1. Простая ссылка на текстуру из атласа и создание физического тела может дать сбой
  2. Принудительная загрузка текстуры путем вызова size() до того, как произойдет сбой тела
  3. Попытка создать новую текстуру пройти через cgImage() не удалось (само изображение повреждено, вероятно, связано с той же ошибкой)
  4. Рендеринг в текстуру с использованием вида и затем создание физического тела из этой новой текстуры работает
  5. Создание физического тела из неатлантической копии текстуры работает

Вывод на консоль из тестовой программы, показывающий, что работает, а что нет:

2020-02-01 06:23:51.872975-0500 bugtest[14399:9898087] PhysicsBody: Could not create physics body.
simple atlas reference failed
2020-02-01 06:23:51.886387-0500 bugtest[14399:9898087] PhysicsBody: Could not create physics body.
atlas force load failed
2020-02-01 06:23:51.913927-0500 bugtest[14399:9898087] PhysicsBody: Could not create physics body.
reconstruct via cgImage failed
re-render using view worked
not in atlas worked

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

Screen shot of different attempts

0 голосов
/ 31 января 2020

Проблема

SKTextureAtlas не сразу загружает текстуры в память. о нет!

Не элегантное решение

Вызов метода размера текстуры перед созданием физического тела заставит ее загрузить ее в память.

let atlasName = "player"
let textureName = "bird0001"

let atlas = SKTextureAtlas(named: atlasName)
let texture = atlas.textureNamed(textureName)

texture.size() //Force load into memory

let node = SKSpriteNode(texture: texture)
node.physicsBody = SKPhysicsBody(texture: texture, size: node.size)

Некоторые другие заметки

A несколько лет go, я обычно загружал весь свой атлас в память, используя метод atlas.preload { }, но этот метод имел ошибку утечки памяти. Я нашел альтернативный способ принудительной загрузки атласа sktexture с использованием texture.size()

...