How do I measure the velocity of a swipe?

前端 未结 4 1767
北荒
北荒 2021-02-11 03:21

I\'m developing a game that will use the force of the swipe as a variable user input.

I read from the documentation that on the touchesEnded event, I can get the allTouc

相关标签:
4条回答
  • 2021-02-11 03:43

    You could use a UIPanGestureRecognizer which has function velocityInView. See https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIPanGestureRecognizer_Class/

    0 讨论(0)
  • 2021-02-11 03:46

    Rather than using allTouches on the UIEvent, you should use the touches set that you get in the call to your UIView's (or other UIResponder's) touchesEnded:withEvent: method. This ensures that you don't get touches that belong to other views.

    Since the iPhone is a multi-touch device, the set contains all the touches that are associated with that event. In other words, if the user is touching the screen with two fingers, there should be two UITouch objects in the set, etc.

    This means that the set does not contain all the points traversed since a touch began until it ended. To track that, you have to save the start point and time in touchesBegan:withEvent:, and then when the touch ends you calculate the speed based on that.

    Note that if the set contains several points (which means the user is touching the screen with several fingers), you have to try to keep track of which UITouch object corresponds to which finger. You will want to do this in touchesMoved:withEvent:.

    Since you get the touches in a set, you can't use an index or some key value to keep track of the touches you are interested in. I believe that the recommended way of doing this is to just assume that the touch that is closest to the point you saved on the previous event comes from the same finger. If you want to be more exact you can also use the UITouch's previousLocationInView: method.

    If you're lazy, you can also simply do [[touches allObjects] objectAtIndex:0] and hope that this will give you the right touch (ie the one originating from the same finger) on each event. This actually often works, but I don't think you should use it in production code, especially not if you're trying to create an app with multi-touch functionality.

    0 讨论(0)
  • Solve like this

    - (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];
    }
    
    0 讨论(0)
  • 2021-02-11 04:02

    I've accomplished something along these lines rather simply by just comparing [touch locationInView:self] to [touch previousLocationInView:self] in touchesEnded of the Class (subclass of UIView) of the object that will be moved. This will give you a vector with location, direction & rough sense of velocity at the moment user released finger from the iPhone.

    0 讨论(0)
提交回复
热议问题