Как известно, рынок игр iOS достаточно прибыльный и одной из интересных и не сложных, с точки зрения разработки, являются именно игры для детей. В этом топике я хочу рассказать, как я видел решение и создание небольшой пазл-игры. Сразу показываю, что должно получиться под конец:

Кому интересно как её сложить — прошу под кат.
Честно скажу, никаких туториалов и примеров подобных задач я не смотрел, по этому может мой способ не самый лучший, но мне показался достаточно удобным и легким в реализации, так же подойдет в качестве туториала для начинающих разработчиков.
Начнем с самых первый шагов.
Для начала создадим обычный проект с одим view. Для этого открываем xCode -> Create a new xCode project -> в левой колонке выбираем Application -> Single View Application -> вписываем Product Name и остальные данные, device выбираем iPhone, не забываем поставить галочку на Use Automatic Reference Counting. Остальные чекбоксы оставляем неотмеченными.
В этом проекте я буду использовать MVC паттерн.
Итак, подведем итоги. Почему я выбрал проверку с помощью контрольных фреймов и как она работает. Все очень просто, когда центр нашего перетаскиваемого кусочка в положении UIGestureRecognizerStateEnded находится в области нашего контрольного фрейма — пазл уложен и мы его оккуратно укладываем. Высота и ширина контрольных фреймов = 50.0f. Это значение можно легко поменять, чем больше эти значения — тем легче укладывать пазлы и тут у нас появляется возможность контролировать точность укладки и тем самым сложность самой игры.
Когда все пазлы правильно выложены, в консоли появится «пазл сложен».
P.S. Соглашусь, это далеко не идеальная версия и есть множество вариаций и допустимых доработок, на пример, как проверка клика именно по UIImage, а не по целому UIImageView и если клик был именно по изображению — тогда разрешаем перетаскивать, но думаю это каждый сам сможет добавить, если в этом будет подребность.
P.P.S. спасибо за внимание, ссылка на репозиторий. Архив с изображениями.

