ボール投げエフェクトをUIViewで表示する方法のメモ
(XcodeのiOS6 Simulatorで試してます。)
弾性、空気抵抗は無し。
重力加速度のみ考慮。
ボールの式
微小な時間dtとvx, vyで計算する
速さx方向:vx = vx
速さy方向:vy = vy – gdt
操作
タッチでボールの初期位置を決定
初期位置から指を滑らせると投げる方向を表示
指を離すとボールを指示マークの方向に投げる
サンプルコード
#import “ViewController.h”
#import <QuartzCore/QuartzCore.h>
@interface ViewController () {
CADisplayLink *timer;
float vx;
float vy;
float g;
}
@property (nonatomic, strong) UIView *ball;
@end
@implementation ViewController
@synthesize ball;
– (void)viewDidLoad
{
[super viewDidLoad];
}
– (void)viewDidAppear:(BOOL)animated
{
UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(pan:)];
[self.view addGestureRecognizer:pan];
}
– (void)pan:(UIPanGestureRecognizer*)pgr
{
CGPoint touch = [pgr locationInView:self.view];
if (UIGestureRecognizerStateBegan == pgr.state) {
UIView *marker = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 60, 60)];
marker.center = touch;
marker.layer.borderWidth = 2.0;
marker.tag = 101;
[self.view addSubview:marker];
}
if (UIGestureRecognizerStateChanged == pgr.state) {
// clean
for (UIView *v in self.view.subviews) {
if (v.tag == 102) {
[v removeFromSuperview];
}
}
// create
UIView *marker = [self.view viewWithTag:101];
float dx = touch.x – marker.center.x;
float dy = touch.y – marker.center.y;
if (dx == 0) {
dx = 0.001;
}
if (dy == 0) {
dy = 0.001;
}
float len = hypot(dx, dy);
for (int i=0; i<len; i += 10) {
UIView *chain = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 5, 5)];
chain.layer.cornerRadius = 2.0;
chain.backgroundColor = [UIColor grayColor];
chain.tag = 102;
float x = marker.center.x + (i * dx / len);
float y = marker.center.y + (i * dy / len);
chain.center = CGPointMake(x, y);
[self.view addSubview:chain];
}
}
if (UIGestureRecognizerStateEnded == pgr.state) {
UIView *marker = [self.view viewWithTag:101];
[self createBall: marker.center];
[self.view addSubview:self.ball];
float x = touch.x – marker.center.x;
float y = – (touch.y – marker.center.y);
float adjust = 0.05; // アニメーションの見た目的な調整
[self throwVX:x*adjust VY:y*adjust];
// clean up
for (UIView *v in self.view.subviews) {
if (v.tag == 101 || v.tag == 102) {
[v removeFromSuperview];
}
}
}
}
– (void)throwVX:(float)dx VY:(float)dy
{
float rate = 100; // 100point = 1m 換算にする 重力加速度とのかねあい
vx = dx * rate; // dx m/s
vy = dy * rate; // dy m/s
g = 9.8 * rate; // 9.8m/s^2 固定
[self startTimer];
}
– (void)createBall:(CGPoint)point
{
self.ball = [[UIView alloc] initWithFrame:CGRectMake(0, 300, 30, 30)];
ball.center = point;
ball.layer.cornerRadius = 15;
ball.backgroundColor = [UIColor lightGrayColor];
ball.layer.borderColor = [UIColor blackColor].CGColor;
ball.layer.borderWidth = 1.5;
}
– (void)startTimer
{
timer = [CADisplayLink displayLinkWithTarget:self selector:@selector(updateDisplay:)];
[timer addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
}
– (void)updateDisplay:(CADisplayLink*)sender
{
static float lastTime = 0.0;
float timeDelta = 0.0;
if (lastTime == 0.0) {
lastTime = sender.timestamp;
} else {
timeDelta = sender.timestamp – lastTime;
lastTime = sender.timestamp;
}
vy = vy – g * timeDelta;
float x = ball.center.x + vx * timeDelta;
float y = ball.center.y – vy * timeDelta;
ball.center = CGPointMake(x, y);
// stop ball on the floor
if (ball.center.y > 400) {
ball = nil; // ボールのViewをアニメ処理から切り離す。
}
}
– (void)viewDidDisappear:(BOOL)animated
{
self.ball = nil;
[timer invalidate];
timer = nil;
}
@end