[iOS]15パズル | Cocoa練習帳

[iOS]15パズル

画像を使ったサービスの一つとして15パズルというスライディング・ブロック・パズルの一種の制作を考えている。




FifteenPuzzle




実装方法については、Cocoa勉強会(関西)で知り合いましたSTUDIO SHIN北村真二さんの記事『実践!iOSで作るゲームアプリ』を参考にした。北村さん、ありがとう!




まず、クラス構造だが、当初は、MVCのモデルにあたるDocumentクラスは、コントローラにあたるViewControllerでゲームの制御を行う事を考えていたが、ゲーム本来の制御とアプリの枠側とは切り離したいだとか、iPhone/iPadの両方に対応させる場合、機器の違いを吸収するViewControllerには持たせない方がいいのでは?と考え、ゲーム専用のコントローラクラスを用意しることにした。結局、北村さんの記事のとおりという事になってしまった。




class




今回の発表で作成したのは、画面に16個のマスを表示し、1個の駒をドラッグで移動するというところまでだ。




ビューコントローラでゲームの制御を行うのでなく、ゲーム用のコントローラを用意することにしたので、ビューコントローラでは描画が必要になったらゲームコントローラを生成するだけだ。




@implementation ViewController
...
- (void)viewDidLoad
{
    [super viewDidLoad];
 
    self.gameController = [[GameController alloc] initWithView:(GameBoardView *)self.view];
}
...
@end



ゲーム盤に関係するビュー等の生成は、GameBoardViewクラスと考えていたが、実際にプログラミングしてみると、ビューからは他のビューの生成が完了したか分からない事に気がついた。なので、GameControllerがGameBoardViewに初期化のタイミングを教える事にした。




@implementation GameController
...
- (id)initWithView:(GameBoardView *)view
{
    self = [super init];
    if (self) {
        self.gameBoardView = view;
        [self.gameBoardView setupWithDelegate:self];
    }
    return self;
}
...
@end



GameBoardViewに対するユーザ操作はデリゲートでGameControllerに伝えられる。なので、タッチダウンされたら何がタッチされたのか覚えておいて、ドラッグ中は駒を移動させ、タッチアップで駒をマスの位置に移動させた。




@implementation GameController
...
- (void)gameBoardViewTouchDown:(GameBoardView *)gameBoardView location:(CGPoint)touchPt taps:(int)taps event:(UIEvent*)event
{
    GameSquare      *square = [self.gameBoardView squareAtPoint:touchPt];
    GamePieceView   *pieceView = [self.gameBoardView pieceViewAtPoint:touchPt];
    if (pieceView) {
        self.pieceView = pieceView;
        self.startLocation = touchPt;
    }
}
 
- (void)gameBoardViewTouchMove:(GameBoardView *)gameBoardView location:(CGPoint)touchPt taps:(int)taps event:(UIEvent*)event
{
    if (self.pieceView) {
        CGRect  frame = [self.pieceView frame];
        frame.origin.x += touchPt.x - self.startLocation.x;
        frame.origin.y += touchPt.y - self.startLocation.y;
        self.startLocation = touchPt;
        [self.pieceView setFrame:frame];
    }
}
 
- (void)gameBoardViewTouchUp:(GameBoardView *)gameBoardView location:(CGPoint)touchPt taps:(int)taps event:(UIEvent*)event
{
    if (self.pieceView) {
        GameSquare      *square = [self.gameBoardView squareAtPoint:touchPt];
        CGRect  frame = [square frame];
        [self.pieceView setFrame:frame];
    }
    self.pieceView = nil;
}
...
@end



15個の駒が全て揃った際は、タッチアップの際に、移動可能かどうかの判定をして、可能なら移動する。その際にアニメーションで、ということになる予定だ。




run




想定通り、マスが描画さいれているか確認するため、数字を印字しているが、反転してしまっている。デバッグ目的の簡易な実装なので、気にしないで欲しい。




ソースコード
GitHubからどうぞ。

https://github.com/murakami/workbook/tree/master/ios/FifteenPuzzle - GitHub


関連情報
実践!iOSで作るゲームアプリ



【Cocoa練習帳】
http://www.bitz.co.jp/weblog/

http://ameblo.jp/bitz/(ミラー・サイト)