узлы Skscene не отображаются при перезапуске приложения - PullRequest
0 голосов
/ 17 ноября 2018

Я использую Xcode 9.4 для создания очень простой игры.Когда пользователь запускает приложение, появляется сеть, которую он / она может перемещать, чтобы поймать мух, которые летят сверху вниз по экрану в соответствии с путем, заданным в запросе http get.

Приложение работаетотлично в симуляторе.

Я загрузил приложение в магазин приложений для тестирования.Когда пользователи загружают приложение через TestFlight, оно отлично работает при первом использовании.Однако, если они закроют приложение и перезапустят его, мухи не появятся.В противном случае сцена отображается так, как ожидалось.Если они затем удаляют приложение, переустанавливают его и запускают, мухи появляются снова, как и ожидалось.Но опять же, если они закрывают приложение и перезапускают его, мух нет.

Я пробрался в Интернет и не нашел никаких указаний по этому вопросу.Есть предложения?

import SpriteKit

func +(left: CGPoint, right: CGPoint) -> CGPoint {
    return CGPoint(x: left.x + right.x, y: left.y + right.y)
}

func -(left: CGPoint, right: CGPoint) -> CGPoint {
    return CGPoint(x: left.x - right.x, y: left.y - right.y)
}

func *(point: CGPoint, scalar: CGFloat) -> CGPoint {
    return CGPoint(x: point.x * scalar, y: point.y * scalar)
}

func /(point: CGPoint, scalar: CGFloat) -> CGPoint {
    return CGPoint(x: point.x / scalar, y: point.y / scalar)
}

#if !(arch(x86_64) || arch(arm64))
func sqrt(a: CGFloat) -> CGFloat {
    return CGFloat(sqrtf(Float(a)))
}
#endif

extension CGPoint {
    func length() -> CGFloat {
        return sqrt(x*x + y*y)
    }

    func normalized() -> CGPoint {
        return self / length()
    }
}

class GameScene: SKScene {

    struct PhysicsCategory {
        static let none      : UInt32 = 0
        static let all       : UInt32 = UInt32.max
        static let fly   : UInt32 = 0b1
        static let net: UInt32 = 0b10
    }

    let net = SKSpriteNode(imageNamed: "net")
    var fliesAdded = 0
    var fliesCaught = 0
    let maxFlies = 10
    var level = CGFloat(1.0)
    var gameKey: String?
    var lives = 3
    var levelCounter = 0

    override func didMove(to view: SKView) {



        backgroundColor = SKColor.white

        // Set up the properties of the net
        net.scale(to: CGSize.init(width: net.size.width/10, height: net.size.height/10))
        net.physicsBody = SKPhysicsBody(rectangleOf: net.size)
        net.physicsBody?.isDynamic = false
        net.physicsBody?.categoryBitMask = PhysicsCategory.net
        net.physicsBody?.contactTestBitMask = PhysicsCategory.fly
        net.physicsBody?.collisionBitMask = PhysicsCategory.none
        net.position = CGPoint(x: size.width * 0.5, y: size.height * 0.1)
        // 4
        addChild(net)

        physicsWorld.gravity = .zero
        physicsWorld.contactDelegate = self

        self.isPaused = false
        run(SKAction.run(addFly))

        let backgroundMusic = SKAudioNode(fileNamed: "background-music-aac.caf")
        backgroundMusic.autoplayLooped = true
        addChild(backgroundMusic)

        // Add a label for the score
        let scoreLabel = SKLabelNode()
        scoreLabel.fontColor = UIColor.black
        scoreLabel.fontSize = 65
        scoreLabel.name = "scoreLabel"
        scoreLabel.position = CGPoint(x: size.width/2, y: size.height/2);
        scoreLabel.text = "0";
        self.addChild(scoreLabel)

        // Add a label for the level
        let levelLabel = SKLabelNode()
        levelLabel.fontColor = UIColor.black
        levelLabel.fontSize = 32.5
        levelLabel.name = "levelLabel"
        levelLabel.text = "level \(Int(level))"
        levelLabel.horizontalAlignmentMode = .left
        levelLabel.verticalAlignmentMode = .top
        levelLabel.position = CGPoint(x: 0, y: self.size.height)
        self.addChild(levelLabel)

        // Add a label for the lives
        let livesLabel = SKLabelNode()
        livesLabel.fontColor = UIColor.black
        livesLabel.fontSize = 32.5
        livesLabel.name = "livesLabel"
        livesLabel.text = "3/3 lives"
        livesLabel.horizontalAlignmentMode = .right
        livesLabel.verticalAlignmentMode = .top
        livesLabel.position = CGPoint(x:self.size.width, y:self.size.height)
        self.addChild(livesLabel)

        // Get the starting level
        let urlComp = NSURLComponents(string: "---")!
        let params = [URLQueryItem(name: "UserName", value: (UIApplication.shared.delegate as! AppDelegate).userName)]
        urlComp.queryItems = params
        var request = URLRequest(url: urlComp.url!)
        request.httpMethod = "GET"


        let task = URLSession.shared.dataTask(with: request) { data, response, error in
            do {
                let result = try JSONDecoder().decode(LevelResponseObject.self, from: data!)
                let userHighestLevel = Int(result.level) ?? 1
                if userHighestLevel > 5 {
                    self.level = CGFloat(userHighestLevel) - 5.0
                }
                else {
                    self.level = CGFloat(userHighestLevel)
                }
                if let levelLabel = self.childNode(withName: "levelLabel") as? SKLabelNode {
                    levelLabel.text = "level \(Int(self.level))"
                }
            } catch {
                print(error)
            }

        }

        task.resume()

    }



