画面をタッチして、入れ替え、回転であそぶパズル

(XcodeのiOS6 iPhone Simulatorで試しています。)

ポイント

・パネルを二つタップすると入れ替え

・同じパネルをタップすると回転

・タッチしたパネルに色を重ねるために、UIViewでBlendModeMultiply

サンプルコード

ViewController.m

#import “ViewController.h”

#import <QuartzCore/QuartzCore.h>

@interface Piece : UIView

@property (nonatomic, strong) UIImage *image;

@property (nonatomic, strong) UIColor *overlay;

@end

@implementation Piece

@synthesize image, overlay;

– (void)setOverlay:(UIColor *)aOverlay

{

    overlay = aOverlay;

    [self setNeedsDisplay];

}

– (void) drawRect:(CGRect)area

{

    CGContextRef context = UIGraphicsGetCurrentContext();

    CGContextSaveGState(context);

    

    // CGContextDrawImageを使うと上下反転してしまうからこっちに。

    [self.image drawInRect:self.bounds];

    

    CGContextSetBlendMode (context, kCGBlendModeMultiply);

    CGContextSetFillColor(context, CGColorGetComponents(overlay.CGColor));

    CGContextFillRect (context, self.bounds);

    CGContextRestoreGState(context);

}

@end

@interface ViewController () {

    Piece *onePiece;

}

@end

@implementation ViewController

– (void)viewDidLoad

{

    [super viewDidLoad];

    [self.view setBackgroundColor:[UIColor blackColor]];

    

    UIImage *resized = [self resize:[UIImage imageNamed:@”rocket.jpg”] scaledToSize:CGSizeMake(320, 320)];

    onePiece = [[Piece alloc] initWithFrame:CGRectMake(0, 0, 320, 320)];

    onePiece.image = resized;

    onePiece.overlay = [UIColor clearColor];

    [self.view addSubview:onePiece];

    

    // レイヤーのマスクで丸角

    CAShapeLayer * shapeLayer = [CAShapeLayer layer];

    shapeLayer.backgroundColor = [UIColor clearColor].CGColor;

    shapeLayer.path = [UIBezierPath bezierPathWithRoundedRect:onePiece.bounds byRoundingCorners: UIRectCornerAllCorners cornerRadii:CGSizeMake(20.0, 20.0)].CGPath;

    onePiece.layer.masksToBounds = YES;

    onePiece.layer.mask = shapeLayer;

    shapeLayer.frame = onePiece.layer.bounds;

    

    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(startTap:)];

    [onePiece addGestureRecognizer:tap];

}

– (void)startTap:(UITapGestureRecognizer*)gr

{

    // 元の絵を上に小さく表示

    [UIView animateWithDuration:0.5 animations:^{

        onePiece.transform = CGAffineTransformMakeScale(0.25, 0.25);

        onePiece.center = CGPointMake(160, 50);

    }];

    

    // 4×4に分割する

    for (int i=0; i<4; i++) {

        for (int j=0; j<4; j++) {

            [self createPiece:CGRectMake(i*80, j*80, 80, 80) image:onePiece.image];

        }

    }

    

    // シャッフルして動かす

    // 配列の中身をランダムに入れ替え

    NSMutableArray *array = [[NSMutableArray alloc] init];

    for (UIView *v in self.view.subviews) {

        if (v.tag == 1) {

            [array addObject:v];

        }

    }

    int count = [array count];

    for (int i = count – 1; i > 0; i–) {

        int randomNum = arc4random() % i;

        [array exchangeObjectAtIndex:i withObjectAtIndex:randomNum];

    }

    // シャッフル後の位置に動かす

    for (int i=0; i<[array count]; i++) {

        float x = 80 * (i / 4) + 40;

        float y = 80 * (i % 4) + 140;

        [UIView animateWithDuration:0.3 delay:0.1 * i options:UIViewAnimationCurveEaseIn animations:^{

            UIView *v = [array objectAtIndex:i];

            // 場所

            v.center = CGPointMake(x, y);

            // 回転

            float angle = (arc4random() % 4) * 0.5 * M_PI;

            v.transform = CGAffineTransformMakeRotation(angle);

        } completion:^(BOOL finished) {}];

    }

}

#pragma mark – image util

– (UIImage *)resize:(UIImage *)image scaledToSize:(CGSize)newSize {

    UIGraphicsBeginImageContext(newSize);

    [image drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];

    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();

    UIGraphicsEndImageContext();

    return newImage;

}

– (void)createPiece:(CGRect)rect image:(UIImage*)origin

{

    CGImageRef imageRef = CGImageCreateWithImageInRect([origin CGImage], rect);

    Piece *piece = [[Piece alloc] initWithFrame:rect];

    // 表示位置を少し下げる

    piece.center = CGPointMake(piece.center.x, piece.center.y + 100);

    piece.image = [UIImage imageWithCGImage:imageRef];

    piece.overlay = [UIColor clearColor];

    piece.layer.borderColor = [UIColor blackColor].CGColor;

    piece.layer.borderWidth = 2.0;

    piece.tag = 1;

    [self.view addSubview:piece];

    

    // こっちはlayer.cornerRadiusで丸角

    piece.layer.cornerRadius = 10.0;

    piece.layer.masksToBounds = YES;

    

    CGImageRelease(imageRef);

    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapPanel:)];

    [piece addGestureRecognizer:tap];

}

– (void)tapPanel:(UITapGestureRecognizer*)gr

{

    static Piece *firstTap;

    

    UIColor *color = [UIColor colorWithRed:0 green:0 blue:1.0 alpha:0.5];

    

    Piece *piece = (Piece*)gr.view;

    if (!firstTap) {

        firstTap = piece;

        piece.overlay = color;

        return;

    }

    

    if (firstTap == gr.view) {

        [UIView animateWithDuration:0.3 animations:^{

            piece.transform = CGAffineTransformRotate(gr.view.transform, M_PI * 0.5);

        } completion:^(BOOL finished) {

            firstTap.overlay = [UIColor clearColor];

            piece.overlay = [UIColor clearColor];

            firstTap = nil;

        }];

    } else {

        CGPoint p1 = firstTap.center;

        CGPoint p2 = piece.center;

        piece.overlay = color;

        [UIView animateWithDuration:0.3 animations:^{

            firstTap.center = p2;

            piece.center = p1;

        } completion:^(BOOL finished) {

            firstTap.overlay = [UIColor clearColor];

            piece.overlay = [UIColor clearColor];

            firstTap = nil;

        }];

    }

}

– (void)didReceiveMemoryWarning

{

    [super didReceiveMemoryWarning];

}

@end