经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 移动开发 » iOS » 查看文章
iOS-宫格拼图
来源:cnblogs  作者:macro小K  时间:2021/4/12 9:50:09  对本文有异议

思路

要求设计思路是类似手持拼图游戏,拼图需求要求有一块为空白版,作为移动方块的预留位置用,通过选择图片后在起初对所有图像方块随机打乱顺序时,发现随机打乱顺序,没办法拼图完成,拼图移动是空白快最临近的上下左右四个图像块的移动,在打乱顺序的时候,也要按照这个算法逻辑实现,才能拼图完成;

另外逻辑实现上,用tag来记录图片,用accessibilityValue 来记录图片的实际位置标记;

用三个数组来实现顺序打乱、正序校验、拼图位置的校验等,起初对三个数组进行相同的初始化值;

实现

变量及相关初始化

  1. ///次序,用来排序
  2. @property (nonatomic,strong) NSMutableArray * orderArray;
  3. ///次序,用来乱序打乱拼图
  4. @property (nonatomic,strong) NSMutableArray * disorderArray;
  5. ///次序,用来拼图移动位置记录
  6. @property (nonatomic,strong) NSMutableArray * puzzleArray;
  7. ///图片原图
  8. @property (nonatomic,strong) UIImage * puzzleImage;
  9. ///行、列数【难度】
  10. @property (nonatomic,assign) NSInteger rows;
  11. ///方块图间距
  12. @property (nonatomic,assign) CGFloat itemSpace;
  13. ///四周边距
  14. @property (nonatomic,assign) CGFloat marginSpace;
  15. ///是否允许拼图
  16. @property (nonatomic,assign) BOOL allowJoint;
  17. ///拖动拼图
  18. @property (nonatomic,strong) UIImageView * panImageView;
  19. ///拖动拼图Frame
  20. @property (nonatomic,assign) CGRect panImageFrame;
  1. - (instancetype)initWithFrame:(CGRect)frame
  2. rows:(NSInteger)rows
  3. puzzleImage:(UIImage *)puzzleImage{
  4. self = [super initWithFrame:frame];
  5. if (self) {
  6. _rows = rows;
  7. _puzzleImage = puzzleImage;
  8. [self setupPP];
  9. }
  10. return self;
  11. }
  12. - (void)setupPP{
  13. self.userInteractionEnabled = NO;
  14. _allowJoint = YES;
  15. _orderArray = [NSMutableArray array];
  16. _disorderArray = [NSMutableArray array];
  17. _puzzleArray = [NSMutableArray array];
  18. // _rows = 6;
  19. _itemSpace = floor(_rows*xkScale/(_rows/2));
  20. _marginSpace = floor(_rows*xkScale);
  21. self.backgroundColor = [UIColor whiteSmoke];
  22. [self setupOrderArray:(_rows * _rows)];
  23. ///如果图片的大小大于当前宽度,就压缩
  24. if (_puzzleImage.size.width > CGRectGetWidth(self.frame)) {
  25. UIGraphicsBeginImageContextWithOptions(self.bounds.size, NO, 1);
  26. [_puzzleImage drawInRect:CGRectMake(0,0,self.bounds.size.width,self.bounds.size.height)];
  27. UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
  28. UIGraphicsEndImageContext();
  29. _puzzleImage = newImage;
  30. }
  31. CGFloat pWidth = (CGRectGetWidth(self.frame) - _itemSpace*(_rows-1) - _marginSpace*2)/_rows;
  32. CGFloat pHeight = (CGRectGetHeight(self.frame) - _itemSpace*(_rows-1) - _marginSpace*2)/_rows;
  33. for (int i = 0; i < _rows; i ++) {
  34. for (int j = 0; j < _rows; j ++) {
  35. NSInteger order = _rows * i + j;
  36. NSLog(@"order = %ld",order);
  37. /*
  38. NSInteger indexes_x = 0;
  39. NSInteger indexes_y = 0;
  40. if (order < (_rows *_rows) - 1) {
  41. NSInteger location = [_disorderArray[order] integerValue];
  42. indexes_y = location/_rows;///第几行
  43. indexes_x = location%_rows;///第几个
  44. }
  45. else{
  46. indexes_y = _rows - 1;
  47. indexes_x = _rows - 1;
  48. }
  49. CGFloat x_img = _marginSpace + (indexes_x)*(pWidth + _itemSpace);
  50. CGFloat y_img = _marginSpace + (indexes_y)*(pHeight + _itemSpace);
  51. */
  52. CGFloat x = _marginSpace + (j)*(pWidth + _itemSpace);
  53. CGFloat y = _marginSpace + (i)*(pHeight + _itemSpace);
  54. UIImageView *imgView = [self puzzleImageWithFrame:CGRectMake(x, y, pWidth, pHeight)];
  55. //将UIImage转化成CGImage
  56. CGImageRef imageRef = CGImageCreateWithImageInRect(_puzzleImage.CGImage, CGRectMake(x, y, pWidth, pHeight));
  57. //将CGImage转化成UIImage
  58. UIImage *imageNew = [UIImage imageWithCGImage:imageRef];
  59. imgView.image = imageNew;
  60. ///用来标记view
  61. imgView.tag = order + 1;
  62. ///用来记录view位置
  63. imgView.accessibilityValue = [NSString stringWithFormat:@"%ld",order + 1];
  64. [self addSubview:imgView];
  65. if (imgView.tag == (_rows * _rows)) {
  66. imgView.image = [UIImage imageNamed:@"pp_chunk"];
  67. imgView.backgroundColor = [UIColor whiteSmoke];
  68. }
  69. }
  70. }
  71. dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, 1.5 * NSEC_PER_SEC);
  72. dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
  73. [self startDisorganizePuzzleImage];
  74. });
  75. }
  1. - (void)setupOrderArray:(NSInteger)count{
  2. for (int i = 1; i<=count; i ++) {
  3. [_orderArray addObject:[NSString stringWithFormat:@"%d",i]];
  4. [_disorderArray addObject:[NSString stringWithFormat:@"%d",i]];
  5. [_puzzleArray addObject:[NSString stringWithFormat:@"%d",i]];
  6. }
  7. }

