
ダイアルをゆびでくるくるまわせるよ。赤いところに合わせてカギを開けてみよう。という感じで、ダイアル式ロックの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.0 – 70);
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.0 – 115, 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.y – dial.center.y, p.x – dial.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.x – 2, 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