1

I'm looking at this drag and drop tutorial by Ray Wenderleich, it allows sprites to be dragged on the screen, however, there's no gravity and the sprites are left pinned in place once the user lifts the finger.

At the same time I'm looking at this SpriteKit collision demo by Apple, it has collisions between objects.

Then there's this tutorial which shows how to apply impulse to sprites.

I've combined the demos together, so my scene has gravity, edge collision and bouncing, but the drag and drop code still does not have inertia.

How can I modify drag and drop behavior into "drag and flick" for sprites? I'm looking for a behavior similar to a view within a scrollview - acceleration, deceleration and inertia.

The code below has two modes - flick which applies impulse onto a sprite and drag which changes the sprite's location. I'm not sure how to combine the two code paths to

- (void)handlePanFrom:(UIPanGestureRecognizer *)recognizer {

    CGPoint touchLocation = [recognizer locationInView:recognizer.view];

    touchLocation = [self convertPointFromView:touchLocation];

    if (recognizer.state == UIGestureRecognizerStateBegan) {

        [self selectNodeForTouch:touchLocation];

    } else if (recognizer.state == UIGestureRecognizerStateChanged) {




        SKNode* node = [self selectNodeForTouch:touchLocation];

        //this is the flick gesture - pings the 
         double angle = atan2(touchLocation.y-node.position.y,touchLocation.x-node.position.x);
        [node.physicsBody applyImpulse:CGVectorMake(20*cos(angle), 20*sin(angle))];

        //CGPoint translation = [recognizer translationInView:recognizer.view];
 //       translation = CGPointMake(translation.x, -translation.y);
 //       [self panForTranslation:translation];
 //       [recognizer setTranslation:CGPointZero inView:recognizer.view];

    } else if (recognizer.state == UIGestureRecognizerStateEnded) {



    }
}

Here's the drag and drop code:

- (void)panForTranslation:(CGPoint)translation {
    CGPoint position = [_selectedNode position];
    if([[_selectedNode name] isEqualToString:kAnimalNodeName]) {
        [_selectedNode setPosition:CGPointMake(position.x + translation.x, position.y + translation.y)];
    } else {
        CGPoint newPos = CGPointMake(position.x + translation.x, position.y + translation.y);
        [_background setPosition:[self boundLayerPos:newPos]];
    }
}
Linus Juhlin
  • 1,175
  • 10
  • 31
Alex Stone
  • 46,408
  • 55
  • 231
  • 407
  • One option would be to store the dragged node's current and to last positions. Depending on the x and y change, you would know how fast the node is being dragged and can apply impulse strength accordingly once touchesEnded. – sangony Mar 25 '15 at 15:53
  • 1
    Hello, not sure if this is what you are looking for, but check out my answer here http://stackoverflow.com/q/28245653/2158465 – Epic Byte Mar 28 '15 at 05:01

1 Answers1

0

You need to apply impulse when pan recognizer changes state to ended. It is also good idea to make physics body static during drag. Best place is in touchesBegan, because it is fastest. Here's example of my code in swift.

func handlePan(panGestureRecognizer recognizer:UIPanGestureRecognizer) {
    let touchLocationView = recognizer.location(in: recognizer.view)
    let touchLocationScene = self.convertPoint(fromView: touchLocationView)

    switch recognizer.state {
    case .began:
        let canditateNode = self.touchedNode(touchLocationScene)
        if let name = canditateNode.name, name.contains(kMovableNode) {
            self.selectedNode = canditateNode
        }
    case .changed:
        let translation = recognizer.translation(in: recognizer.view)
        if let position = self.selectedNode?.position {
            self.selectedNode?.position = CGPoint(x: position.x + translation.x, y: position.y - translation.y)
            recognizer.setTranslation(CGPoint.zero, in: recognizer.view)
        }
    case .ended:
        self.selectedNode?.physicsBody?.isDynamic = true;
        let velocity = recognizer.velocity(in: recognizer.view)
        self.selectedNode?.physicsBody?.applyImpulse(CGVector(dx: velocity.x, dy: -velocity.y))
        self.selectedNode = nil
    default:
        break
    }
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    NSLog("touchesBegan")
    if let touch = touches.first {
        let touchLocationScene = touch.location(in: self)
        let canditateNode = self.touchedNode(touchLocationScene)
        if let name = canditateNode.name, name.contains(kMovableNode) {
            self.selectedNode = canditateNode
            self.selectedNode?.physicsBody?.isDynamic = false
        }
    }
}
Vanilla
  • 51
  • 1
  • 3
  • 9
jendan
  • 271
  • 4
  • 14