打乱拼图顺序

打乱拼图顺序的算法和规则,可以根据打乱的程度或者次数,通过递归添加结束条件

  1. - (void)setupDisorganizePuzzleImageNumber:(NSInteger)number{
  2. if (number <= 0) {
  3. self.userInteractionEnabled = YES;
  4. return;
  5. }
  6. self.userInteractionEnabled = NO;
  7. ///获取空白格
  8. UIImageView *emImg = [self viewWithTag:(_rows * _rows)];
  9. ///获取空白格的位置
  10. NSInteger emLocation = [emImg.accessibilityValue integerValue];
  11. ///通过空白格位置,获取四周可以移动的格子的位置与tag
  12. NSMutableArray *arrayLoc = [NSMutableArray array];
  13. NSInteger upLocation = emLocation - _rows;
  14. NSInteger downLocation = emLocation + _rows;
  15. NSInteger leftLocation = emLocation - 1;
  16. NSInteger righjtLocation = emLocation + 1;
  17. if (upLocation > 0) {///
  18. [arrayLoc addObject:@(upLocation)];
  19. }
  20. if (downLocation <= (_rows*_rows)) {///
  21. [arrayLoc addObject:@(downLocation)];
  22. }
  23. if (leftLocation%_rows != 0 && leftLocation <= (_rows*_rows)) {///
  24. [arrayLoc addObject:@(leftLocation)];
  25. }
  26. if (righjtLocation%_rows != 1 && righjtLocation <= (_rows*_rows)) {///
  27. [arrayLoc addObject:@(righjtLocation)];
  28. }
  29. ///随机获取一个转移目标
  30. NSInteger random = arc4random() % arrayLoc.count;
  31. NSInteger targetLocation = [arrayLoc[random] integerValue];
  32. NSInteger targetIndex = [_disorderArray indexOfObject:[NSString stringWithFormat:@"%ld",targetLocation]];
  33. ///获取目标试图
  34. UIImageView *targetImg = [self viewWithTag:targetIndex + 1];
  35. if (targetImg) {
  36. CGRect targetRect = CGRectMake(CGRectGetMinX(targetImg.frame),
  37. CGRectGetMinY(targetImg.frame),
  38. CGRectGetWidth(targetImg.frame),
  39. CGRectGetHeight(targetImg.frame));
  40. CGRect emRect = CGRectMake(CGRectGetMinX(emImg.frame),
  41. CGRectGetMinY(emImg.frame),
  42. CGRectGetWidth(emImg.frame),
  43. CGRectGetHeight(emImg.frame));
  44. [UIView animateWithDuration:0.01 animations:^{
  45. emImg.frame = targetRect;
  46. targetImg.frame = emRect;
  47. } completion:^(BOOL finished) {
  48. ///处理交换【打乱次序】
  49. NSInteger emIndex = [_disorderArray indexOfObject:emImg.accessibilityValue];
  50. [_disorderArray exchangeObjectAtIndex:(targetIndex) withObjectAtIndex:(emIndex)];
  51. ///切换保存顺序【拼图】
  52. NSInteger accesTarget = [targetImg.accessibilityValue integerValue] - 1;
  53. NSInteger accesEm = [emImg.accessibilityValue integerValue] - 1;
  54. [_puzzleArray exchangeObjectAtIndex:(accesTarget) withObjectAtIndex:(accesEm)];
  55. targetImg.accessibilityValue = [NSString stringWithFormat:@"%ld",emLocation];
  56. emImg.accessibilityValue = [NSString stringWithFormat:@"%ld",targetLocation];
  57. [self setupDisorganizePuzzleImageNumber:number - 1];
  58. }];
  59. }
  60. }

