TouchesMoved () retrasa muy inconsistentemente cuando hay un SkSpriteNode con un cuerpo de física

Estoy usando Swift 3.0, SpriteKit y Xcode 8.2.1, probando en un iPhone 6s con iOS 10.2.

El problema es simple … en la superficie. Básicamente, mi TouchesMoved () se actualiza a una velocidad muy incoherente y está destruyendo una parte fundamental de la interfaz de usuario en mi juego. A veces funciona perfectamente, un minuto después se actualiza a la mitad de la velocidad que debería.

He aislado el problema. Simplemente tener un SKSpriteNode en la escena que tiene un cuerpo físico provoca el problema … Aquí está mi código GameScene:

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 } } } 

El problema no siempre ocurre así que a veces tienes que reiniciar la aplicación como 5 veces, pero eventualmente verás que arrastrando el cuadrado es muy flojo si lo haces lentamente. También entiendo que es sutil a veces, pero cuando se amplía esto es un gran problema.

Mi pregunta principal: ¿Por qué tener un SKSpriteNode con un cuerpo de física hace que TouchesMoved () se rezague y no tenga nada más que rezagarse y cómo puedo prevenir esto?

¡Por favor, por el amor del código y mi cordura, sálvame de este abismo!

Parece que esto se debe a que el SO está demasiado ocupado para responder a los events táctiles. Encontré dos forms de reproducir esto:

  • Habilite el Modo Avión en el dispositivo y luego desactívelo. Durante los ~ 5-10 segundos después de deshabilitar el modo avión, el retraso de los events táctiles.

  • Abra otro proyecto en Xcode y select "Esperar a que se inicie la aplicación" en el editor de esquema, luego presione Crear y ejecutar para instalar la aplicación en el dispositivo sin ejecutarlo. Mientras la aplicación se está instalando, el evento táctil se retrasa.


No parece haber una solución para esto, pero aquí hay una solución. Usando la position y la hora en la actualización anterior , pnetworkingice la position y la hora en la próxima actualización y anima al sprite a esa position. No es perfecto, pero funciona bastante bien. Tenga en count que se rompe si el usuario tiene varios dedos en la pantalla.

 class GameScene: SKScene{ var lastTouchTime = Date.timeIntervalSinceReferenceDate var lastTouchPosition = CGPoint.zero var square = SKSpriteNode(color: UIColor.black, size: CGSize(width: 100,height: 100)) override func didMove(to view: SKView) { backgroundColor = SKColor.white self.addChild(square) } override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { lastTouchTime = Date().timeIntervalSinceReferenceDate lastTouchPosition = touches.first?.location(in: self) ?? .zero } override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) { let currentTime = Date().timeIntervalSinceReferenceDate let timeDelta = currentTime - lastTouchTime for touch in touches{ square.removeAction(forKey: "TouchPnetworkingiction") let oldPosition = lastTouchPosition let positionInScreen = touch.location(in: self) lastTouchPosition = positionInScreen square.position = positionInScreen //Calculate the difference between the sprite's last position and its current position, //and use it to pnetworkingict the sprite's position next frame. let positionDelta = CGPoint(x: positionInScreen.x - oldPosition.x, y: positionInScreen.y - oldPosition.y) let pnetworkingictedPosition = CGPoint(x: positionInScreen.x + positionDelta.x, y: positionInScreen.y + positionDelta.y) //Multiply the timeDelta by 1.5. This helps to smooth out the lag, //but making this number too high cause the animation to be ineffective. square.run(SKAction.move(to: pnetworkingictedPosition, duration: timeDelta * 1.5), withKey: "TouchPnetworkingiction") } lastTouchTime = Date().timeIntervalSinceReferenceDate } } 

Tuve problemas similares al arrastrar una image usando el método touchesMoved . Antes solo estaba actualizando la position del nodo en function de dónde estaba el toque, lo que hacía que el movimiento se viera lag. Lo hice mejor así:

 //in touchesMoved let touchedPoint = touches.first! let pointToMove = touchedPoint.location(in: self) let moveAction = SKAction.move(to: pointToMove, duration: 0.01)// play with the duration to get a smooth movement node.run(moveAction) 

Espero que esto ayude.