iPhoneゲーム カギ開け

ダイアルをゆびでくるくるまわせるよ。赤いところに合わせてカギを開けてみよう。という感じで、ダイアル式ロックのiPhoneゲームアプリの作成方法を書いてみます。

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

ポイント
ダイアルにUIPanGestureRecognizerを設定し、最初にタッチした位置と、指を動かした位置からatan2fを使って角度を計算しています。その角度分だけTransform Rotateをかければくるくる回ります。指を離したときに赤いメモリのところが、x = 0, y = centerの位置にきていたらカギが開くようにしました。カギのワイヤー部分はUIBezierPathで書いています。

サンプルコード

#import “ViewController.h”

#import <QuartzCore/QuartzCore.h>

#define UIColorHex(rgbValue) [UIColor colorWithRed:((float)((rgbValue & 0xFF0000) >> 16))/255.0 green:((float)((rgbValue & 0xFF00) >> 8))/255.0 blue:((float)(rgbValue & 0xFF))/255.0 alpha:1.0]

@interface ViewController () {

    UIView *wire;

    UIView *dial;

    UIView *bigRedMark;

    UIView *redMark;

}

@end

@implementation ViewController

– (void)viewDidLoad

{

    [super viewDidLoad];

    self.view.backgroundColor = [self colorTheme:4];

    

    [self createWire];

    [self createDial];

    [self createTargetMark];

    [self showQuestion];

}

– (void)createWire

{

    UIBezierPath *path = [UIBezierPath bezierPath];

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

    [path addLineToPoint:CGPointMake(0, 50)];

    [path addArcWithCenter:CGPointMake(50, 50) radius:50 startAngle:M_PI endAngle:0 clockwise:YES];

    [path addLineToPoint:CGPointMake(100, 100)];

    CAShapeLayer *sl = [[CAShapeLayer alloc] initWithLayer:wire.layer];

    sl.fillColor = [UIColor clearColor].CGColor;

    sl.strokeColor = [self colorTheme:1].CGColor;

    sl.lineWidth = 20;

    sl.path = path.CGPath;

    

    wire = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 200)];

    wire.center = CGPointMake(self.view.bounds.size.width/2.0, self.view.bounds.size.height/2.070);

    wire.backgroundColor = [UIColor clearColor];

    [wire.layer addSublayer:sl];

    [self.view addSubview:wire];

}

– (void)createDial

{

    dial = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 200, 200)];

    dial.layer.cornerRadius = 100;

    dial.center = CGPointMake(self.view.bounds.size.width/2.0, self.view.bounds.size.height/2.0);

    dial.backgroundColor = [self colorTheme:0];

    [self.view addSubview:dial];

    

    // dial scale

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

        UIView *line;

        if (i % 5 != 0) {

            line = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 3)];

            line.layer.anchorPoint = CGPointMake(100.0/10.0, 0.5);

        } else {

            line = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 15, 4)];

            line.layer.anchorPoint = CGPointMake(100.0/15.0, 0.5);

        }

        line.backgroundColor = [self colorTheme:2];

        line.layer.position = CGPointMake(100, 100);

        line.transform = CGAffineTransformMakeRotation(i * M_PI/20.0);

        [dial addSubview:line];

        

        line.tag = i+1;

    }

    

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

    pan.maximumNumberOfTouches = 1;

    [dial addGestureRecognizer:pan];

}

– (void)createTargetMark

{

    bigRedMark = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 30, 10)];

    bigRedMark.backgroundColor = [self colorTheme:3];

    bigRedMark.center = CGPointMake(self.view.bounds.size.width/2.0115, self.view.bounds.size.height/2.0);

    [self.view addSubview:bigRedMark];

}

– (void)showQuestion

{

    int q = arc4random() % 40 + 1;

    redMark = [dial viewWithTag:q];

    redMark.backgroundColor = [self colorTheme:3];

}

– (void)turn:(UIPanGestureRecognizer*)gr

{    

    static float previousAngle;

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

    float angle = atan2f(p.ydial.center.y, p.xdial.center.x);

    if (gr.state == UIGestureRecognizerStateBegan) {

        previousAngle = angle;

    }

    

    dial.transform = CGAffineTransformRotate(dial.transform, angle – previousAngle);

    previousAngle = angle;

        

    if (gr.state == UIGestureRecognizerStateEnded) {

        CGRect check = [dial convertRect:redMark.frame toView:self.view];

        check = CGRectMake(check.origin.x2, check.origin.y, check.size.width, check.size.height);

        

        if (CGRectIntersectsRect(check, bigRedMark.frame)) {

            [UIView animateWithDuration:0.5 animations:^{

                wire.transform = CGAffineTransformMakeTranslation(0, –50);

            } completion:^(BOOL finished) {

                [UIView animateWithDuration:0.5 animations:^{

                    wire.transform = CGAffineTransformIdentity;

                } completion:^(BOOL finished) {

                    redMark.backgroundColor = [self colorTheme:2];

                    [self showQuestion];

                }];

            }];

        }

    }

}

– (UIColor*)colorTheme:(int)no

{

    switch (no) {

        case 0:

            return UIColorHex(0x2D4728);

            

        case 1:

            return UIColorHex(0x456E3E);

            

        case 2:

            return UIColorHex(0x55874C);

            

        case 3:

            return UIColorHex(0xAD0100);

            

        default:

            return UIColorHex(0x85D477);

    }

}

– (void)didReceiveMemoryWarning

{

    [super didReceiveMemoryWarning];

    // Dispose of any resources that can be recreated.

}

@end