iPhone アプリ磁石あそび

磁石で、赤と青の点をあつめて遊ぶiPhoneアプリを書いてみます。磁石の青い方の先端には赤い点がくっついて、磁石の赤い方の先端には青い点がくっつきます。


動作イメージ
XcodeからiOS6 iPhone Simulatorで動かすとこんな感じになります。

ポイント
UIPanGestureRecognizerを使う際に、触った部分を中心に移動させたいので、stateがbeginの時に磁石のanchorPointを変更して、移動はlayerのpositionで行いました。あと、磁石の先端部分に赤、青の点が触れたかどうかの判定を行っています。触れていたら、rootのviewから磁石のViewに点を移すことで、くっついたように見せてみました。

サンプルコード

#import “ViewController.h”

#import <QuartzCore/QuartzCore.h>

@interface ViewController () {

    UIView *magnet;

    UIView *redPoint;

    UIView *bluePoint;

    NSMutableArray *blueChips;

    NSMutableArray *redChips;

}

@end

@implementation ViewController

– (void)viewDidLoad

{

    [super viewDidLoad];

    self.view.backgroundColor = [UIColor whiteColor];

    [self createMagnet];

    [self scatterChips];

    [self createBtn];

}

– (void)createMagnet

{

    magnet = [[UIView alloc] initWithFrame:CGRectMake(100, 400, 100, 100)];

    [self.view addSubview:magnet];

    

    // blue part

    UIBezierPath *path = [UIBezierPath bezierPath];

    [path moveToPoint:CGPointMake(10, 0)];

    [path addQuadCurveToPoint:CGPointMake(50, 100) controlPoint:CGPointMake(0, 100)];

    CAShapeLayer *sl = [[CAShapeLayer alloc] init];

    sl.fillColor = [UIColor clearColor].CGColor;

    sl.strokeColor = [UIColor blueColor].CGColor;

    sl.lineWidth = 20;

    sl.path = path.CGPath;

    [magnet.layer addSublayer:sl];

    

    // red part

    path = [UIBezierPath bezierPath];

    [path moveToPoint:CGPointMake(90, 0)];

    [path addQuadCurveToPoint:CGPointMake(50, 100) controlPoint:CGPointMake(100, 100)];

    sl = [[CAShapeLayer alloc] init];

    sl.fillColor = [UIColor clearColor].CGColor;

    sl.strokeColor = [UIColor redColor].CGColor;

    sl.lineWidth = 20;

    sl.path = path.CGPath;

    [magnet.layer addSublayer:sl];

    

    redPoint = [[UIView alloc] initWithFrame:CGRectMake(-2, –1, 22, 30)];

    redPoint.backgroundColor = [UIColor lightGrayColor];

    redPoint.transform = CGAffineTransformMakeRotation(M_PI * 0.02);

    [magnet addSubview:redPoint];

    

    bluePoint = [[UIView alloc] initWithFrame:CGRectMake(80, –1, 22, 30)];

    bluePoint.backgroundColor = [UIColor lightGrayColor];

    bluePoint.transform = CGAffineTransformMakeRotation(-M_PI * 0.02);

    [magnet addSubview:bluePoint];

    

    UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(move:)];

    [magnet addGestureRecognizer:pan];

}

– (void)scatterChips

{

    redChips = [[NSMutableArray alloc] init];

    blueChips = [[NSMutableArray alloc] init];

    

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

        int type = arc4random() % 4;   // 0 or 1: skip  2: red, 3: blue

        float x = (i % 30) * 10 + 10;

        float y = (i / 30) * 10 + 10;

        

        switch (type) {

            case 2:

            {

                UIView *red = [[UIView alloc] initWithFrame:CGRectMake(x, y, 5, 5)];

                red.backgroundColor = [UIColor redColor];

                [self.view addSubview:red];

                [redChips addObject:red];

                break;

            }

            case 3:

            {

                UIView *blue = [[UIView alloc] initWithFrame:CGRectMake(x, y, 5, 5)];

                blue.backgroundColor = [UIColor blueColor];

                [self.view addSubview:blue];

                [blueChips addObject:blue];

                break;

            }

            default:

                break;

        }

    }

}

– (void)createBtn

{

    UILabel *btn = [[UILabel alloc] initWithFrame:CGRectMake(220, 480, 80, 50)];

    btn.text = @”reset”;

    btn.textAlignment = NSTextAlignmentCenter;

    btn.font = [UIFont systemFontOfSize:30];

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

    btn.layer.borderWidth = 1;

    [self.view addSubview:btn];

    

    btn.userInteractionEnabled = YES;

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

    [btn addGestureRecognizer:tap];

}

– (void)move:(UIPanGestureRecognizer*)gr

{

    CGPoint p = [gr locationInView:self.view];

    CGPoint local = [gr locationInView:gr.view];

    

    if (gr.state == UIGestureRecognizerStateBegan) {

        float x = local.x / gr.view.bounds.size.width;

        float y = local.y / gr.view.bounds.size.height;

        gr.view.layer.anchorPoint = CGPointMake(x, y);

    }

    

    [self check];

    

    gr.view.layer.position = p;

}

– (void)check

{

    CGRect redMag = [magnet convertRect:redPoint.frame toView:self.view];

    for (UIView *v in redChips) {

        if (CGRectIntersectsRect(redMag, v.frame)) {

            v.frame = [magnet convertRect:v.frame fromView:self.view];

            v.alpha = 0;

            [self performSelector:@selector(connectMagnet:) withObject:v afterDelay:0];

        }

    }

    

    CGRect blueMag = [magnet convertRect:bluePoint.frame toView:self.view];

    for (UIView *v in blueChips) {

        if (CGRectIntersectsRect(blueMag, v.frame)) {

            v.frame = [magnet convertRect:v.frame fromView:self.view];

            v.alpha = 0;

            [self performSelector:@selector(connectMagnet:) withObject:v afterDelay:0];

        }

    }

}

– (void)connectMagnet:(UIView *)v

{

    [UIView animateWithDuration:0.2 animations:^{

        v.transform = CGAffineTransformMakeScale(2, 2);

    } completion:^(BOOL finished) {

        v.transform = CGAffineTransformIdentity;

    }];

    

    v.alpha = 1.0;

    [magnet addSubview:v];

    [redChips removeObject:v];

    [blueChips removeObject:v];

}

– (void)reset

{

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

        [v removeFromSuperview];

    }

    

    [self createMagnet];

    [self scatterChips];

    [self createBtn];

}

– (void)didReceiveMemoryWarning

{

    [super didReceiveMemoryWarning];

    // Dispose of any resources that can be recreated.

}

@end