読者です 読者をやめる 読者になる 読者になる

いものやま。

雑多な知識の寄せ集め

変種オセロのスタート画面を作ってみた。(その6)

ゲーム開発 Swift YWF

昨日はスタート画面からゲーム画面への遷移を作った。

今日は逆に、ゲーム画面からスタート画面への遷移を作成していく。

スタート画面への遷移

昨日と同様に、GameSceneに画面遷移を実装する。

//==============================
// YWF
//------------------------------
// GameScene.swift
//==============================

import SpriteKit

public class GameScene: SKScene, ButtonNodeObserver {
  // 省略

  public init(size: CGSize,
              userName: String, userStatus: PieceNode.Status,
              opponentName: String, opponentPlayer: Player) {
    // 省略

    self.exitButton.addObserver(self)
    
    // 省略
  }  
  
  public func buttonIsSelected(button: ButtonNode) {
    let scene = StartScene(size: self.size)
    let transition = SKTransition.fadeWithDuration(NSTimeInterval(1.0))
    self.view?.presentScene(scene, transition: transition)
  }
  
  // 省略
}

うん、何も言うことないな。

オブザーバの解放

で、やはり昨日と同様に、オブザーバの解放も実装。

//==============================
// YWF
//------------------------------
// BoardNode.swift
//==============================

import SpriteKit

public class BoardNode: SKSpriteNode {
  // 省略

  public func removeAllObservers() {
    self.observers.removeAll()
  }
  
  // 省略
}
//==============================
// YWF
//------------------------------
// ButtonNode.swift
//==============================

import SpriteKit

public class ButtonNode: SKSpriteNode {
  // 省略
  
  public func removeAllObservers() {
    self.observers.removeAll()
  }
  
  // 省略
}

あと、ターンコントローラを止める必要があるので、ターンコントローラを少し修正。

//==============================
// YWF
//------------------------------
// TurnController.swift
//==============================

import Foundation

public class TurnController: BoardNodeObserver, ButtonNodeObserver {
  // 省略
  
  public func stop() {
    self.cancelSelectOperation()
  }
  
  // 省略
}

あとは、これらを呼び出すように、GameSceneを修正。

//==============================
// YWF
//------------------------------
// GameScene.swift
//==============================

import SpriteKit

public class GameScene: SKScene, ButtonNodeObserver {
  // 省略
  
  private var boardNode: BoardNode!
  private var undoButton: ButtonNode!
  private var passButton: ButtonNode!
  private var exitButton: ButtonNode!
  
  public init(size: CGSize,
              userName: String, userStatus: PieceNode.Status,
              opponentName: String, opponentPlayer: Player) {
    // 省略
    // 各ノードへの参照をプロパティに保持するように修正
  }

  // 省略
  
  public override func willMoveFromView(view: SKView) {
    self.turnController.stop()
    self.releaseObservers()
  }
  
  private func releaseObservers() {
    self.boardNode.removeAllObservers()
    self.undoButton.removeAllObservers()
    self.passButton.removeAllObservers()
    self.exitButton.removeAllObservers()
  }
}

これで画面遷移の実装はOK・・・のはずだったんだけど、実際にやってみたら、nilアクセスの実行時例外でアプリがクラッシュ。

原因を調べてみると、初めての人間のアクション選択で、選択がキャンセルされたときにnilが返されてくるのだけれど、これをnilチェックせずにアンボクシングしていたのが原因。
といっても、選択がキャンセルされるわけで、何もしなければこの選択自体が使われることはないんだけど、Swiftがオプショナル型なんていう余計なものを使うようになっているせいで、このバグに繋がってしまった・・・
ホント、このオプショナル型とかいうクソ仕様、どうにかならないものなのか・・・

まぁ、仕方ないので、ちょろっと修正。

//==============================
// YWF
//------------------------------
// Human.swift
//==============================

import Foundation

public class Human: Player, BoardNodeObserver, ButtonNodeObserver {
  // 省略
  
  public func cancelSelect() {
    self.selectedAction = .Pass
    self.notifyInput()
  }
}

ちゃんと修正するならnilチェックを入れてとするのだけど、そもそもこの値が使われないことは分かっているのだから、とりあえずnilだけ返らないようにしている。

動作確認

動作確認すると、次のような感じ。

ちゃんとスタート画面→ゲーム画面、ゲーム画面→スタート画面の遷移が出来ていることが分かると思う。

これだけでもOKなんだけど、ミスタッチなどでゲーム画面からスタート画面に移ってしまうと、元のゲーム画面に戻ることが出来なくて困ってしまう。
なので、スタート画面に戻るときには、確認のダイアログを出したいところ。
ということで、スタート画面に戻る前に確認のダイアログを出すという修正を明日はやっていこうと思う。

今日はここまで!