• iOS-宫格拼图


    思路

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

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

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

    实现

    变量及相关初始化

    ///次序,用来排序
    @property (nonatomic,strong) NSMutableArray * orderArray;
    ///次序,用来乱序打乱拼图
    @property (nonatomic,strong) NSMutableArray * disorderArray;
    ///次序,用来拼图移动位置记录
    @property (nonatomic,strong) NSMutableArray * puzzleArray;
    ///图片原图
    @property (nonatomic,strong) UIImage * puzzleImage;
    ///行、列数【难度】
    @property (nonatomic,assign) NSInteger rows;
    ///方块图间距
    @property (nonatomic,assign) CGFloat itemSpace;
    ///四周边距
    @property (nonatomic,assign) CGFloat marginSpace;
    
    ///是否允许拼图
    @property (nonatomic,assign) BOOL allowJoint;
    ///拖动拼图
    @property (nonatomic,strong) UIImageView * panImageView;
    ///拖动拼图Frame
    @property (nonatomic,assign) CGRect  panImageFrame;
    - (instancetype)initWithFrame:(CGRect)frame
                             rows:(NSInteger)rows
                      puzzleImage:(UIImage *)puzzleImage{
        self = [super initWithFrame:frame];
        if (self) {
            _rows = rows;
            _puzzleImage = puzzleImage;
            [self setupPP];
        }
        return self;
    }
    
    - (void)setupPP{
        self.userInteractionEnabled = NO;
        _allowJoint = YES;
        _orderArray = [NSMutableArray array];
        _disorderArray = [NSMutableArray array];
        _puzzleArray = [NSMutableArray array];
        
    //    _rows = 6;
        _itemSpace = floor(_rows*xkScale/(_rows/2));
        _marginSpace = floor(_rows*xkScale);
        
        self.backgroundColor = [UIColor whiteSmoke];
        
        
        [self setupOrderArray:(_rows * _rows)];
        
        ///如果图片的大小大于当前宽度,就压缩
        if (_puzzleImage.size.width > CGRectGetWidth(self.frame)) {
            UIGraphicsBeginImageContextWithOptions(self.bounds.size, NO, 1);
            [_puzzleImage drawInRect:CGRectMake(0,0,self.bounds.size.width,self.bounds.size.height)];
            UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
            UIGraphicsEndImageContext();
            _puzzleImage = newImage;
        }
      
        CGFloat pWidth = (CGRectGetWidth(self.frame)  - _itemSpace*(_rows-1) - _marginSpace*2)/_rows;
        CGFloat pHeight = (CGRectGetHeight(self.frame)  - _itemSpace*(_rows-1) - _marginSpace*2)/_rows;
        
        for (int i = 0; i < _rows; i ++) {
            for (int j = 0; j < _rows; j ++) {
                NSInteger order = _rows * i + j;
                NSLog(@"order = %ld",order);
                /*
                NSInteger indexes_x = 0;
                NSInteger indexes_y = 0;
                
                if (order < (_rows *_rows) - 1) {
                    NSInteger location = [_disorderArray[order] integerValue];
                    indexes_y = location/_rows;///第几行
                    indexes_x = location%_rows;///第几个
                }
                else{
                    indexes_y = _rows - 1;
                    indexes_x = _rows - 1;
                }
                CGFloat x_img = _marginSpace + (indexes_x)*(pWidth + _itemSpace);
                CGFloat y_img = _marginSpace + (indexes_y)*(pHeight + _itemSpace);
                */
                CGFloat x = _marginSpace + (j)*(pWidth + _itemSpace);
                CGFloat y = _marginSpace + (i)*(pHeight + _itemSpace);
                
    
                UIImageView *imgView = [self puzzleImageWithFrame:CGRectMake(x, y, pWidth, pHeight)];
                //将UIImage转化成CGImage
                CGImageRef imageRef = CGImageCreateWithImageInRect(_puzzleImage.CGImage, CGRectMake(x, y, pWidth, pHeight));
                //将CGImage转化成UIImage
                UIImage *imageNew = [UIImage imageWithCGImage:imageRef];
                imgView.image = imageNew;
                ///用来标记view
                imgView.tag = order + 1;
                ///用来记录view位置
                imgView.accessibilityValue = [NSString stringWithFormat:@"%ld",order + 1];
                [self addSubview:imgView];
                
                if (imgView.tag == (_rows * _rows)) {
                    imgView.image = [UIImage imageNamed:@"pp_chunk"];
                    imgView.backgroundColor = [UIColor whiteSmoke];
                }
            }
        }
        
        dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, 1.5 * NSEC_PER_SEC);
        dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
            [self startDisorganizePuzzleImage];
        });
    }
    - (void)setupOrderArray:(NSInteger)count{
        for (int i = 1; i<=count; i ++) {
            [_orderArray addObject:[NSString stringWithFormat:@"%d",i]];
            [_disorderArray addObject:[NSString stringWithFormat:@"%d",i]];
            [_puzzleArray addObject:[NSString stringWithFormat:@"%d",i]];
            
        }
    }

    打乱拼图顺序

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

    - (void)setupDisorganizePuzzleImageNumber:(NSInteger)number{
        if (number <= 0) {
            self.userInteractionEnabled = YES;
            return;
        }
        self.userInteractionEnabled = NO;
        ///获取空白格
        UIImageView *emImg = [self viewWithTag:(_rows * _rows)];
        ///获取空白格的位置
        NSInteger emLocation = [emImg.accessibilityValue integerValue];
        ///通过空白格位置,获取四周可以移动的格子的位置与tag
        NSMutableArray *arrayLoc = [NSMutableArray array];
        NSInteger  upLocation = emLocation - _rows;
        NSInteger  downLocation = emLocation + _rows;
        NSInteger  leftLocation = emLocation - 1;
        NSInteger  righjtLocation = emLocation + 1;
        if (upLocation > 0) {///
            [arrayLoc addObject:@(upLocation)];
        }
        if (downLocation <= (_rows*_rows)) {///
            [arrayLoc addObject:@(downLocation)];
        }
        if (leftLocation%_rows != 0 && leftLocation <= (_rows*_rows)) {///
            [arrayLoc addObject:@(leftLocation)];
        }
        if (righjtLocation%_rows != 1 && righjtLocation <= (_rows*_rows)) {///
            [arrayLoc addObject:@(righjtLocation)];
        }
        ///随机获取一个转移目标
        NSInteger random = arc4random() % arrayLoc.count;
        NSInteger targetLocation = [arrayLoc[random] integerValue];
        NSInteger targetIndex = [_disorderArray indexOfObject:[NSString stringWithFormat:@"%ld",targetLocation]];
        ///获取目标试图
        UIImageView *targetImg = [self viewWithTag:targetIndex + 1];
        if (targetImg) {
            CGRect targetRect = CGRectMake(CGRectGetMinX(targetImg.frame),
                                           CGRectGetMinY(targetImg.frame),
                                           CGRectGetWidth(targetImg.frame),
                                           CGRectGetHeight(targetImg.frame));
            CGRect emRect = CGRectMake(CGRectGetMinX(emImg.frame),
                                       CGRectGetMinY(emImg.frame),
                                       CGRectGetWidth(emImg.frame),
                                       CGRectGetHeight(emImg.frame));
            [UIView animateWithDuration:0.01 animations:^{
                emImg.frame = targetRect;
                targetImg.frame = emRect;
            } completion:^(BOOL finished) {
                ///处理交换【打乱次序】
                NSInteger emIndex = [_disorderArray indexOfObject:emImg.accessibilityValue];
                [_disorderArray exchangeObjectAtIndex:(targetIndex) withObjectAtIndex:(emIndex)];
                
                ///切换保存顺序【拼图】
                NSInteger accesTarget = [targetImg.accessibilityValue integerValue] - 1;
                NSInteger accesEm = [emImg.accessibilityValue integerValue] - 1;
                [_puzzleArray exchangeObjectAtIndex:(accesTarget) withObjectAtIndex:(accesEm)];
                
                targetImg.accessibilityValue = [NSString stringWithFormat:@"%ld",emLocation];
                emImg.accessibilityValue = [NSString stringWithFormat:@"%ld",targetLocation];
                
                
                [self setupDisorganizePuzzleImageNumber:number - 1];
            }];
        }
    }

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

    ///拼图点击事件
    - (void)puzzleImageTapClick:(UITapGestureRecognizer *)tap{
        NSInteger tapTag = tap.view.tag;
        UIImageView *tapImg = [self viewWithTag:tapTag];
        [self puzzleImageTapGestureHandler:tapImg];
    }
    
    ///点击手势操作
    - (void)puzzleImageTapGestureHandler:(UIImageView *)puzzleImage{
        if (!_allowJoint) {
            return;
        }
        NSInteger emTag = (_rows * _rows);
        NSInteger tapTag = puzzleImage.tag;
        if (emTag == tapTag) {
            return;
        }
        UIImageView *emImg = [self viewWithTag:emTag];
        UIImageView *tapImg = puzzleImage;
        
        CGFloat emMinX = floor(CGRectGetMinX(emImg.frame));
        CGFloat emMaxX = floor(CGRectGetMaxX(emImg.frame));
        CGFloat emMinY = floor(CGRectGetMinY(emImg.frame));
        CGFloat emMaxY = floor(CGRectGetMaxY(emImg.frame));
        
        CGFloat tapMinX = floor(CGRectGetMinX(tapImg.frame));
        CGFloat tapMaxX = floor(CGRectGetMaxX(tapImg.frame));
        CGFloat tapMinY = floor(CGRectGetMinY(tapImg.frame));
        CGFloat tapMaxY = floor(CGRectGetMaxY(tapImg.frame));
     
        BOOL isExchange = NO;
        if ((tapMinX == emMinX) &&
            fabs((tapMaxY + _itemSpace) - emMinY) < 5*xkScale){
            isExchange = YES;
        }
        else if ((tapMinX == emMinX) &&
                 fabs((emMaxY + _itemSpace) - tapMinY) < 5*xkScale){
            isExchange = YES;
        }
        else if ((tapMinY == emMinY) &&
                 fabs((tapMaxX + _itemSpace) - emMinX) < 5*xkScale){
            isExchange = YES;
        }
        else if ((tapMinY == emMinY) &&
                 fabs((emMaxX + _itemSpace) - tapMinX) < 5*xkScale){
            isExchange = YES;
        }
        else{
            isExchange = NO;
        }
        
        CGRect tapRect = CGRectMake(CGRectGetMinX(tapImg.frame),
                                    CGRectGetMinY(tapImg.frame),
                                    CGRectGetWidth(tapImg.frame),
                                    CGRectGetHeight(tapImg.frame));
        CGRect emRect = CGRectMake(CGRectGetMinX(emImg.frame),
                                   CGRectGetMinY(emImg.frame),
                                   CGRectGetWidth(emImg.frame),
                                   CGRectGetHeight(emImg.frame));
        if (isExchange) {
            NSLog(@"允许交换");
            [UIView animateWithDuration:0.3 animations:^{
                _allowJoint = NO;
                emImg.frame = tapRect;
                tapImg.frame = emRect;
            } completion:^(BOOL finished) {
                
                
                NSInteger accesTap = [tapImg.accessibilityValue integerValue];
                NSInteger accesEm = [emImg.accessibilityValue integerValue];
                ///因为accessibilityValue与tag一样,索引需要减1
                [_puzzleArray exchangeObjectAtIndex:(accesTap - 1) withObjectAtIndex:(accesEm - 1)];
                tapImg.accessibilityValue = [NSString stringWithFormat:@"%ld",accesEm];
                emImg.accessibilityValue = [NSString stringWithFormat:@"%ld",accesTap];
                _allowJoint = YES;
                if ([self isPuzzleImageFinish]) {
                    NSLog(@"拼图完成");
                    [self puzzleImageFinishHandler];
                }
                else{
                    NSLog(@"继续加油");
                }
                
            }];
        }
        else{
            NSLog(@"不允许交换");
        }
    }

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

    /// 拼图拖动
    - (void)puzzleImagePanGesture:(UIPanGestureRecognizer *)pan{
        _panImageView = (UIImageView *)pan.view;
        [self bringSubviewToFront:pan.view];
        if (_panImageView.tag == (_rows * _rows)) {///空白格
            
        }
        else{
            if (pan.state == UIGestureRecognizerStateBegan) {
                _panImageFrame = pan.view.frame;
                _panImageView = (UIImageView *)pan.view;
            }
            else if (pan.state == UIGestureRecognizerStateChanged){
                //获取偏移量
                CGPoint transP = [pan translationInView:pan.view];
                // 移动图片控件
                CGRect tapRect = CGRectMake(CGRectGetMinX(pan.view.frame) + transP.x,
                                            CGRectGetMinY(pan.view.frame) + transP.y,
                                            CGRectGetWidth(pan.view.frame),
                                            CGRectGetHeight(pan.view.frame));
                pan.view.frame = tapRect;
                // 复位,表示相对上一次位置复位重置
                [pan setTranslation:CGPointZero inView:pan.view];
            }
            else if (pan.state == UIGestureRecognizerStateEnded){
                if (!_allowJoint) {
                    [UIView animateWithDuration:0.1 animations:^{
                        _allowJoint = NO;
                        _panImageView.frame = _panImageFrame;
                    } completion:^(BOOL finished) {
                        _allowJoint = YES;
                    }];
                    return;
                }
                
                NSInteger emTag = (_rows * _rows);
                UIImageView *emImg = [self viewWithTag:emTag];
                CGPoint point1 = _panImageView.center;
                CGPoint point2 = emImg.center;
                CGFloat distance = sqrt(pow((point1.x - point2.x), 2) + pow((point1.y - point2.y), 2));
                if (distance <= CGRectGetHeight(_panImageFrame)/2) {///中心点相差小于20的,允许判断是否交换位置
                    [self puzzleImagePanGestureHandler:_panImageView defaultFrame:_panImageFrame];
                }
                else{///放回原来位置
                    [UIView animateWithDuration:0.1 animations:^{
                        _allowJoint = NO;
                        _panImageView.frame = _panImageFrame;
                    } completion:^(BOOL finished) {
                        _allowJoint = YES;
                    }];
                }
                
            }
            else{
                
            }
        }
    }
    
    ///拖动手势操作
    - (void)puzzleImagePanGestureHandler:(UIImageView *)puzzleImage defaultFrame:(CGRect)defaultFrame{
        
        NSInteger emTag = (_rows * _rows);
        NSInteger tapTag = puzzleImage.tag;
        if (emTag == tapTag) {
            return;
        }
        UIImageView *emImg = [self viewWithTag:emTag];
        UIImageView *tapImg = puzzleImage;
        
        CGFloat emMinX = floor(CGRectGetMinX(emImg.frame));
        CGFloat emMaxX = floor(CGRectGetMaxX(emImg.frame));
        CGFloat emMinY = floor(CGRectGetMinY(emImg.frame));
        CGFloat emMaxY = floor(CGRectGetMaxY(emImg.frame));
        
        CGFloat tapMinX = floor(CGRectGetMinX(defaultFrame));
        CGFloat tapMaxX = floor(CGRectGetMaxX(defaultFrame));
        CGFloat tapMinY = floor(CGRectGetMinY(defaultFrame));
        CGFloat tapMaxY = floor(CGRectGetMaxY(defaultFrame));
       
        BOOL isExchange = NO;
        if ((tapMinX == emMinX) &&
            fabs((tapMaxY + _itemSpace) - emMinY) < 5*xkScale){
            isExchange = YES;
        }
        else if ((tapMinX == emMinX) &&
                 fabs((emMaxY + _itemSpace) - tapMinY) < 5*xkScale){
            isExchange = YES;
        }
        else if ((tapMinY == emMinY) &&
                 fabs((tapMaxX + _itemSpace) - emMinX) < 5*xkScale){
            isExchange = YES;
        }
        else if ((tapMinY == emMinY) &&
                 fabs((emMaxX + _itemSpace) - tapMinX) < 5*xkScale){
            isExchange = YES;
        }
        else{
            isExchange = NO;
        }
        
        CGRect emRect = CGRectMake(CGRectGetMinX(emImg.frame),
                                   CGRectGetMinY(emImg.frame),
                                   CGRectGetWidth(emImg.frame),
                                   CGRectGetHeight(emImg.frame));
        if (isExchange) {
            NSLog(@"允许交换");
            [UIView animateWithDuration:0.3 animations:^{
                _allowJoint = NO;
                emImg.frame = defaultFrame;
                tapImg.frame = emRect;
            } completion:^(BOOL finished) {
                NSInteger accesTap = [tapImg.accessibilityValue integerValue];
                NSInteger accesEm = [emImg.accessibilityValue integerValue];
                
                [_puzzleArray exchangeObjectAtIndex:(accesTap - 1) withObjectAtIndex:(accesEm - 1)];
                tapImg.accessibilityValue = [NSString stringWithFormat:@"%ld",accesEm];
                emImg.accessibilityValue = [NSString stringWithFormat:@"%ld",accesTap];
                _allowJoint = YES;
                if ([self isPuzzleImageFinish]) {
                    NSLog(@"拼图完成");
                    [self puzzleImageFinishHandler];
                }
                else{
                    NSLog(@"继续加油");
                }
            }];
        }
        else{
            NSLog(@"不允许交换");
            ///原图归位
            [UIView animateWithDuration:0.3 animations:^{
                _allowJoint = NO;
                tapImg.frame = defaultFrame;
            } completion:^(BOOL finished) {
                _allowJoint = YES;
            }];
            
        }
    }

    判断拼图是否完成

    - (BOOL)isPuzzleImageFinish{
        NSString *order = [_orderArray componentsJoinedByString:@""];
        NSString *after = [_puzzleArray componentsJoinedByString:@""];
        return [order isEqualToString:after];
    }

    效果

       

  • 相关阅读:
    java
    java
    java
    java
    java
    java
    java
    java
    sed命令的用法
    linux系统产生随机数的6种方法
  • 原文地址:https://www.cnblogs.com/wangkejia/p/14610702.html
Copyright © 2020-2023  润新知