I'm using Swift 3.0, SpriteKit, and Xcode 8.2.1, testing on an iPhone 6s running iOS 10.2.
The problem is simple... on the surface. Basically my TouchesMoved() updates at a very inconsistent rate and is destroying a fundamental part of the UI in my game. Sometimes it works perfectly, a minute later it's updating at half of the rate that it should.
I've isolated the problem. Simply having an SKSpriteNode in the scene that has a physics body causes the problem... Here's my GameScene code:
import SpriteKit
import Darwin
import Foundation
var spaceShip = SKTexture(imageNamed: "Spaceship")
class GameScene: SKScene{
var square = SKSpriteNode(color: UIColor.black, size: CGSize(width: 100,height: 100))
override func didMove(to view: SKView) {
backgroundColor = SKColor.white
self.addChild(square)
//This is what causes the problem:
var circleNode = SKSpriteNode(texture: spaceShip, color: UIColor.clear, size: CGSize(width: 100, height: 100))
circleNode.physicsBody = SKPhysicsBody(circleOfRadius: circleNode.size.width/2)
self.addChild(circleNode)
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches{
var positionInScreen = touch.location(in: self)
square.position = positionInScreen
}
}
}
The problem doesn't always happen so sometimes you have to restart the app like 5 times, but eventually you will see that dragging the square around is very laggy if you do it slowly. Also I understand it's subtle at times, but when scaled up this is a huge problem.
My main question: Why does me having an SKSpriteNode with a physics body cause TouchesMoved() to lag and nothing else to lag, and how can I prevent this?
Please for the love of code and my sanity save me from this abyss!!!
It looks like this is caused by the OS being too busy to respond to touch events. I found two ways to reproduce this:
Enable Airplane Mode on the device, then disable it. For the ~5-10 seconds after disabling Airplane Mode, the touch events lag.
Open another project in Xcode and select "Wait for the application to launch" in the scheme editor, then press Build and Run to install the app to the device without running it. While the app is installing, the touch events lag.
It doesn't seem like there is a fix for this, but here's a workaround. Using the position and time at the previous update, predict the position and time at the next update and animate the sprite to that position. It's not perfect, but it works pretty well. Note that it breaks if the user has multiple fingers on the screen.