拼图点击手势(空白格不允许)

  1. ///拼图点击事件
  2. - (void)puzzleImageTapClick:(UITapGestureRecognizer *)tap{
  3. NSInteger tapTag = tap.view.tag;
  4. UIImageView *tapImg = [self viewWithTag:tapTag];
  5. [self puzzleImageTapGestureHandler:tapImg];
  6. }
  7. ///点击手势操作
  8. - (void)puzzleImageTapGestureHandler:(UIImageView *)puzzleImage{
  9. if (!_allowJoint) {
  10. return;
  11. }
  12. NSInteger emTag = (_rows * _rows);
  13. NSInteger tapTag = puzzleImage.tag;
  14. if (emTag == tapTag) {
  15. return;
  16. }
  17. UIImageView *emImg = [self viewWithTag:emTag];
  18. UIImageView *tapImg = puzzleImage;
  19. CGFloat emMinX = floor(CGRectGetMinX(emImg.frame));
  20. CGFloat emMaxX = floor(CGRectGetMaxX(emImg.frame));
  21. CGFloat emMinY = floor(CGRectGetMinY(emImg.frame));
  22. CGFloat emMaxY = floor(CGRectGetMaxY(emImg.frame));
  23. CGFloat tapMinX = floor(CGRectGetMinX(tapImg.frame));
  24. CGFloat tapMaxX = floor(CGRectGetMaxX(tapImg.frame));
  25. CGFloat tapMinY = floor(CGRectGetMinY(tapImg.frame));
  26. CGFloat tapMaxY = floor(CGRectGetMaxY(tapImg.frame));
  27. BOOL isExchange = NO;
  28. if ((tapMinX == emMinX) &&
  29. fabs((tapMaxY + _itemSpace) - emMinY) < 5*xkScale){
  30. isExchange = YES;
  31. }
  32. else if ((tapMinX == emMinX) &&
  33. fabs((emMaxY + _itemSpace) - tapMinY) < 5*xkScale){
  34. isExchange = YES;
  35. }
  36. else if ((tapMinY == emMinY) &&
  37. fabs((tapMaxX + _itemSpace) - emMinX) < 5*xkScale){
  38. isExchange = YES;
  39. }
  40. else if ((tapMinY == emMinY) &&
  41. fabs((emMaxX + _itemSpace) - tapMinX) < 5*xkScale){
  42. isExchange = YES;
  43. }
  44. else{
  45. isExchange = NO;
  46. }
  47. CGRect tapRect = CGRectMake(CGRectGetMinX(tapImg.frame),
  48. CGRectGetMinY(tapImg.frame),
  49. CGRectGetWidth(tapImg.frame),
  50. CGRectGetHeight(tapImg.frame));
  51. CGRect emRect = CGRectMake(CGRectGetMinX(emImg.frame),
  52. CGRectGetMinY(emImg.frame),
  53. CGRectGetWidth(emImg.frame),
  54. CGRectGetHeight(emImg.frame));
  55. if (isExchange) {
  56. NSLog(@"允许交换");
  57. [UIView animateWithDuration:0.3 animations:^{
  58. _allowJoint = NO;
  59. emImg.frame = tapRect;
  60. tapImg.frame = emRect;
  61. } completion:^(BOOL finished) {
  62. NSInteger accesTap = [tapImg.accessibilityValue integerValue];
  63. NSInteger accesEm = [emImg.accessibilityValue integerValue];
  64. ///因为accessibilityValue与tag一样,索引需要减1
  65. [_puzzleArray exchangeObjectAtIndex:(accesTap - 1) withObjectAtIndex:(accesEm - 1)];
  66. tapImg.accessibilityValue = [NSString stringWithFormat:@"%ld",accesEm];
  67. emImg.accessibilityValue = [NSString stringWithFormat:@"%ld",accesTap];
  68. _allowJoint = YES;
  69. if ([self isPuzzleImageFinish]) {
  70. NSLog(@"拼图完成");
  71. [self puzzleImageFinishHandler];
  72. }
  73. else{
  74. NSLog(@"继续加油");
  75. }
  76. }];
  77. }
  78. else{
  79. NSLog(@"不允许交换");
  80. }
  81. }

