iOS/iPhone/iPad/watchOS/tvOS/MacOSX/Android プログラミング, Objective-C, Cocoa, Swiftなど
画像を使ったサービスの一つとして15パズルというスライディング・ブロック・パズルの一種の制作を考えている。
実装方法については、Cocoa勉強会(関西)で知り合いましたSTUDIO SHIN北村真二さんの記事『実践!iOSで作るゲームアプリ』を参考にした。北村さん、ありがとう!
まず、クラス構造だが、当初は、MVCのモデルにあたるDocumentクラスは、コントローラにあたるViewControllerでゲームの制御を行う事を考えていたが、ゲーム本来の制御とアプリの枠側とは切り離したいだとか、iPhone/iPadの両方に対応させる場合、機器の違いを吸収するViewControllerには持たせない方がいいのでは?と考え、ゲーム専用のコントローラクラスを用意しることにした。結局、北村さんの記事のとおりという事になってしまった。
今回の発表で作成したのは、画面に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個の駒が全て揃った際は、タッチアップの際に、移動可能かどうかの判定をして、可能なら移動する。その際にアニメーションで、ということになる予定だ。
想定通り、マスが描画さいれているか確認するため、数字を印字しているが、反転してしまっている。デバッグ目的の簡易な実装なので、気にしないで欲しい。