15パズル - 2
15パズルの二回目。
前回、<GameBoad><Piece><PieceMng>の3つのサブクラスのファイルをプロジェクトに追加しました。
今回は、そのうちPieceの中身を説明します。
まず、Pieceサブクラスのヘッダファイル<Piece.h>です。(クラスファイル作成時に自動的に生成される行も含め、すべてを掲載しています。)
#import <UIKit/UIKit.h> #import "GameBoad.h" @interface Piece : UIView { GameBoad *parent; int no; NSMutableSet *leftEcl; NSMutableSet *rightEcl; NSMutableSet *upperEcl; NSMutableSet *downEcl; } @property (readwrite) int no; @property (retain, readwrite) NSMutableSet *leftEcl; @property (retain, readwrite) NSMutableSet *rightEcl; @property (retain, readwrite) NSMutableSet *upperEcl; @property (retain, readwrite) NSMutableSet *downEcl; - (void)setNumber:(int)number parent:(GameBoad *)boad; @end
interfaceとして、6つのインスタンス変数と1つのメソッド(-setNumber)を加えています。またインスタンス変数でサブクラスGameBoadを参照しているため"GameBoad.h"をimportしています。
・インスタンス変数parentは、Pieceの親にあたる4x4のマス目を表すGameBoadサブクラスのインスタンスへのポインタを格納します。setNumberでセットされます。
・noは、このピースの番号(1〜15)です。同じくsetNumberでセットされます。
・leftEcl、rightEcl、upperEcl、downEclは、このピースを上下左右に移動する時に、ぶつかることになる他のピースのインスタンスを格納する配列です。前回、この15パズルではコマ(ピース)をドラッグでまとめて動かせるようにすると書きました。そのための情報で、PieceMngから操作します。
・@propertyとして、no、leftEcl、rightEcl、upperEcl、downEclを定義しています。これは、次の<Piece.m>の@systhesizeとセットで、他のクラスから[Pieceのインスタンス.no]のようにアクセスできるようにするためです。
次はPieceサブクラスの実体<Piece.m>です。
#import "Piece.h" @implementation Piece @synthesize no, leftEcl, rightEcl, upperEcl, downEcl; - (id)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { // Initialization code } return self; } - (void)drawRect:(CGRect)rect { // Drawing code } - (void)dealloc { [super dealloc]; } - (void)setNumber:(int)number parent:(GameBoad *)boad { no = number; parent = boad; //NSMutableSetの初期化 leftEcl = [[NSMutableSet alloc] initWithCapacity:1]; rightEcl = [[NSMutableSet alloc] initWithCapacity:1]; upperEcl = [[NSMutableSet alloc] initWithCapacity:1]; downEcl = [[NSMutableSet alloc] initWithCapacity:1]; } - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { //タッチされたPointを取り出す UITouch *touch = [touches anyObject]; CGPoint currentTouchPosition = [touch locationInView:self]; //タッチされたPointを親のview(GameBoad)の座標に変換する CGPoint location = [parent convertPoint:currentTouchPosition fromView:self]; //タッチされたPointを親のview(GameBoad)に通知する [parent isTouchesBegan:no loc:location]; } - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { UITouch *touch = [touches anyObject]; CGPoint currentTouchPosition = [touch locationInView:self]; CGPoint location = [parent convertPoint:currentTouchPosition fromView:self]; [parent isTouchesMoved:no loc:location]; } - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { UITouch *touch = [touches anyObject]; CGPoint currentTouchPosition = [touch locationInView:self]; CGPoint location = [parent convertPoint:currentTouchPosition fromView:self]; [parent isTouchesEnded:no loc:location]; } @end
・initWithFrame、drawRect、deallocの各メソッドはクラスファイル作成時に自動生成されたままで変更を加えていません。
・setNumberは、親のviewであるGameBoadから呼ばれる、このピースの番号とGameBoadのインスタンスへのポインタを設定するためのメソッドです。同時に、leftEcl、rightEcl、upperEcl、downEclの初期化を行っています。
・touchesBegan、touchesMoved、touchesEndedは、このピースが指でタッチされ、ドラッグされ、指が離されるという各イベントが起こった時にシステムから呼び出されるメソッドです。ここでは、それらのイベントの位置情報を、親であるGameBoadへ通知することだけを行っています。ピースの移動はすべてGameBoadの方で処理します。
・注意すべきは、位置情報をGameBoadへ通知する際に、座標の変換を行っているこの行です。
CGPoint location = [parent convertPoint:currentTouchPosition fromView:self];
UIViewのメソッドconvertPointは、システムからPieceに渡ってきた位置情報(currentTouchPosition)を、Pieceの座標系(fromView:self])から親のviewであるGameBoadの座標系に変換してくれます。
・なお、touchesBegan、touchesMoved、touchesEndedはUIView基底クラスのメソッドをオーバーライドしているものです。だから<Piece.h>にメソッドの宣言はありません。
Pieceについては以上です。次回は、PieceMngについて説明します。