Is the SpriteKit broken in iOS13.3?

Hello there


I began coding for iOS after a few year and, though I like how it works in Xcode, I can't help but getting suspicious at how something doesn't seem to work properly, for exemple, in this snippet, the tiles will go were I expect them to, but won't fade away by a half.:


                addChild(shape)
                let placeIt = SKAction.group(
                    [
                    SKAction.fadeAlpha(by: 0.5, duration: 2),
                    SKAction.move(to: CGPoint(x: CGFloat(x) * (SIZE + SPACE) + dX, y: CGFloat(y) * (SIZE + SPACE) + dY), duration: 2)])
                placeIt.timingMode = SKActionTimingMode.easeInEaseOut
               
                NSLog("moving %@", shape.name!)
                shape.run(placeIt, withKey: "placeIt \(shape.name!)")
                NSLog("%@ moved", shape.name!)

Even stranger, I invoke a function just after this loops which targets 2 specific shapes in order to fade them back in, then rotate them. Of course, they've not been faded, but they won't rotate and even the NSLog statements won't be anywhere to see.


Later in the game it works if I rotate once (on touchEnd), but If I want to also rotate the surrounding, it does stop to rotate aven once by further attempts.


These shapes use Physics. I know the bitmasks are right but there never seem to have a contact even though it should happen. Show physics is relevant: there's a border when expected and rotating the shapes should trigger a contact which used to happen, but not anymore. I also never got the scaling to get properly.


Seriously, I don't understand what is going here 😟

Should the SKActions only be run in a specific context?


Please help!

Mirx

Replies

And you're getting no "SKPhysicsContact detected" messages? I'm afraid I'm about at the limit of being able to remotely debug. I'd suggest just making a simple test scene, two squares, set the physics bodies and category/contact bitmasks, and do the rotation. I do this and do get contact messages:


class GameScene: SKScene, SKPhysicsContactDelegate {
  let squareSize = CGSize(width: 100, height: 100)

  func makeSquare(color: UIColor, category: UInt32) -> SKSpriteNode {
    let square = SKSpriteNode(color: color, size: squareSize)
    let body = SKPhysicsBody(rectangleOf: squareSize)
    square.physicsBody = body
    square.zPosition = 1
    body.categoryBitMask = category
    body.contactTestBitMask = category ^ 0b11
    addChild(square)
    return square
  }

  func didBegin(_ contact: SKPhysicsContact) {
    guard let node1 = contact.bodyA.node else { return }
    guard let node2 = contact.bodyB.node else { return }
    print("contact \(node1.name!) and \(node2.name!)")
  }

  func rotate(_ sprite: SKSpriteNode) {
    sprite.run(.rotate(byAngle: .pi, duration: 1))
  }

  override func didMove(to view: SKView) {
    let square1 = makeSquare(color: .red, category: 0b01)
    square1.position = .zero
    square1.name = "square1"
    let square2 = makeSquare(color: .blue, category: 0b10)
    square2.position = CGPoint(x: square1.position.x + 1.05 * squareSize.width, y: square1.position.y)
    square2.name = "square2"
    run(.wait(forDuration: 3)) { self.rotate(square1) }
  }

  override func update(_ currentTime: TimeInterval) {
    // Called before each frame is rendered
  }

  override init(size: CGSize) {
    super.init(size: size)
    physicsWorld.gravity = .zero
    physicsWorld.contactDelegate = self
    anchorPoint = CGPoint(x: 0.5, y: 0.5)
  }

  required init(coder aDecoder: NSCoder) {
    fatalError()
  }
}


I also checked that at least one (but not both) bodies must have isDynamic true. One thing I hadn't thought about is that the squares will push each other during the rotation, which is kind of suggesting that you may not want the physics engine involved at all. That is, I'd probably use just a discrete grid representation and have a rotating square check the neighboring cells for their status in order to capture them.

Once again thanks for the time you devoted helping me.

I went in the addShape func and made all the tiles non-dynamic by default, then when naming the players tiles, I made these active.

It works.

The physics engin might get too busy if all of the tiles are active...