Search code examples
swiftsprite-kitrotationskaction

Shooting balls from a rotating cannon


I'm making a SpriteKit game. I have six cannons that I've made rotate back and fourth. I want to shoot cannonballs from each cannon that sync with the rotation of each cannon. I want a duration of one second between each cannonball.

So basically: A cannon that is in constant rotation is shooting cannonballs in the same direction as the rotation.

For the cannons i'm using an extension:

extension CGFloat {
func degreesToRadians() -> CGFloat {
    return self * CGFloat.pi / 180
}
}

I'm gonna put the code for just one cannon, since I should be able to figure out how to adjust one of the cannonball movements to the others. Here is one:

func createCannons() { 

  let cannonLeftBottom = SKSpriteNode(imageNamed: "Cannon")

  cannonLeftBottom.anchorPoint = CGPoint(x: 0.5, y: 0.5)
  cannonLeftBottom.position = CGPoint(x: -325, y: -420)
  cannonLeftBottom.zPosition = 4
  cannonLeftBottom.setScale(0.4)
  cannonLeftBottom.zRotation = CGFloat(65).degreesToRadians()

  let rotateLB = SKAction.rotate(byAngle: 
  CGFloat(-65).degreesToRadians(), duration: 2)

  let rotateBackLB = SKAction.rotate(byAngle: 
  CGFloat(65).degreesToRadians(), duration: 2)

  let repeatRotationLB = 
  SKAction.repeatForever(SKAction.sequence([rotateLB,rotateBackLB]))

  cannonLeftBottom.run(repeatRotationLB)

  self.addChild(cannonLeftBottom)

}

Here is my function for the cannonball:

func createBalls() {

  let cannonBallLB = SKSpriteNode(imageNamed: "Ball")

  cannonBallLB.name = "CannonBall"
  cannonBallLB.position = CGPoint(x: -325, y: -420)
  cannonBallLB.physicsBody = SKPhysicsBody(circleOfRadius: 
  cannonBallLB.size.height / 2)
  cannonBallLB.physicsBody?.affectedByGravity = false
  cannonBallLB.zPosition = 3
  cannonBallLB.setScale(0.1)
  self.addChild(cannonBallLB)

}

THX!


Solution

  • You need to convert from Polar Coordinates to Rectangular Coordinates.

    You do this by using sin and cos

    E.G.

    let speed = 100 //This would mean move 100 points per second
    let force = CGVector(dx:cos(cannon.zRotation) * speed,dy:sin(cannon.zRotation) * speed)
    cannonBall.applyForce(force)
    

    Note: Now unless they changed this, force used to be in units of points, if they fixed it to units of meters, then you need to divide your speed by 150, since 150 points = 1 meter in Spritekit