基于IOS平台的游戏之小拼图
2016-06-13 19:10
603 查看
IOS/Xcode工具
一:主要功能
在拼图小游戏开发过程中,实现的主要的功能。
压缩图片:需要给传递过来的任意图片,根据手机模拟器中View大小,重新设置图片的尺寸,即压缩图片运用UIGraphicsBeginImageContext进行实现。
切割图片separateImage:将尺寸设置好的图片,进行切割成3*3 或者4*4,获取整个View的尺寸大小和图片的尺寸大小,进行大小比较,当图片的大小超过容器View的时候,将图片进行大小的缩放。然后根据切割的块,来计算出每个图块的宽高。运用两层For循环,将完整的图片按照每块设置的大小进行切割,并将0-0位置设置为空白位置 。将每块图片View的信息放到数组中。存放的信息有:当前拼图的下标,以及拼图起始没有打乱顺序的下标,用来最后判断游戏是否胜利的标记。
打乱图片顺序:产生两个NSINteger随机数,来作为存放图片View的数组的下标,从而获取图片信息,然后将两张图片进行位置对换,并改变当前拼图的下标。然后用逆序数的奇偶性来判断游戏是否能正常复位(有时候随机打乱的图片,并不能够恢复原来的位置即无解,则就需要运用逆序数的奇偶性进行判断),并判断拼图是否完全的打乱。如果两个条件有一方符合,将再次遍历打乱图片,产生两个随机数…否则游戏开始。
拼图移动:由于每个图块都有在合适的位置进行移动的实现方法,所以如果我们点击的图片,能与空白位进行移动,那么就交换这两张图块。
游戏完成:遍历的从存放每个图块视图的数组中取出每块图片View,并判断每块图片的当前下标,是否与最终特定的下标位置相等,如果每个图块都完全对照,则表示图片拼凑完成,则游戏胜利,弹出对话框。
二:效果图
开始:
![](http://img.blog.csdn.net/20160613181226037)
拼图开始(点击菜单可以返回):
![](http://img.blog.csdn.net/20160613181258194)
拼图进阶:
![](http://img.blog.csdn.net/20160613181410133)
成功:
![](http://img.blog.csdn.net/20160613181418352)
三:代码
If you are interested, study the code.
拼图视图PuzzleImageView.m
拼图视图PuzzleImageView.h
拼图视图控制器PuzzleViewController.m
拼图视图控制器PuzzleViewController.h
菜单视图控制器MenuViewController.m
菜单视图控制器MenuViewControlle.h
1:拼图视图PuzzleImageView.m
2: 拼图视图PuzzleImageView.h
3:拼图视图控制器PuzzleViewController.m
4:拼图视图控制器PuzzleViewController.h
5: 菜单视图控制器MenuViewController.m
6:菜单视图控制器MenuViewControlle.h
四:主要函数解析
-(void) initData:主要的功能是初始化拼图标题,以及指定图片名称。
ByScalingToSize:(CGSize)targetSize:压缩图片,重新设置图片尺寸。
-(NSMutableArray *) separateImage:根据不同的等级来对图片进行切割。(对切割好的图片设置好 两个下标Tag(nowIndex, resultIndex))用来最后判断拼图是否成功复位。
-(void)puzzleTheImage: 打乱图块顺序
-(BOOL) makePuzzleCanBeSolved:逆序数检查图片是否能复位即有解。
-(BOOL) makePuzzleFinished:判断每个图块是否全部打乱,也是用来判断游戏是否复位成功的判断函数的实现。
-(void)exchangePuzzleFrameWithZero:交换两个图块。并实时判断游戏是否成功结束。
-(void) puzzleImageViewShouldMove:判断图块是否能与空白位进行移动。若可以则移动。
简单的介绍逆序数
拼图复位判断:循环遍历每个图块,看每个图片的当前下标nowIndex,是否与最初分块的下标值(resultIndex)相等,如果完全一致,表示拼图成功复位。
逆序数奇偶性判断有无解:对源状态A与目标状态B进行规范化,使得两矩阵的元素0(important)的位置相同;记为新的源状态A’与目标状态B’;
根据逆序数想关推论,以3*3为例,矩阵为
0 1 2 逆序数为0 是偶数
3 4 5 所以最后随机乱序的拼图 也应该是偶矩阵排列
6 7 8 逆序数的计算有线性代数知识点可知
逆序数计算的例子:
0 4 5
7 8 3
2 1 6
以 0 4 5 7 8 3 2 1 6 一一看起
4:比4小的值有 3 2 1 (三个)
5:比5小的值有 3 2 1 (三个)
7:比7小的值有 3 2 1 6 (四个)
8:比8小的值有 3 2 1 6 (四个)
2:比2小的值有 1(一个)
1:比1小的值有 (0个)
6:比6小的值显然..
三个+三个+四个+四个+一个= 15 判断一下 奇数。 与最出的偶数矩阵奇偶性不同。故乱序的拼图如果是这个矩阵,则无解。
代码仍需要在不断的学习中完善,带着怀疑的态度来思考(⊙_⊙)?。
360云盘代码(点击前先复制访问密码) 访问密码 1394
代码
一:主要功能
在拼图小游戏开发过程中,实现的主要的功能。
压缩图片:需要给传递过来的任意图片,根据手机模拟器中View大小,重新设置图片的尺寸,即压缩图片运用UIGraphicsBeginImageContext进行实现。
切割图片separateImage:将尺寸设置好的图片,进行切割成3*3 或者4*4,获取整个View的尺寸大小和图片的尺寸大小,进行大小比较,当图片的大小超过容器View的时候,将图片进行大小的缩放。然后根据切割的块,来计算出每个图块的宽高。运用两层For循环,将完整的图片按照每块设置的大小进行切割,并将0-0位置设置为空白位置 。将每块图片View的信息放到数组中。存放的信息有:当前拼图的下标,以及拼图起始没有打乱顺序的下标,用来最后判断游戏是否胜利的标记。
打乱图片顺序:产生两个NSINteger随机数,来作为存放图片View的数组的下标,从而获取图片信息,然后将两张图片进行位置对换,并改变当前拼图的下标。然后用逆序数的奇偶性来判断游戏是否能正常复位(有时候随机打乱的图片,并不能够恢复原来的位置即无解,则就需要运用逆序数的奇偶性进行判断),并判断拼图是否完全的打乱。如果两个条件有一方符合,将再次遍历打乱图片,产生两个随机数…否则游戏开始。
拼图移动:由于每个图块都有在合适的位置进行移动的实现方法,所以如果我们点击的图片,能与空白位进行移动,那么就交换这两张图块。
游戏完成:遍历的从存放每个图块视图的数组中取出每块图片View,并判断每块图片的当前下标,是否与最终特定的下标位置相等,如果每个图块都完全对照,则表示图片拼凑完成,则游戏胜利,弹出对话框。
二:效果图
开始:
拼图开始(点击菜单可以返回):
拼图进阶:
成功:
三:代码
If you are interested, study the code.
拼图视图PuzzleImageView.m
拼图视图PuzzleImageView.h
拼图视图控制器PuzzleViewController.m
拼图视图控制器PuzzleViewController.h
菜单视图控制器MenuViewController.m
菜单视图控制器MenuViewControlle.h
1:拼图视图PuzzleImageView.m
//PuzzleImageView.m #import <Foundation/Foundation.h> #import "PuzzleImageView.h" @implementation PuzzleImageView - (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { } return self; } - (id) initWithImage:(UIImage *)image { if (self = [super initWithImage:image]) { [self setUserInteractionEnabled:YES];//交互设置 [self setMultipleTouchEnabled:YES];//多指触控 self.layer.borderWidth = 1;//注意边框为1,来判断拼图是否能移动 } return self; } -(BOOL)canMoveToPoint:(CGPoint)pos { //判断拼图是否能够移动,注意Origin的取值。 CGPoint point = self.frame.origin; CGSize size = self.frame.size; //可用Log输出日志对其中取值进行查看 //左右移动的拼图 if (abs(abs(point.x - pos.x) - size.width) <1 && (point.y == pos.y)) { return YES; } //上下移动拼图 else if(abs(abs(point.y - pos.y) - size.height) <1 && (point.x == pos.x)) { return YES; } else { return NO; } } -(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { //代理 if(self.delegate && [self.delegate respondsToSelector:@selector(puzzleImageViewShouldMove:)]) { [self.delegate puzzleImageViewShouldMove:self]; } } @end
2: 拼图视图PuzzleImageView.h
//PuzzleImageView.h #import <UIKit/UIKit.h> #import <Foundation/Foundation.h> @class PuzzleImageView; @protocol PuzzleDelegate <NSObject> @optional -(void) puzzleImageViewShouldMove:(PuzzleImageView *)imageview; @end @interface PuzzleImageView : UIImageView @property (assign, nonatomic) id <PuzzleDelegate> delegate; @property (assign, nonatomic) NSInteger resultIndex; @property (assign, nonatomic) NSInteger nowIndex; -(BOOL)canMoveToPoint:(CGPoint)pos; @end
3:拼图视图控制器PuzzleViewController.m
//PuzzleViewController.m #import "PuzzleViewController.h" #import <Foundation/Foundation.h> @interface PuzzleViewController () @end @implementation PuzzleViewController - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; if (self) { // Custom initialization } return self; } - (void)viewDidLoad { [super viewDidLoad]; //初始化数据 [self initData]; //初始化图片 [self initPuzzleImage]; } - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; } // 初始化必要数据 -(void) initData { self.title = @"拼图"; self.string_ImageName = @"IMG.JPG"; } // 初始化图片 -(void) initPuzzleImage { [self resetPuzzleImageWithImage:[UIImage imageNamed:self.string_ImageName]]; } // 重置图片 -(void) resetPuzzleImageWithImage:(UIImage *)image { CGFloat scale = image.size.height / image.size.width; //重新设置图片尺寸(压缩图片) UIImage *resultImage = [self image:image ByScalingToSize:CGSizeMake(380, 380*scale)]; self.isStart = NO; //切割图片 self.array_ImageView = [self separateImage:resultImage ByX:self.lvl andY:self.lvl]; //打乱图片顺序 [self puzzleTheImage]; if(self.view_PuzzleBoard) { [self.view_PuzzleBoard removeFromSuperview]; } //加载图片视图(tip:可以通过修改坐标值,以及更改背景颜色,来观察,绘制位置) self.view_PuzzleBoard = [self createPuzzleBoardViewWithFrame:CGRectMake(0, 0, 380, [UIScreen mainScreen].bounds.size.height)]; //将拼图视图添加到View中 [self.view addSubview:self.view_PuzzleBoard]; } //重新设置图片尺寸 - (UIImage *)image:(UIImage *)sourceImage ByScalingToSize:(CGSize)targetSize { UIImage *newImage = nil; CGRect rect = CGRectMake(0.0, 0.0, targetSize.width, targetSize.height); //压缩图片过程 UIGraphicsBeginImageContext(rect.size); [sourceImage drawInRect:rect]; newImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); if(newImage == nil) NSLog(@"could not scale image"); return newImage ; } // 分解图片 -(NSMutableArray *) separateImage:(UIImage *)image ByX:(int)x andY:(int)y { // 数据监测 if (x < 1 || y < 1 || ![image isKindOfClass:[UIImage class]]) { return Nil; } CGFloat sWidth = self.view.frame.size.width; CGFloat sHeight = self.view.frame.size.height; CGFloat iWidth = image.size.width; CGFloat iHeight = image.size.height; // 图片大小适配(防止图片超过屏幕尺寸) if (iHeight > sHeight || iWidth > sWidth) { CGFloat scala = MIN(sHeight/iHeight, sWidth/iWidth); iWidth = iWidth * scala; iHeight = iHeight * scala; } NSMutableArray *array = [NSMutableArray array]; float resultX = iWidth * 1.0 / y; float resultY = iHeight * 1.0 / x; for (int i = 0; i < x; i++) { for (int j = 0; j < y; j++) { CGRect rect = CGRectMake(resultX*j, resultY*i, resultX, resultY); CGImageRef imageRef = CGImageCreateWithImageInRect([image CGImage],rect); UIImage* elementImage = [UIImage imageWithCGImage:imageRef]; // 空白位 if (i == 0 && j == 0) { elementImage = nil; } PuzzleImageView *puzzleImageView=[[PuzzleImageView alloc] initWithImage:elementImage]; puzzleImageView.resultIndex = i * x + j; puzzleImageView.nowIndex = i * x + j; puzzleImageView.delegate = self; puzzleImageView.frame = CGRectMake( 10+resultX * j, 150+resultY * i, resultX, resultY); [array addObject:puzzleImageView]; } } return array; } //创建拼图所需的背景图,可将注释放开结合坐标更改,观察具体使用 -(UIView *) createPuzzleBoardViewWithFrame:(CGRect)rect { UIView *view = [[UIView alloc]initWithFrame:rect]; //view.backgroundColor = [UIColor grayColor]; //遍历 for (PuzzleImageView *pzView in self.array_ImageView) { [view addSubview: pzView]; } return view; } // 打乱顺序 -(void)puzzleTheImage { // 保持0位不动,否则奇偶性检查无效(需要提前对逆序数有所学习认识) //随机产生两个1~8之间的数字 NSInteger aIndex = arc4random()%(self.array_ImageView.count - 1) + 1; PuzzleImageView *aView = [self.array_ImageView objectAtIndex:aIndex]; NSInteger bIndex = arc4random()%(self.array_ImageView.count - 1) + 1; PuzzleImageView *bView = [self.array_ImageView objectAtIndex:bIndex]; //交换随机产生的两个图片的 NowIndex [self exchangePuzzleFrameWithZero:aView And:bView withAnimation:NO]; // 检查打乱是否完成,否则递归 if (![self makePuzzleCanBeSolved] || ![self makePuzzleFinished]) { [self puzzleTheImage]; } else { // 游戏正式开始 self.isStart = YES; } } // 检查无解 -(BOOL) makePuzzleCanBeSolved { // 奇偶性总值 NSInteger sum = 0; // 循环遍历(两层for循环计算的是逆序数值,知道逆序数的怎么计算的,就可以相应理解) for (NSInteger i = 0; i < self.array_ImageView.count; i++) { PuzzleImageView *aView = [self.array_ImageView objectAtIndex:i]; printf("--%d",aView.nowIndex); for (NSInteger j = i + 1; j < self.array_ImageView.count; j++) { PuzzleImageView *bView = [self.array_ImageView objectAtIndex:j]; // printf("b-- %d ",bView.nowIndex); // 逆序数检查 if (aView.nowIndex > bView.nowIndex) { sum ++; } } } // 根据逆序数奇偶性判断是否有解 if ((sum % 2) == 0) { return YES; } else { printf("无解\n"); return NO; } } // 全部无序 -(BOOL) makePuzzleFinished { BOOL flag = YES; //每个拼图进行一一比对 for (PuzzleImageView *pzView in self.array_ImageView) { if (pzView.resultIndex != 0 && pzView.resultIndex == pzView.nowIndex) { printf("未全打乱\n"); flag = NO; break; } } return flag; } //拼图移动 -(void) puzzleImageViewShouldMove:(PuzzleImageView *)imageview { PuzzleImageView *zeroPZ = [self.array_ImageView objectAtIndex:0]; // 是否允许移动 if ([imageview canMoveToPoint:zeroPZ.frame.origin]) { //交换 [self exchangePuzzleFrameWithZero:zeroPZ And:imageview withAnimation:YES]; } } // 交换两个拼图视图 -(void)exchangePuzzleFrameWithZero:(PuzzleImageView *)zeroView And:(PuzzleImageView *)bView withAnimation:(BOOL)animation { CGRect aRect = zeroView.frame; NSInteger aIndex = zeroView.nowIndex; [zeroView setFrame:bView.frame]; [zeroView setNowIndex:bView.nowIndex]; [bView setNowIndex:aIndex]; if (animation) { [UIView animateWithDuration:0.4 delay:0.0 options:UIViewAnimationOptionCurveEaseInOut animations:^{ [bView setFrame:aRect]; } completion:Nil]; }else { [bView setFrame:aRect]; } if (self.isStart && [self gameComplete]) { UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"恭喜" message:@"游戏完成!" delegate:self cancelButtonTitle:@"确定" otherButtonTitles:Nil, nil]; [alert show]; } } // 完成退出 - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex { [self.navigationController popViewControllerAnimated:YES]; } // 判断游戏完成 -(BOOL) gameComplete { BOOL flag = YES; for (PuzzleImageView *pzView in self.array_ImageView) { if (pzView.resultIndex != pzView.nowIndex) { flag = NO; break; } } return flag; } @end
4:拼图视图控制器PuzzleViewController.h
//PuzzleViewController.h #import <UIKit/UIKit.h> #import "PuzzleImageView.h" #import <Foundation/Foundation.h> @interface PuzzleViewController : UIViewController <PuzzleDelegate, UIActionSheetDelegate, UINavigationControllerDelegate, UIImagePickerControllerDelegate> @property (strong, nonatomic) NSMutableArray *array_ImageView; @property (strong, nonatomic) NSString *string_ImageName; @property (assign, nonatomic) BOOL isStart; @property (assign, nonatomic) NSInteger lvl; @property (strong, nonatomic) UIView *view_PuzzleBoard; @end
5: 菜单视图控制器MenuViewController.m
// ViewController.m #import <Foundation/Foundation.h> #import "MenuViewController.h" #import "PuzzleViewController.h" @interface MenuViewController () @end @implementation MenuViewController - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; if (self) { } return self; } - (void)viewDidLoad { [super viewDidLoad]; [self initData]; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; } //视图控制器更改,不同视图的跳转(点击Button时候跳转拼图页面)传入的是拼图阶。 -(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { UIViewController *vc = segue.destinationViewController; if ([vc isKindOfClass:[PuzzleViewController class]]) { ((PuzzleViewController *)vc).lvl = self.lvl; } } // 初始化必要数据 -(void)initData { self.title = @"菜单"; self.lvl = 3; } //滑块值的更改处理 - (IBAction)sliderValueChange:(id)sender { UISlider *slider = sender; if (slider.value < 4) { self.lvl = 3; [slider setValue:3.0]; self.label_lvl.text = @"简单"; }else if (slider.value < 5) { self.lvl = 4; [slider setValue:4.0]; self.label_lvl.text = @"中等"; }else if (slider.value > 4) { self.lvl = 5; [slider setValue:5.0]; self.label_lvl.text = @"困难"; } } @end
6:菜单视图控制器MenuViewControlle.h
//MenuViewControlle.h #import <UIKit/UIKit.h> #import <Foundation/Foundation.h> @interface MenuViewController : UIViewController @property (assign, nonatomic) NSInteger lvl; @property (strong, nonatomic) IBOutlet UILabel *label_lvl; - (IBAction)sliderValueChange:(id)sender; @end
四:主要函数解析
-(void) initData:主要的功能是初始化拼图标题,以及指定图片名称。
ByScalingToSize:(CGSize)targetSize:压缩图片,重新设置图片尺寸。
-(NSMutableArray *) separateImage:根据不同的等级来对图片进行切割。(对切割好的图片设置好 两个下标Tag(nowIndex, resultIndex))用来最后判断拼图是否成功复位。
-(void)puzzleTheImage: 打乱图块顺序
-(BOOL) makePuzzleCanBeSolved:逆序数检查图片是否能复位即有解。
-(BOOL) makePuzzleFinished:判断每个图块是否全部打乱,也是用来判断游戏是否复位成功的判断函数的实现。
-(void)exchangePuzzleFrameWithZero:交换两个图块。并实时判断游戏是否成功结束。
-(void) puzzleImageViewShouldMove:判断图块是否能与空白位进行移动。若可以则移动。
简单的介绍逆序数
拼图复位判断:循环遍历每个图块,看每个图片的当前下标nowIndex,是否与最初分块的下标值(resultIndex)相等,如果完全一致,表示拼图成功复位。
逆序数奇偶性判断有无解:对源状态A与目标状态B进行规范化,使得两矩阵的元素0(important)的位置相同;记为新的源状态A’与目标状态B’;
1. 若A'与B'的逆序对的奇偶性相同(即A'与B1的逆序对的奇偶性相同),则A'必定可能转化为B',即A可以转化到B(从这一条性质知道,乱序的拼图是否能够有解); 2. 若A'与B'的逆序对的奇偶性不同(即A'与B2的逆序对的奇偶性相同),则A'必定不可能转化为B',即A不可以转化到B;
根据逆序数想关推论,以3*3为例,矩阵为
0 1 2 逆序数为0 是偶数
3 4 5 所以最后随机乱序的拼图 也应该是偶矩阵排列
6 7 8 逆序数的计算有线性代数知识点可知
逆序数计算的例子:
0 4 5
7 8 3
2 1 6
以 0 4 5 7 8 3 2 1 6 一一看起
4:比4小的值有 3 2 1 (三个)
5:比5小的值有 3 2 1 (三个)
7:比7小的值有 3 2 1 6 (四个)
8:比8小的值有 3 2 1 6 (四个)
2:比2小的值有 1(一个)
1:比1小的值有 (0个)
6:比6小的值显然..
三个+三个+四个+四个+一个= 15 判断一下 奇数。 与最出的偶数矩阵奇偶性不同。故乱序的拼图如果是这个矩阵,则无解。
代码仍需要在不断的学习中完善,带着怀疑的态度来思考(⊙_⊙)?。
360云盘代码(点击前先复制访问密码) 访问密码 1394
代码
相关文章推荐
- [置顶] iOS开发——布局框架Masonry的介绍与使用
- ios获取所有相册的视频并播放
- iOS App集成Apple Pay教程(附示例代码)
- iOS中的内边距是什么
- iOS学习之Table View的简单使用
- iOS数据存储精讲
- iOS - EXC_BAD_ACCESS 错误排查
- ios访问相册,摄像头等权限
- iOS 各个型号的尺寸及大小
- IOS Dev Intro - Core Media
- ios 视频拼接/合成
- iOS监听音量调节事件
- 关于iOS block传值的理解
- iOS 类似外卖 两个tableView联动
- iOS形变之CATransform3D
- IOS开发之Xcode下LLDB调试技巧_Debug_更改BOOL类型的值
- iOS动画详解(二)
- iOS动画详解(一)
- iOS开发,应用间的跳转
- IOS Block传值