拼图拖动手势(空白格不允许)

  1. /// 拼图拖动
  2. - (void)puzzleImagePanGesture:(UIPanGestureRecognizer *)pan{
  3. _panImageView = (UIImageView *)pan.view;
  4. [self bringSubviewToFront:pan.view];
  5. if (_panImageView.tag == (_rows * _rows)) {///空白格
  6. }
  7. else{
  8. if (pan.state == UIGestureRecognizerStateBegan) {
  9. _panImageFrame = pan.view.frame;
  10. _panImageView = (UIImageView *)pan.view;
  11. }
  12. else if (pan.state == UIGestureRecognizerStateChanged){
  13. //获取偏移量
  14. CGPoint transP = [pan translationInView:pan.view];
  15. // 移动图片控件
  16. CGRect tapRect = CGRectMake(CGRectGetMinX(pan.view.frame) + transP.x,
  17. CGRectGetMinY(pan.view.frame) + transP.y,
  18. CGRectGetWidth(pan.view.frame),
  19. CGRectGetHeight(pan.view.frame));
  20. pan.view.frame = tapRect;
  21. // 复位,表示相对上一次位置复位重置
  22. [pan setTranslation:CGPointZero inView:pan.view];
  23. }
  24. else if (pan.state == UIGestureRecognizerStateEnded){
  25. if (!_allowJoint) {
  26. [UIView animateWithDuration:0.1 animations:^{
  27. _allowJoint = NO;
  28. _panImageView.frame = _panImageFrame;
  29. } completion:^(BOOL finished) {
  30. _allowJoint = YES;
  31. }];
  32. return;
  33. }
  34. NSInteger emTag = (_rows * _rows);
  35. UIImageView *emImg = [self viewWithTag:emTag];
  36. CGPoint point1 = _panImageView.center;
  37. CGPoint point2 = emImg.center;
  38. CGFloat distance = sqrt(pow((point1.x - point2.x), 2) + pow((point1.y - point2.y), 2));
  39. if (distance <= CGRectGetHeight(_panImageFrame)/2) {///中心点相差小于20的,允许判断是否交换位置
  40. [self puzzleImagePanGestureHandler:_panImageView defaultFrame:_panImageFrame];
  41. }
  42. else{///放回原来位置
  43. [UIView animateWithDuration:0.1 animations:^{
  44. _allowJoint = NO;
  45. _panImageView.frame = _panImageFrame;
  46. } completion:^(BOOL finished) {
  47. _allowJoint = YES;
  48. }];
  49. }
  50. }
  51. else{
  52. }
  53. }
  54. }
  55. ///拖动手势操作
  56. - (void)puzzleImagePanGestureHandler:(UIImageView *)puzzleImage defaultFrame:(CGRect)defaultFrame{
  57. NSInteger emTag = (_rows * _rows);
  58. NSInteger tapTag = puzzleImage.tag;
  59. if (emTag == tapTag) {
  60. return;
  61. }
  62. UIImageView *emImg = [self viewWithTag:emTag];
  63. UIImageView *tapImg = puzzleImage;
  64. CGFloat emMinX = floor(CGRectGetMinX(emImg.frame));
  65. CGFloat emMaxX = floor(CGRectGetMaxX(emImg.frame));
  66. CGFloat emMinY = floor(CGRectGetMinY(emImg.frame));
  67. CGFloat emMaxY = floor(CGRectGetMaxY(emImg.frame));
  68. CGFloat tapMinX = floor(CGRectGetMinX(defaultFrame));
  69. CGFloat tapMaxX = floor(CGRectGetMaxX(defaultFrame));
  70. CGFloat tapMinY = floor(CGRectGetMinY(defaultFrame));
  71. CGFloat tapMaxY = floor(CGRectGetMaxY(defaultFrame));
  72. BOOL isExchange = NO;
  73. if ((tapMinX == emMinX) &&
  74. fabs((tapMaxY + _itemSpace) - emMinY) < 5*xkScale){
  75. isExchange = YES;
  76. }
  77. else if ((tapMinX == emMinX) &&
  78. fabs((emMaxY + _itemSpace) - tapMinY) < 5*xkScale){
  79. isExchange = YES;
  80. }
  81. else if ((tapMinY == emMinY) &&
  82. fabs((tapMaxX + _itemSpace) - emMinX) < 5*xkScale){
  83. isExchange = YES;
  84. }
  85. else if ((tapMinY == emMinY) &&
  86. fabs((emMaxX + _itemSpace) - tapMinX) < 5*xkScale){
  87. isExchange = YES;
  88. }
  89. else{
  90. isExchange = NO;
  91. }
  92. CGRect emRect = CGRectMake(CGRectGetMinX(emImg.frame),
  93. CGRectGetMinY(emImg.frame),
  94. CGRectGetWidth(emImg.frame),
  95. CGRectGetHeight(emImg.frame));
  96. if (isExchange) {
  97. NSLog(@"允许交换");
  98. [UIView animateWithDuration:0.3 animations:^{
  99. _allowJoint = NO;
  100. emImg.frame = defaultFrame;
  101. tapImg.frame = emRect;
  102. } completion:^(BOOL finished) {
  103. NSInteger accesTap = [tapImg.accessibilityValue integerValue];
  104. NSInteger accesEm = [emImg.accessibilityValue integerValue];
  105. [_puzzleArray exchangeObjectAtIndex:(accesTap - 1) withObjectAtIndex:(accesEm - 1)];
  106. tapImg.accessibilityValue = [NSString stringWithFormat:@"%ld",accesEm];
  107. emImg.accessibilityValue = [NSString stringWithFormat:@"%ld",accesTap];
  108. _allowJoint = YES;
  109. if ([self isPuzzleImageFinish]) {
  110. NSLog(@"拼图完成");
  111. [self puzzleImageFinishHandler];
  112. }
  113. else{
  114. NSLog(@"继续加油");
  115. }
  116. }];
  117. }
  118. else{
  119. NSLog(@"不允许交换");
  120. ///原图归位
  121. [UIView animateWithDuration:0.3 animations:^{
  122. _allowJoint = NO;
  123. tapImg.frame = defaultFrame;
  124. } completion:^(BOOL finished) {
  125. _allowJoint = YES;
  126. }];
  127. }
  128. }

判断拼图是否完成

  1. - (BOOL)isPuzzleImageFinish{
  2. NSString *order = [_orderArray componentsJoinedByString:@""];
  3. NSString *after = [_puzzleArray componentsJoinedByString:@""];
  4. return [order isEqualToString:after];
  5. }

效果

   

 

原文链接:http://www.cnblogs.com/wangkejia/p/14610702.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号