Question

I'm using the following code to implement a flick on sprites within a SpriteKit SKScene so they will continue to move and slide across the screen based on the motion of a finger from a UIPanGestureRecognizer.

For the most part it works fine, however when I get close to the edges of the viewable area of the screen and attempt this gesture to flick the sprite offscreen., it has the opposite effect and pushed the sprite back towards the center rather than offscreen.

Can anyone tell me why when the sprite it too close to the edge of the screen it's getting pushed back in rather than flicked offscreen as expected?

if (recognizer.state == UIGestureRecognizerStateEnded) {
    if ([touchedNode.name isEqualToString:@"sprite"]) {
        SKSpriteNode *touchedSprite = (SKSpriteNode *)touchedNode;
        // Calculate the length of the velocity vector (i.e. the magnitude)
        CGPoint velocity = [recognizer velocityInView:self.view];
        CGFloat magnitude = sqrtf((velocity.x * velocity.x) + (velocity.y * velocity.y));
        CGFloat slideMult = magnitude / 200;
        NSLog(@"magnitude: %f, slideMult: %f", magnitude, slideMult);

        // Calculate a final point based on the above
        float slideFactor = 0.1 * slideMult;    // Increase for more of a slide
        CGPoint finalPoint = CGPointMake(recognizer.view.center.x + (velocity.x * slideFactor), recognizer.view.center.y - (velocity.y * slideFactor));

        SKAction *moveAction = [SKAction moveTo:finalPoint duration:slideFactor * 2];
        [moveAction setTimingMode:SKActionTimingEaseOut];
        [touchedSprite runAction:moveAction];
    }
}
Was it helpful?

Solution 2

The problem is that the calculation for the final CGPoint is based on where the UIPanGestureRecognizer was added. In this case it has to be added to the SKView as an SKSpriteNode is not a UIView subclass so cannot have a UIPanGestureRecognizer added to it.

Here's the old calculation as above

CGPoint finalPoint = 
 CGPointMake(recognizer.view.center.x + (velocity.x * slideFactor), 
             recognizer.view.center.y - (velocity.y * slideFactor));

Here's the change made to use the centre of the sprite node as the base for the calculation.

CGPoint finalPoint = 
 CGPointMake(touchedSprite.position.x 
              + (touchedSprite.size.width / 2) 
              + (velocity.x * slideFactor), 
             touchedNode.position.y 
              + (touchedNode.size.height / 2) 
              - (velocity.y * slideFactor));

OTHER TIPS

I think that it is possible, that you forgot to convert your CGPoint from view to the scene

Let's assume that we initalize our gesture

__weak IBOutlet SKView      *skView;
...
panRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)];
[skView addGestureRecognizer:panRecognizer];

so if we want to have touch location of this gesture recognizer in SpriteKit space, we have to conver this point from view to skScene

- (void)handlePan:(UIPanGestureRecognizer*)sender{

CGPoint point = [sender locationInView:skView];
point = [skView.scene convertPointFromView:point];

// do your things here

}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top