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

いものやま。

雑多な知識の寄せ集め

変種オセロのUIを作ってみた。(その10)

昨日はタッチ処理の実装を行った。

今日はタッチ処理の実装をちょっと修正する。

タッチ処理の修正

作ったタッチ処理を実際に触ってみた分かったのは、選択を確定させるのに2回タッチするのは面倒ということ。
なので、1回のタッチで選択を確定させるように修正を行う。

修正の方法としては、2通りの方法が考えられる。

  • 2回タッチする処理の実装も残しておいて、設定で切り替えられるようにする。
  • 1回タッチする処理の実装だけにする。

プログラムとしては前者の方がいいのだろうけど、今回はバッサリと2回タッチする処理は切り捨てることにした。

なお、前者の作りにする場合、タッチ処理の部分を別クラスに切り分けて、BoardNodeはそのクラスのインスタンスに処理を委譲するようにするといい。
そうすることで、設定でクラスのインスタンスを切り替えるだけで、タッチ処理の実装も切り替わるようになる。
デザインパターンでいうストラテジーパターン)

修正したコードは、以下。(タッチ処理関連の部分のみ)

public class BoardNode: SKSpriteNode {
  // 省略

  private var touch: UITouch!
  private var currentSelectedSquare: SquareNode!

  // 省略

  public override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
    self.touch = touches.first as! UITouch
    let location = self.touch.locationInNode(self)
    
    let touchedSquare = self.findSquareAtPoint(location)
    if self.touchedSquareIsValid(touchedSquare) {
      self.currentSelectedSquare = touchedSquare
      self.currentSelectedSquare.changeStatusTo(.HighLighted, withTurn: self.board.turn)
    }
  }
  
  public override func touchesMoved(touches: Set<NSObject>, withEvent event: UIEvent) {
    self.clearCurrentSelectedSquareIfNeeded()
    
    if self.touch != nil && touches.contains(touch) {
      let location = self.touch.locationInNode(self)
      
      let touchedSquare = self.findSquareAtPoint(location)
      if self.touchedSquareIsValid(touchedSquare) {
        self.currentSelectedSquare = touchedSquare
        self.currentSelectedSquare.changeStatusTo(.HighLighted, withTurn: self.board.turn)
      }
    }
  }
  
  public override func touchesEnded(touches: Set<NSObject>, withEvent event: UIEvent) {
    self.clearCurrentSelectedSquareIfNeeded()
    
    if self.touch != nil && touches.contains(touch) {
      let location = self.touch.locationInNode(self)
      
      let touchedSquare = self.findSquareAtPoint(location)
      if self.touchedSquareIsValid(touchedSquare) {
        self.currentSelectedSquare = touchedSquare
        
        let row = self.currentSelectedSquare.row
        let col = self.currentSelectedSquare.col
        println("confirmed! [row: \(row), col: \(col)]")

        self.lighDown()
        self.currentSelectedSquare.changeStatusTo(.Lighted, withTurn: self.board.turn)
        if self.board.isPlayable(row, col) {
          self.play(row, col)
        } else if self.board.isChangeable(row, col) {
          self.change(row, col)
        }
        self.lightUpEnableSquares()
        
        self.currentSelectedSquare = nil
      }
    }
  }
  
  private func findSquareAtPoint(location: CGPoint) -> SquareNode! {
    for node in self.nodesAtPoint(location) {
      switch node {
      case let square as SquareNode:
        return square
      default:
        break
      }
    }
    return nil
  }
  
  private func touchedSquareIsValid(touchedSquare: SquareNode!) -> Bool {
    if touchedSquare == nil {
      return false
    }
    let row = touchedSquare.row
    let col = touchedSquare.col
    if self.board.isPlayable(row, col) || self.board.isChangeable(row, col) {
      return true
    } else {
      return false
    }
  }
  
  private func clearCurrentSelectedSquareIfNeeded() {
    if self.currentSelectedSquare != nil {
      self.currentSelectedSquare.changeStatusTo(.Lighted, withTurn: self.board.turn)
      self.currentSelectedSquare = nil
    }
  }
}

1回のタッチで選択を確定させるようにしたので、コードも少し簡単になってる。

この状態で実行させると、次のような感じ。

動画だとちょっと分かりにくいかもしれないけど、1回タッチするだけで選択が確定している。

それと、タッチしたまま指を動かした場合、最終的に触っていたマスが選択されたことになるし、もしそれでマス以外の場所を触っていた場合には、タッチ自体がキャンセルされるようになってる。

これでUIの一番肝心な部分は出来たので、あとはゲーム全体の流れをコントロールしていく部分を作っていく必要がある。

今日はここまで!