Gugulethu
Gugulethu

Reputation: 1436

How to create a slingshot mechanism in Swift, SpriteKit

I am trying to create a Sling shot mechanism where I rotate a node with an object attached at the end. The slingshot starts off with a touch and hold interaction to rotate the object and on release, launches the object attached at the end - A similar effect is seen here

This is my code for the rotation which has worked. Not sure how to start the joining and slinging part.

var touchingScreen = false

override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
    super.touchesBegan(touches, withEvent: event)
    touchingScreen = true
    println("Screen Touched")
}

override func touchesCancelled(touches: Set<NSObject>!, withEvent event: UIEvent!) {
    super.touchesCancelled(touches, withEvent: event)
    touchingScreen = false
    println("Screen Not Touched")
}

override func touchesEnded(touches: Set<NSObject>, withEvent event: UIEvent) {
    super.touchesEnded(touches, withEvent: event)
    touchingScreen = false
    println("Screen Not Touched")
}

override func update(currentTime: CFTimeInterval) {

    if touchingScreen {

        var RotatingAngle = CGFloat(M_PI)
        var rotationDuration = 20.0
        var rotateCanon = SKAction.rotateByAngle(CGFloat(RotatingAngle), duration: rotationDuration)
        canon.runAction(rotateCanon)

    } else if !touchingScreen {


        var RotatingAngleTwo = CGFloat(0)
        var rotationDurationTwo = 0.0
        var rotateCanon = SKAction.rotateByAngle(CGFloat(RotatingAngleTwo), duration: rotationDurationTwo)
        canon.runAction(rotateCanon)
    }

}

Thanks for the help.

Upvotes: 2

Views: 695

Answers (1)

0x141E
0x141E

Reputation: 12753

Some thoughts...

  1. It's fairly straightforward to implement a slingshot as shown in the video if you break it down into smaller steps
  2. If you represent the ball's position on the circle with polar coordinates, you can rotate the ball by simply incrementing the angle over time and then converting from polar to cartesian coordinates
  3. When launched, the ball's trajectory should be tangent to the ball's position on the circle and its speed should be the same as its angular velocity.

and some code...

enum State {
    case Stopped
    case Rotating
    case Launched
}

let two_pi = CGFloat(M_PI*2.0)
let pi = CGFloat(M_PI)

// These are useful vector/point operators
func * (left:CGPoint, right:CGFloat) -> CGPoint {
    return CGPointMake(left.x*right, left.y*right)
}

func += (inout left:CGPoint, right:CGPoint) {
    left = CGPointMake(left.x+right.x, left.y+right.y)
}

func * (left:CGVector, right:CGFloat) -> CGVector {
    return CGVectorMake(left.dx*right, left.dy*right)
}

func / (left:CGVector, right:CGFloat) -> CGVector {
    return CGVectorMake(left.dx/right, left.dy/right)
}

class GameScene: SKScene {
    let shape = SKShapeNode(circleOfRadius: 7)
    let radius:CGFloat = 30
    var center = CGPointZero
    var currentAngle = -pi/2
    let angleIncr = two_pi / 60.0
    var state:State = .Stopped

    override func didMoveToView(view: SKView) {
        scaleMode = .ResizeFill
        // Set the center of the sling
        center = CGPointMake (CGRectGetMidX(view.frame),CGRectGetMidY(view.frame))
        addBall()
        let circle = SKShapeNode(circleOfRadius: radius)
        circle.position = CGPointMake (CGRectGetMidX(view.frame),CGRectGetMidY(view.frame))
        addChild(circle)
    }

    // Adds a circle shape node at the bottom of the sling
    func addBall() {
        currentAngle = -pi/2
        shape.fillColor = SKColor.blueColor()
        shape.position = CGPointMake (center.x, center.y-radius)
        shape.physicsBody = SKPhysicsBody(circleOfRadius: 7)
        shape.physicsBody?.affectedByGravity = false
        shape.physicsBody?.mass = 0.5
        shape.zPosition = 1
        addChild(shape)
    }

    override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
        if let touch = touches.first as? UITouch {
            let location = touch.locationInNode(self)
            if (state == .Stopped) {
                // Start rotating the ball around the sling
                state = .Rotating
            }
        }
    }

    override func touchesEnded(touches: Set<NSObject>, withEvent event: UIEvent) {
        if (state == .Rotating) {
            // Launch the ball on a vector tangent to its current position on the circle
            state = .Launched
            // Normal vector
            var normal = CGVectorMake(shape.position.x-center.x, shape.position.y-center.y)
            normal = normal / magnitude(normal)
            // Tangent vector
            let vector = CGVectorMake(normal.dy, -normal.dx)
            // Convert angular to linear speed
            let speed = angleIncr * 60.0 * radius
            shape.physicsBody?.velocity = vector*speed

            runAction(SKAction.waitForDuration(1.0)) {
                self.shape.removeFromParent()
                self.state = .Stopped
                self.addBall()
            }
        }
    }

    override func update(currentTime: CFTimeInterval) {
        switch (state) {
        case .Rotating:
            var point = angleToPoint(currentAngle) * radius
            point += center
            shape.position = point
            currentAngle -= angleIncr
            // Wrap at 2 pi
            currentAngle %= two_pi
        default:
            break
        }
    }

    func angleToPoint(angle:CGFloat) -> CGPoint {
        return CGPointMake(cos(angle), sin(angle))
    }

    func magnitude(v1:CGVector) -> CGFloat {
        return sqrt(v1.dx*v1.dx+v1.dy*v1.dy)
    }
}

and a video...

enter image description here

Upvotes: 1

Related Questions