如何测量滑动的速度?

时间:2009-12-10 09:26:00

标签: objective-c cocoa-touch

我正在开发一种游戏,它将使用滑动力作为可变用户输入。

我从文档中读到,在touchesEnded事件中,我可以获得allTouches数组,这是从touchesBegan收集的用户触摸列表。由此我计划得到最后两次接触以获得滑动的方向。我还将获得touchesBegan和touchesEnded之间的时间间隔,从中我将获得滑动的速度。我将使用方向和速度来计算滑动力。

我想知道的是:有更好的方法吗?这已经封装在某个库中的库调用吗?

提前致谢。

4 个答案:

答案 0 :(得分:7)

像这样解决

- (void)rotateAccordingToAngle:(float)angle
{
    [spinWheel setTransform:CGAffineTransformRotate(spinWheel.transform, angle)];
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 
{    
    [spinWheel.layer removeAllAnimations];
    previousTimestamp = event.timestamp;
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    UITouch *touch = [touches anyObject];
    if (touch.view==spinWheel)
    {
        UITouch *touch = [touches anyObject];
        CGPoint center = CGPointMake(CGRectGetMidX([spinWheel bounds]), CGRectGetMidY([spinWheel bounds]));
        CGPoint currentTouchPoint = [touch locationInView:spinWheel];
        CGPoint previousTouchPoint = [touch previousLocationInView:spinWheel];
        CGFloat angleInRadians = atan2f(currentTouchPoint.y - center.y, currentTouchPoint.x - center.x) - atan2f(previousTouchPoint.y - center.y, previousTouchPoint.x - center.x);

        [self rotateAccordingToAngle:angleInRadians];

        CGFloat angleInDegree = RADIANS_TO_DEGREES(angleInRadians);
        revolutions+= (angleInDegree/360.0f);
    }
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    UITouch *touch = [touches anyObject];
    if (touch.view==spinWheel) 
    {
        NSTimeInterval timeSincePrevious = event.timestamp - previousTimestamp;
        CGFloat revolutionsPerSecond = revolutions/timeSincePrevious;
        NSLog(@"%.3f",revolutionsPerSecond);
        [self startAnimationWithRevolutions:revolutionsPerSecond forTime:5.0f];
    }
    revolutions = 0;
}

- (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag
{
    spinWheel.userInteractionEnabled = TRUE;
    if (timerUpdate) {
        [timerUpdate invalidate];
        timerUpdate = nil;
    }
}
-(void)updateTransform{
    spinWheel.transform = [[spinWheel.layer presentationLayer] affineTransform];
}
-(void)startAnimationWithRevolutions:(float)revPerSecond forTime:(float)time
{
    spinWheel.userInteractionEnabled = FALSE;
    float totalRevolutions = revPerSecond * time;

    timerUpdate = [NSTimer scheduledTimerWithTimeInterval:0.1f target:self selector:@selector(updateTransform) userInfo:nil repeats:YES];

    [CATransaction begin];
    [CATransaction setValue:[NSNumber numberWithFloat:time] forKey:kCATransactionAnimationDuration];

    CABasicAnimation* spinAnimation = [CABasicAnimation
                                       animationWithKeyPath:@"transform.rotation"];
    CGAffineTransform transform = spinWheel.transform;
    float fromAngle = atan2(transform.b, transform.a);
    float toAngle = fromAngle + (totalRevolutions*4*M_PI);
    spinAnimation.fromValue = [NSNumber numberWithFloat:fromAngle];
    spinAnimation.toValue = [NSNumber numberWithFloat:toAngle];
    spinAnimation.repeatCount = 0;
    spinAnimation.removedOnCompletion = NO;
    spinAnimation.delegate = self;
    spinAnimation.timingFunction = [CAMediaTimingFunction functionWithName:
                                    kCAMediaTimingFunctionEaseOut];
    [spinWheel.layer addAnimation:spinAnimation forKey:@"spinAnimation"];
    [CATransaction commit];
}

答案 1 :(得分:3)

我已经在这些方面完成了一些工作,而不仅仅是将[touch locationInView:self][touch previousLocationInView:self]中的touchesEnded进行比较,该{{1}}将被移动的对象的类(UIView的子类)。这将为您提供一个包含位置,方向和位置的向量。当用户从iPhone上释放手指时,粗糙速度感。

答案 2 :(得分:1)

您应该使用在调用UIView(或其他UIResponder)时获得的 touches 集,而不是在UIEvent上使用allTouches。 touchesEnded:withEvent:方法。这可以确保您不会获得属于其他视图的触摸。

由于iPhone是多点触控设备,因此该套装包含与该事件相关的所有触控。换句话说,如果用户用两根手指触摸屏幕,则集合中应该有两个UITouch个对象。

这意味着该集合包含自触摸开始直到结束所经过的所有点。要跟踪这一点,您必须在touchesBegan:withEvent:中保存起点和时间,然后在触摸结束时根据该值计算速度。

请注意,如果该组包含多个点(这意味着用户用几个手指触摸屏幕),则必须尝试跟踪哪个UITouch对象与哪个手指对应。您需要在touchesMoved:withEvent:

中执行此操作

由于你得到了一组中的触摸,你不能使用索引或某个键值来跟踪你感兴趣的触摸。我相信这样做的推荐方法是假设触摸最接近您在上一个事件中保存的点的来自同一个手指。如果你想更精确,你也可以使用UITouch的previousLocationInView:方法。

如果你很懒,你也可以简单地做[[touches allObjects] objectAtIndex:0],并希望这会在每个事件中给你正确的触摸(即来自同一个手指的触摸)。这实际上经常有效,但我不认为你应该在生产代码中使用它,尤其是当你试图创建一个具有多点触控功能的应用时。

答案 3 :(得分:1)

您可以使用具有velocityInView功能的UIPanGestureRecognizer。见https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIPanGestureRecognizer_Class/