

<目的>  
ViewControllerでGameSceneをpresentで表示させていて、そのGameSceneでのスコアを次のViewで表示させるためにGameSceneから元のViewControllerのSegueを使い次のViewを表示させたい。  
<問題点>  
ビルドに関しても問題なく作動するのだが、GameSceneでのGameOver時にボタンを生成し、そのボタンでSegueによる遷移を行おうとしているが、遷移しない。

ViewControllerB.swift

[code]

    class ViewControllerB: UIViewController {
        override func viewDidAppear(_ animated: Bool) {
    
            super.viewDidLoad()
            let scene = GameScene()
            let view = self.view as! SKView
    
            view.showsFPS = true
            view.showsNodeCount = true
    
            scene.size = view.frame.size
    
            view.presentScene(scene)
        }   
    }
    
[/code]

GameScene.swift

[code]

    class GameScene : SKScene, SKPhysicsContactDelegate {
    
        var bowl:SKSpriteNode?
    
        var timer:Timer?
    
        var lowestShape:SKShapeNode?
    
        var score = 0
        var scoreLabel: SKLabelNode?
        var scoreList = [100,200,300,500,800,1000,1500]
        var viewController: UIViewController?
    
        override func didMove(to view: SKView){
    
            self.physicsWorld.gravity = CGVector(dx: 0.0, dy: -2.0)
            self.physicsWorld.contactDelegate = self
    
            let background =  SKSpriteNode(imageNamed: "background")
            background.position = CGPoint(x: self.size.width*0.5, y: self.size.height*0.5)
            background.size = self.size
            self.addChild(background)
    
            let lowestShape = SKShapeNode(rectOf: CGSize(width: self.size.width*3, height: 10))
            lowestShape.position = CGPoint(x: self.size.width*0.5, y: -10)
    
            let physicsBody = SKPhysicsBody(rectangleOf: lowestShape.frame.size)
            physicsBody.isDynamic = false
            physicsBody.contactTestBitMask = 0x1 << 1
            lowestShape.physicsBody = physicsBody
    
            self.addChild(lowestShape)
            self.lowestShape = lowestShape
    
            let bowlTexture = SKTexture(imageNamed: "bowl")
            let bowl = SKSpriteNode(texture: bowlTexture)
            bowl.position = CGPoint(x: self.size.width*0.5, y: 100)
            bowl.size = CGSize(width: bowlTexture.size().width*0.5, height: bowlTexture.size().height*0.5)
            bowl.physicsBody = SKPhysicsBody(texture: bowlTexture, size: bowl.size)
            bowl.physicsBody?.isDynamic = false
            self.bowl = bowl
            self.addChild(bowl)
    
            var scoreLabel = SKLabelNode(fontNamed: "Helvetica")
            scoreLabel.position = CGPoint(x: self.size.width*0.92, y: self.size.height*0.78)
            scoreLabel.text = "¥0"
            scoreLabel.fontSize = 32
            scoreLabel.horizontalAlignmentMode = SKLabelHorizontalAlignmentMode.right
            scoreLabel.fontColor = UIColor.green
            self.addChild(scoreLabel)
            self.scoreLabel = scoreLabel
    
            self.fallNagoyaSpecialty()
    
            self.timer = Timer.scheduledTimer(timeInterval: 3, target: self, selector: #selector(fallNagoyaSpecialty), userInfo: nil, repeats: true)
        }
    
        @objc func fallNagoyaSpecialty() {
            let index = Int(arc4random_uniform(7))
            let texture = SKTexture(imageNamed: "\(index)")
            let sprite = SKSpriteNode(texture: texture)
            sprite.position = CGPoint(x: self.size.width*0.5, y: self.size.height)
            sprite.size = CGSize(width: texture.size().width*0.5, height: texture.size().height*0.5)
            sprite.physicsBody = SKPhysicsBody(texture: texture, size: sprite.size)
            sprite.physicsBody?.contactTestBitMask = 0x1 << 1
    
            self.addChild(sprite)
    
            self.score += self.scoreList[index]
            self.scoreLabel?.text = "¥\(self.score)"
        }
    
        override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
            if let touch = touches.first {
                let location = touch.location(in: self)
                let action = SKAction.move(to: CGPoint(x: location.x, y:100), duration: 0.2)
                self.bowl?.run(action)
            }
        }
    
        override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
            if let touch = touches.first {
                let location = touch.location(in: self)
                let action = SKAction.move(to: CGPoint(x: location.x , y:100), duration: 0.2)
                self.bowl?.run(action)
            }
        }
    
        func didBegin(_ contact: SKPhysicsContact) {
            if contact.bodyA.node == self.lowestShape || contact.bodyB.node == self.lowestShape{
                let sprite = SKSpriteNode(imageNamed: "gameover")
                sprite.position = CGPoint(x: self.size.width*0.5, y: self.size.height*0.5)
                self.addChild(sprite)
    
                self.isPaused = true
                self.timer?.invalidate()
                haveScore()
                let myButton = UIButton()
                myButton.frame = CGRect(x: 0, y: 0, width: 200, height: 40)
                myButton.backgroundColor = UIColor.red
                myButton.setTitle("次へ", for: UIControl.State.normal)
                myButton.setTitleColor(UIColor.white, for: UIControl.State.normal)
                myButton.layer.cornerRadius = 20.0
                myButton.layer.position = CGPoint(x: self.view!.frame.width/2, y: 200.0)
                myButton.addTarget(self , action: #selector(self.next(sender:)), for: .touchUpInside)
                self.view!.addSubview(myButton)     
            }
        }
        func haveScore() {
            let appDelegate = UIApplication.shared.delegate as! AppDelegate
            appDelegate.message = score
        }
    
        @objc func next(sender: UIButton){
    
            self.viewController?.performSegue(withIdentifier: "toFinish", sender: nil)
        }
    
    }
    
[/code]


CC BY-SA 4.0
2019-03-11T11:44:40.730
53365
2021-03-03T04:05:00.890
2019-03-13T06:55:42.123
76
32500
question
swift4 spritekit
Xcode(Swift) でSKSceneでSegueを使った画面遷移について


「問題点」が生じる原因は、`GameScene`クラスのプロパティ`viewController`に対して、どこにも`UIViewController`クラスのインスタンスの参照が代入されていないことにあります。`viewController`の型はOptional型なので、デフォルト値は`nil`になります。  
メソッド`next(sender: UIButton)`の実装内

[code]

    self.viewController?.performSegue(withIdentifier: "toFinish", sender: nil)
    
[/code]

この行の中の`viewController`の値は、上に理由で`nil`なので、 **Optional Chaining**
の文法により、この行の実行が中断されます。すなわち画面遷移は起きません。  
適切なタイミング（`ViewControllerB`において、`GameScene`インスタンスを生成した直後など）で、プロパティ`viewController`に代入をしてみてください。

もうひとつ気になるのは、クラス`GameScene`のプロパティ`viewController`の型が`UIViewController?`になっていることです。これはサブクラスの`ViewControllerB?`としなければ、セグエ`toFinish`を認識してもらえないのではないでしょうか？


CC BY-SA 4.0
2019-03-12T14:37:55.653
53391
2019-03-15T09:34:15.300
2019-03-15T09:34:15.300
18540
18540
53365
answer