思路要求设计思路是类似手持拼图游戏,拼图需求要求有一块为空白版,作为移动方块的预留位置用,通过选择图片后在起初对所有图像方块随机打乱顺序时,发现随机打乱顺序,没办法拼图完成,拼图移动是空白快最临近的上...
思路
要求设计思路是类似手持拼图游戏,拼图需求要求有一块为空白版,作为移动方块的预留位置用,通过选择图片后在起初对所有图像方块随机打乱顺序时,发现随机打乱顺序,没办法拼图完成,拼图移动是空白快最临近的上下左右四个图像块的移动,在打乱顺序的时候,也要按照这个算法逻辑实现,才能拼图完成;
另外逻辑实现上,用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];
}
效果
沃梦达教程
本文标题为:iOS-宫格拼图
猜你喜欢
- Android实现轮询的三种方式 2023-02-17
- 最好用的ios数据恢复软件:PhoneRescue for Mac 2023-09-14
- Android MaterialButton使用实例详解(告别shape、selector) 2023-06-16
- iOS 对当前webView进行截屏的方法 2023-03-01
- Android studio实现动态背景页面 2023-05-23
- SurfaceView播放视频发送弹幕并实现滚动歌词 2023-01-02
- Flutter实现底部和顶部导航栏 2022-08-31
- 详解flutter engine 那些没被释放的东西 2022-12-04
- 作为iOS开发,这道面试题你能答出来,说明你基础很OK! 2023-09-14
- Android实现监听音量的变化 2023-03-30