Кому интересно как её сложить — прошу под кат.
Честно скажу, никаких туториалов и примеров подобных задач я не смотрел, по этому может мой способ не самый лучший, но мне показался достаточно удобным и легким в реализации, так же подойдет в качестве туториала для начинающих разработчиков.
Начнем с самых первый шагов.
Создание проекта
Для начала создадим обычный проект с одим view. Для этого открываем xCode -> Create a new xCode project -> в левой колонке выбираем Application -> Single View Application -> вписываем Product Name и остальные данные, device выбираем iPhone, не забываем поставить галочку на Use Automatic Reference Counting. Остальные чекбоксы оставляем неотмеченными.
Переходим к настройке проекта и добавления нужных нам файлов перед началом программирования
- В Project Navigator кликаем на файл нашего проекта. Вибираем TARGETS -> Summary и поправляем Orientations так как на изображении:
- Так как мы не будем работать с Interface Builder, удаляем ненужный нам файл ViewController.xib.
Далее переходим в AppDelegate.m и ищем строчку:
self.viewController = [[MDHViewController alloc] initWithNibName:@"MDHViewController" bundle:nil];
И заменяем её на (снова же по причине не использования Interface Builder):
self.viewController = [[MDHViewController alloc] init];
Почему MDHViewController? Все дело в префиксе, который мы указали при создании проекта (у меня он MDH).
- Следующий наш шаг — добавления изображений к проекту. Для удобства создадим отдельную папку для них (думаю не нужно объяснять как это сделать). Клацаем на созданую папку правой кнопкой мыши и выбираем Add files to .... Выбираем нужные нам изображание и добавляем их с настройками:
.
Все изображения и сам проект можно скачать по ссылке:
Начало разработки
В этом проекте я буду использовать MVC паттерн.
- Cmd + N -> Cocoa Touch -> Objective-C class
Вот мы и создали модель нашей игры.
- Переходим в GameModel.h. И создаем два массива данных:
#import <Foundation/Foundation.h> @interface GameModel : NSObject { @private NSArray *_puzzlesArray; NSArray *_coordinatesArray; NSInteger _puzzlesCount; } @property (strong, nonatomic) NSArray *puzzlesArray; @property (strong, nonatomic) NSArray *coordinatesArray; @property (nonatomic) NSInteger puzzlesCount; @end
Первый массив будет содержать наши части пазла, а второй контрольные фреймы, по которых мы будем совершать проверку перед уложением пазла. puzzlesCount — нас счетчик уложенных кусочков пазла.
GameModel.m:
@implementation GameModel @synthesize puzzlesArray = _puzzlesArray; @synthesize coordinatesArray = _coordinatesArray; @synthesize puzzlesCount = _puzzlesCount; -(id)init { self = [super init]; if (self) { [self setArraysData]; self.puzzlesCount = 0; } return self; } -(void)setArraysData { self.puzzlesArray = @[[UIImage imageNamed:@"kot_element_1"], [UIImage imageNamed:@"kot_element_2"], [UIImage imageNamed:@"kot_element_3"], [UIImage imageNamed:@"kot_element_4"]]; self.coordinatesArray = @[[NSValue valueWithCGRect:CGRectMake(285.5f, 107.0f, 50.0f, 50.0f)], [NSValue valueWithCGRect:CGRectMake(211.0f, 180.0f, 50.0f, 50.0f)], [NSValue valueWithCGRect:CGRectMake(78.0f, 75.0f, 50.0f, 50.0f)], [NSValue valueWithCGRect:CGRectMake(84.0f, 212.0f, 50.0f, 50.0f)]]; } @end
Для удобства я вынес заполнение массивов в отдельный метод, который исполняется при инициализации нашей игровой модели.
- Переходим в наш главный ViewController.h (у меня MDHViewController.h). Присоединяем GameModel.h:
#import "MDHViewController.h" #import "GameModel.h"
Нам нужно добавить UIImageView, который будет представлять нам границы пазла и конечно же не забываем про игровую модель:@interface MDHViewController () @end @implementation MDHViewController { UIImageView *puzzlesBundle; GameModel *gameModel; }
- Так как мы не используем Interface Builder добавляем метод loadView. В нем инициализируем puzzlesBundle и gameModel:
-(void)loadView { [super loadView]; puzzlesBundle = [[UIImageView alloc] init]; gameModel = [[GameModel alloc] init]; }
- Переходим к методу viewDidLoad:
- (void)viewDidLoad { [super viewDidLoad]; //даем белый фон нашему self.view [self.view setBackgroundColor:[UIColor whiteColor]]; //добавляем изображение границ нашего пазла UIImage *image = [UIImage imageNamed:@"kot_fg"]; [puzzlesBundle setImage:image]; [puzzlesBundle setFrame:CGRectMake(50.0f, 20.0f, image.size.width, image.size.height)]; [puzzlesBundle setBackgroundColor:[UIColor clearColor]]; [self.view addSubview:puzzlesBundle]; //добавляем четыре части пазла for (NSUInteger i = 0; i < gameModel.puzzlesArray.count; i++) { UIImage *puzzleImage = [gameModel.puzzlesArray objectAtIndex:i]; UIImageView *imageView = [[UIImageView alloc] initWithImage:puzzleImage]; //устанавливаем рандомные координаты [imageView setFrame:CGRectMake(arc4random() % 250, arc4random() % 200, puzzleImage.size.width, puzzleImage.size.height)]; [imageView setBackgroundColor:[UIColor clearColor]]; //теги решил использовать в качестве номерации кусочков пазла, что бы позже знать с какой именно частью мы работаем и с каким контрольным фреймом сравнивать [imageView setTag:i]; [imageView setUserInteractionEnabled:YES]; UIPanGestureRecognizer *gesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePanGesture:)]; //добавляем возможность перетаскивания частей пазла [imageView addGestureRecognizer:gesture]; [self.view addSubview:imageView]; } }
В комментариях к коду я описал основные моменты, думаю остальное должно быть понятно, кто, хотя бы немного, знаком с программированием под iOS.
- И основная часть, описываем наш handlePanGesture:(UIGestureRecognizer *)gesture метод:
-(void)handlePanGesture:(UIGestureRecognizer *)gesture { if (gesture.state == UIGestureRecognizerStateBegan) { //при клике выдвигаем кусок пазлаповерх всех остальных [self.view bringSubviewToFront:gesture.view]; } if (gesture.state == UIGestureRecognizerStateChanged) { //отслеживаем передвижение CGPoint dragPoint = [gesture locationInView:self.view]; //и присваеваем нашему кусочку пазла новые координаты [gesture.view setFrame:CGRectMake(dragPoint.x - gesture.view.frame.size.width/2, dragPoint.y - gesture.view.frame.size.height/2, gesture.view.frame.size.width, gesture.view.frame.size.height)]; } if (gesture.state == UIGestureRecognizerStateEnded) { //что бы достать значение tag, которое мы задали в viewDidLoad прибегаем к принужденному переобразованию типов UIImageView *imageView = (UIImageView *)gesture.view; //достаем нужный нам контрольный фрейм CGRect checkRect = [[gameModel.coordinatesArray objectAtIndex:imageView.tag] CGRectValue]; //проверяем входит ли центр кусочка пазла в контрольный фрейм if (CGRectContainsPoint(checkRect, [self.view convertPoint:gesture.view.center toView:puzzlesBundle])) { //и если да, то ставим его на нужное место [gesture.view setCenter:CGPointMake(checkRect.origin.x + checkRect.size.width/2+50.0f, checkRect.origin.y + checkRect.size.height / 2)]; //и блокируем для дальнейших перетаскиваний [gesture.view setUserInteractionEnabled:NO]; gameModel.puzzlesCount++; } if (gameModel.puzzlesCount == 4) { NSLog(@"пазл сложен"); } } }
Итак, подведем итоги. Почему я выбрал проверку с помощью контрольных фреймов и как она работает. Все очень просто, когда центр нашего перетаскиваемого кусочка в положении UIGestureRecognizerStateEnded находится в области нашего контрольного фрейма — пазл уложен и мы его оккуратно укладываем. Высота и ширина контрольных фреймов = 50.0f. Это значение можно легко поменять, чем больше эти значения — тем легче укладывать пазлы и тут у нас появляется возможность контролировать точность укладки и тем самым сложность самой игры.
Когда все пазлы правильно выложены, в консоли появится «пазл сложен».
P.S. Соглашусь, это далеко не идеальная версия и есть множество вариаций и допустимых доработок, на пример, как проверка клика именно по UIImage, а не по целому UIImageView и если клик был именно по изображению — тогда разрешаем перетаскивать, но думаю это каждый сам сможет добавить, если в этом будет подребность.
P.P.S. спасибо за внимание, ссылка на репозиторий. Архив с изображениями.