iPhone 跳ねる速度

曲線でボールの跳ねる速度をコントロールするiPhoneアプリのサンプルコードを書いてみます。

#import “ViewController.h”

@interface ViewController ()

@property (nonatomic, weak) UIView *ball;

@property (nonatomic, weak) UIView *curveView;

@property (nonatomic, weak) CAShapeLayer *curveline;

@property (nonatomic, weak) CALayer *selected;

@end

@implementation ViewController

– (void)viewDidLoad {

    [super viewDidLoad];

    self.view.backgroundColor = [UIColor yellowColor];

    [self createBall];

    [self createBoard];

}

– (void)createBall {

    UIView *ball = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 40, 40)];

    ball.backgroundColor = [UIColor blackColor];

    ball.center = CGPointMake(CGRectGetMidX(self.view.bounds), CGRectGetMaxY(self.view.bounds) * 0.2);

    ball.layer.cornerRadius = 20;

    [self.view addSubview:ball];

    self.ball = ball;

    

    UIBezierPath *path = [UIBezierPath bezierPath];

    [path moveToPoint:ball.center];

    [path addLineToPoint:CGPointMake(ball.center.x, ball.center.y + 100)];

    [path addLineToPoint:CGPointMake(ball.center.x, ball.center.y)];

    CAKeyframeAnimation *anim = [CAKeyframeAnimation animationWithKeyPath:@”position”];

    anim.path = path.CGPath;

    anim.duration = 1.0;

    [ball.layer addAnimation:anim forKey:nil];

}

– (void)createBoard {

    UIView *curveView = [[UIView alloc] initWithFrame:CGRectMake(0, CGRectGetMidY(self.view.bounds), CGRectGetMaxX(self.view.bounds), CGRectGetMidY(self.view.bounds))];

    curveView.backgroundColor = [[UIColor whiteColor] colorWithAlphaComponent:0.2];

    [self.view addSubview:curveView];

    curveView.userInteractionEnabled = YES;

    self.curveView = curveView;

    

    CAShapeLayer *s = [CAShapeLayer layer];

    s.fillColor = [UIColor clearColor].CGColor;

    s.lineWidth = 4;

    s.strokeColor = [UIColor blackColor].CGColor;

    [curveView.layer addSublayer:s];

    self.curveline = s;

    

    // cp

    CGPoint cp[] = {CGPointMake(100, 150), CGPointMake(200, 80)};

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

        CALayer *slider = [CALayer layer];

        slider.name = [NSString stringWithFormat:@”slider%d”, i];

        slider.frame = CGRectMake(0, 0, 30, 30);

        slider.backgroundColor = [UIColor whiteColor].CGColor;

        slider.position = cp[i];

        slider.cornerRadius = 15;

        slider.borderWidth = 2;

        slider.borderColor = [UIColor darkGrayColor].CGColor;

        [curveView.layer addSublayer:slider];

    }

    

    [self updateCurve];

}

– (void)updateCurve {

    

    CGPoint cp1;

    CGPoint cp2;

    for (CALayer *l in self.curveView.layer.sublayers) {

        if ([l.name isEqual:@”slider0″]) cp1 = l.position;

        if ([l.name isEqual:@”slider1″]) cp2 = l.position;

    }

    

    UIBezierPath *path = [UIBezierPath bezierPath];

    [path moveToPoint:CGPointMake(10, CGRectGetMaxY(self.curveView.bounds) + 10)];

    [path addCurveToPoint:CGPointMake(CGRectGetMaxX(self.curveView.bounds) – 10, 10) controlPoint1:cp1 controlPoint2:cp2];

    self.curveline.path = path.CGPath;

    

    

    

    // update guide line

    for (CAShapeLayer *l in self.curveView.layer.sublayers) {

        if ([l.name isEqual:@”guide”]) {

            [l removeFromSuperlayer];

        }

    }

    UIBezierPath *guidepath = [UIBezierPath bezierPath];

    [guidepath moveToPoint:CGPointMake(10, CGRectGetMaxY(self.curveView.bounds) + 10)];

    [guidepath addLineToPoint:cp1];

    [guidepath moveToPoint:CGPointMake(CGRectGetMaxX(self.curveView.bounds) – 10, 10)];

    [guidepath addLineToPoint:cp2];

    

    CAShapeLayer *guide = [CAShapeLayer layer];

    guide.path = guidepath.CGPath;

    guide.name = @”guide”;

    guide.fillColor = [UIColor clearColor].CGColor;

    guide.strokeColor = [UIColor lightGrayColor].CGColor;

    guide.lineWidth = 2;

    [self.curveView.layer addSublayer:guide];

}

– (void)bounce {

    

    CGPoint cp1;

    CGPoint cp2;

    for (CALayer *l in self.curveView.layer.sublayers) {

        if ([l.name isEqual:@”slider0″]) cp1 = l.position;

        if ([l.name isEqual:@”slider1″]) cp2 = l.position;

    }

    

    UIBezierPath *path = [UIBezierPath bezierPath];

    [path moveToPoint:self.ball.center];

    [path addLineToPoint:CGPointMake(self.ball.center.x, self.ball.center.y + 100)];

    [path addLineToPoint:CGPointMake(self.ball.center.x, self.ball.center.y)];

    CAKeyframeAnimation *anim = [CAKeyframeAnimation animationWithKeyPath:@”position”];

    anim.path = path.CGPath;

    anim.duration = 0.8;

    float w = CGRectGetMaxX(self.curveView.bounds);

    float h = CGRectGetMaxY(self.curveView.bounds);

    anim.timingFunction = [CAMediaTimingFunction functionWithControlPoints:cp1.x/w :1.0-cp1.y/h :cp2.x/w :1.0-cp2.y/h];

    anim.removedOnCompletion = NO;

    anim.fillMode = kCAFillModeForwards;

    [self.ball.layer addAnimation:anim forKey:nil];

}

– (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event

{

    CGPoint p = [[touches anyObject] locationInView:self.curveView];

    p = [self.curveView convertPoint:p toView:nil];  // get layer point

    CALayer *hit = [self.curveView.layer hitTest:p];

    if ([hit.name hasPrefix:@”slider”]) {

        self.selected = hit;

    } else {

        [self bounce];

    }

}

– (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event

{

    CGPoint p = [[touches anyObject] locationInView:self.curveView];

    

    [CATransaction begin];

    [CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions];

    self.selected.position = p;

    [self updateCurve];

    [CATransaction commit];

}

– (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event

{

    self.selected = nil;

}

@end