    func touchDown(atPoint pos : CGPoint) {
        //net.position = CGPoint(x: pos.x, y: size.height * 0.1)
    }

    func touchMoved(toPoint pos : CGPoint) {

        //net.position = CGPoint(x: pos.x, y: size.height * 0.1)

    }

    func touchUp(atPoint pos : CGPoint) {

    }

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {

    }

    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
        for touch: AnyObject in touches {
            let touchLocation = touch.location(in: self)

            net.position = CGPoint(x: touchLocation.x, y: size.height * 0.1)

        }
    }

    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {

    }

    override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {

    }

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

    // MARK: Private functions

    func addFly() {


            let origin = (UIApplication.shared.delegate as! AppDelegate).dataOrigin

            let urlComp = NSURLComponents(string: "---")!
            let params = [URLQueryItem(name: "Origin", value: origin)]
            urlComp.queryItems = params
            var request = URLRequest(url: urlComp.url!)
            request.httpMethod = "GET"


            let task = URLSession.shared.dataTask(with: request) { data, response, error in
                do {
                    let result = try JSONDecoder().decode(ResponseObject.self, from: data!)
                    let rows = result.items[0].Data.components(separatedBy: ";")
                    let firstPoint = Double(rows[0]) ?? 0.0
                    //let xCoords = rows.map{ CGFloat(NSString(string: $0).doubleValue - firstPoint)*self.size.width/157.4*2 + self.size.width/2 }
                    let xCoords = rows.map{ self.size.width/(1+exp(-(CGFloat(NSString(string: $0).doubleValue - firstPoint)/10)))} // increasing the denominator in the exponential will make the relationship more linear, decreasing it will exaggerate moves near to the center
                    self.gameKey = result.items[0].Key

                    self.fliesAdded += 1

                    // Create sprite
                    print("New Fly")
                    print("Level \(self.level)")
                    let fly = SKSpriteNode(imageNamed: "fly")
                    fly.scale(to: CGSize.init(width: self.size.width/20, height: fly.size.height/fly.size.width*self.size.width/20))

                    fly.physicsBody = SKPhysicsBody(rectangleOf: fly.size)
                    fly.physicsBody?.isDynamic = true
                    fly.physicsBody?.categoryBitMask = PhysicsCategory.fly
                    fly.physicsBody?.contactTestBitMask = PhysicsCategory.none
                    fly.physicsBody?.collisionBitMask = PhysicsCategory.none

                    // Position the fly slightly off-screen along the top edge,
                    // in the middle of the x axis
                    fly.position = CGPoint(x: self.size.width/2, y: self.size.height + fly.size.height/2)

                    // Add the fly to the scene
                    self.addChild(fly)

                    var flightSequence: [SKAction] = []

                    var currentY = fly.position.y
                    var currentX = fly.position.x

                    let yDistanceToTravel = currentY - (self.net.position.y + self.net.size.height/2)
                    let yIncrement = yDistanceToTravel / CGFloat(xCoords.count - 1)

                    var duration = CGFloat(8.28)/CGFloat(xCoords.count - 1)
                    duration = duration/(1.0 + self.level/10)

                    // Create a sequence of moves for the fly
                    for targetX in xCoords {
                        // Set the parameters for the move

                        let targetY = currentY - yIncrement
                        let flyTurn = SKAction.rotate(toAngle: -atan((targetX-currentX)/(targetY-currentY)), duration: 0.0, shortestUnitArc: true)
                        flightSequence.append(flyTurn)
                        let flyMovement = SKAction.move(to: CGPoint(x: targetX, y: targetY), duration: TimeInterval(duration))
                        flightSequence.append(flyMovement)
                        currentY = targetY
                        currentX = targetX
                    }



                    // After the fly passes the net send it vertically down
                    let flyTurn = SKAction.rotate(toAngle: 0.0, duration: 0.0, shortestUnitArc: true)
                    flightSequence.append(flyTurn)
                    let flyMovement = SKAction.move(to: CGPoint(x: currentX, y: -fly.size.height/2), duration: TimeInterval(duration))
                    flightSequence.append(flyMovement)

                    // Remove the fly after it passes the net and end the game
                    let flightOver = SKAction.run() { [weak self] in
                        guard let `self` = self else { return }
                        if (self.gameKey != nil){
                            self.recordDistance(fly: fly, net: self.net, gameKey: self.gameKey!, level: self.level, win: false)
                        }
                        fly.removeFromParent()
                        self.gameOver()
                    }
                    flightSequence.append(flightOver)

                    fly.run(SKAction.sequence(flightSequence))

                } catch {
                    print(error)
                }


            }

            task.resume()


    }

    func gameOver() {

        if (lives == 1) {
            let reveal = SKTransition.flipHorizontal(withDuration: 0.5)
            let scoreScene = ScoreScene(size: self.size, score: fliesCaught, level: Int(level))
            view?.presentScene(scoreScene, transition: reveal)
        }
        else {
            lives = lives - 1
            if let livesLabel = self.childNode(withName: "livesLabel") as? SKLabelNode {
                livesLabel.text = "\(lives)/3 lives"
            }
            addFly()
        }
    }


    func flyCaught(fly: SKSpriteNode, net: SKSpriteNode, gameKey: String?) {

        if (gameKey != nil) {
            recordDistance(fly: fly, net: net, gameKey: gameKey!, level: self.level, win: true)
        }

        fly.removeFromParent()

        fliesCaught += 1
        //print("Score = \(fliesCaught)")
        if let scoreLabel = self.childNode(withName: "scoreLabel") as? SKLabelNode {
            scoreLabel.text = "\(fliesCaught)"
        }
        if levelCounter == 4 {
            levelCounter = 0
            level = level + 1.0
            if let levelLabel = self.childNode(withName: "levelLabel") as? SKLabelNode {
                levelLabel.text = "level \(Int(level))"
            }
        }
        else {
            levelCounter = levelCounter + 1
        }
        addFly()
    }

    func recordDistance(fly: SKSpriteNode, net: SKSpriteNode, gameKey: String, level: CGFloat, win: Bool) {
        let distance = fly.position.x - net.position.x
        //print("Distance to center of net = \(distance)")

        // prepare json data

        let json: [String: Any] = ["UserName": (UIApplication.shared.delegate as! AppDelegate).userName,
                                   "DataKey": gameKey,
                                   "Level": Int(level),
                                   "Win": win,
                                   "DistanceToCenter": distance,
                                   "ScreenWidth": self.size.width]

        let jsonData = try? JSONSerialization.data(withJSONObject: json)

        // create post request
        let url = URL(string: "---")!
        var request = URLRequest(url: url)
        request.httpMethod = "POST"

        // insert json data to the request
        request.httpBody = jsonData

        let task = URLSession.shared.dataTask(with: request) { data, response, error in
            guard let _ = data, error == nil else {                                                 // check for fundamental networking error
                print("error=\(String(describing: error))")
                return
            }

            if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200 {           // check for http errors
                print("statusCode should be 200, but is \(httpStatus.statusCode)")
                print("response = \(String(describing: response))")
            }
        }

        task.resume()

    }

}

extension GameScene: SKPhysicsContactDelegate {
    func didBegin(_ contact: SKPhysicsContact) {
        // 1
        var firstBody: SKPhysicsBody
        var secondBody: SKPhysicsBody
        if contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask {
            firstBody = contact.bodyA
            secondBody = contact.bodyB
        } else {
            firstBody = contact.bodyB
            secondBody = contact.bodyA
        }

        if ((firstBody.categoryBitMask & PhysicsCategory.fly != 0) &&
            (secondBody.categoryBitMask & PhysicsCategory.net != 0)) {
            if let fly = firstBody.node as? SKSpriteNode,
                let net = secondBody.node as? SKSpriteNode {
                //print("Collision with net")
                if fly.position.y > net.position.y + net.size.height/2 {
                    //print("Fly Caught")
                    flyCaught(fly: fly, net: net, gameKey: gameKey)
                }
            }
        }
    }
}

struct ResponseObject: Decodable {
    let items: [RouteItem]
}

struct RouteItem: Decodable {
    let Key: String
    let Origin: String
    let Data: String
}

struct LevelResponseObject: Decodable {
    let level: String
}
...