3

I need the ball node to be be initially released in my game in a downwards angle (which is randomly generated each time). I found out the velocity of the ball includes both the direction and speed (please correct me if this is wrong) therefore I generated a random angle and multiplied this by a value such as '0.5' to represent the impulse/speed. My code for this can be seen below:

let minAngle : UInt32 = 181
let maxAngle : UInt32 = 359
let randomAngle = arc4random_uniform(maxAngle - minAngle) + minAngle
let dx:CGFloat = 0.5 * CGFloat(randomAngle)
let dy:CGFloat = 0.5 * CGFloat(randomAngle)

ball.physicsBody?.velocity = CGVector(dx: dx, dy: dy)

However I realised this isn't working as the ball goes in upwards direction. Is my range in-correct or is my method of doing so incorrect? If it is my method how could I guarantee that the ball always is released in a downwards angle (I must also add a speed to the ball)?

Thanks

Antonio C
  • 71
  • 1
  • 9
  • you are not using an angle whatsoever, you need to use arctan or arctan2 if you want to go from a polar coordinate to a rect coordinate – Knight0fDragon Nov 14 '16 at 21:27

2 Answers2

1

spritekit works using radians not degrees. better to learn to think in terms of radians rather than degrees since that's what you'll be using. If you want to continue using degrees you can use this kind of formula.

func convertToRadians(degrees: Int) -> CGFloat {
    return CGFloat(M_PI) * CGFloat(degrees) / 180
}

let minAngle = convertToRadians(degrees: 181)
let maxAngle = convertToRadians(degrees: 359)

another way of calculating it

let minAngle = CGFloat(Measurement(value: 181, unit: UnitAngle.degrees).converted(to: .radians).value)
let maxAngle = CGFloat(Measurement(value: 359, unit: UnitAngle.degrees).converted(to: .radians).value)

get a random angle in radians between two sets of degrees

func random() -> CGFloat {
    return CGFloat(Float(arc4random()) / 0xFFFFFFFF)
}

func randomDegreesToRadians(min: CGFloat, max: CGFloat) -> CGFloat {
    assert(min < max)
    let randomDegrees = random() * (max - min) + min
    return CGFloat(M_PI) * CGFloat(randomDegrees) / 180
}


randomDegreesToRadians(min: 100, max: 200)
hamobi
  • 7,940
  • 4
  • 35
  • 64
  • When I convert it to the the radian using the 2nd way of doing above it gives me an error saying the 'binary operator '-'' can't be applied to two CGFloats – Antonio C Nov 15 '16 at 10:37
  • I have the 2 ranges 'min and max' angle however I cant generate the random number – Antonio C Nov 15 '16 at 10:41
  • do you want to generate a random angle between your two angles? – hamobi Nov 15 '16 at 17:56
  • Yes. I need to generate a random angle. I need this angle always to be downwards (hence the 181 to 359 range). I then need the impulse to be added to the angle so that the ball has speed. – Antonio C Nov 15 '16 at 20:41
  • whilst the answer does lead to a random angle It sometimes is upwards – Antonio C Nov 15 '16 at 21:44
  • antonio.. look at this image http://www.globalnerdy.com/wordpress/wp-content/uploads/2016/01/radians.jpg 0 degrees is to the right in spritekit – hamobi Nov 15 '16 at 21:45
  • ok therefore the downwards angle should be in between pi and 0 value. Which in degrees would be between 181 to 359 or am i getting confused? – Antonio C Nov 15 '16 at 21:48
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/128208/discussion-between-hamobi-and-antonio-c). – hamobi Nov 15 '16 at 21:49
1

You need to use SIN COS and ATAN on angles to get where you are going.

If you know your angle and speed, you use SIN and COS:

extension Int {
    var degreesToRadians: Double { return Double(self) * .pi / 180 }
    var radiansToDegrees: Double { return Double(self) * 180 / .pi }
}
extension FloatingPoint {
    var degreesToRadians: Self { return self * .pi / 180 }
    var radiansToDegrees: Self { return self * 180 / .pi }
}

credit to Leo Dabus How can I convert from degrees to radians?

let minAngle = 181.degreesToRadans
let maxAngle = 359.degreesToRadans
let randomAngle = arc4random_uniform(maxAngle - minAngle) + minAngle
let dx:CGFloat = 0.5 * cos(CGFloat(randomAngle))
let dy:CGFloat = 0.5 * sin(CGFloat(randomAngle))

ball.physicsBody?.velocity = CGVector(dx: dx, dy: dy)

If you only know 2 points, and need to get the angle, you use arctan2: (We need to make point1 our origin, so we subtract point2 from point1)

   let point1 = CGPoint(x:0,y:1)
   let point2 = CGPoint(x:0,y:2)
   let distancePoint = CGPoint(x:point2.x - point1.x, y:point2.y - point1.y)
   let angle = atan2(distancePoint.y,distancePoint.x)
Community
  • 1
  • 1
Knight0fDragon
  • 16,609
  • 2
  • 23
  • 44
  • Hi. thanks the angle seems to be working randomly now however it still goes upwards sometimes??? I dont understand why maybe the range or random generation is incorrect? – Antonio C Nov 15 '16 at 17:31
  • no idea, when angle is 0 are we facing up or are we facing right – Knight0fDragon Nov 15 '16 at 17:33
  • if we expect your ball to travel up the screen, this means y should be 1 and x should be 0. so we want to swap cos and sin so that dx = sin and dy = cos. Then we have to ask are you rotating clockwise or counter clockwise. If counter clockwise, then we need to do -sin on x, since sin(90) = 1 – Knight0fDragon Nov 15 '16 at 17:38
  • It's `atan2 `not `arctan2`, and the `x` and `y` are swapped. – 0x141E Nov 15 '16 at 19:03