Oliver Reznik Oliver Reznik - 8 months ago 19
Swift Question

How do I position a node to a random point on a circle's perimeter in Sprite Kit?

So I need to spawn game enemies from random points on the perimeter of a circle. This is the code I have so far which feels really close to working but isn't:

let enemy = SKShapeNode(circleOfRadius: 5)

func enemyGenerator() {

//takes an x value and calculates the corresponding y coordinate on the circle.
func enemyYSpawnPosition(x: CGFloat) -> CGFloat {
return sqrt(104006.25 - (x * x))

//randomly selects an x value from a range of acceptable values.
func enemyXSpawnPosition() -> CGFloat {
func randRange (lower: Int , upper: Int) -> Int {
return lower + Int(arc4random_uniform(UInt32(upper - lower + 1)))
var xValue = randRange(-2.5, 322.5)
return CGFloat (xValue)

//used to randomly decide whether the y value will be subtracted or added.
func coinFlip (lower: Int, upper: Int) -> Int {
return lower + Int(arc4random_uniform(UInt32(upper - lower + 1)))
var randResult = coinFlip(1, 2)

//positions the enemy using the functions above.
if randResult == 1 {
self.enemy.position = CGPointMake(enemyXSpawnPosition(), CGRectGetMidY(self.frame) + enemyYSpawnPosition(enemyXSpawnPosition()))
else {
self.enemy.position = CGPointMake(enemyXSpawnPosition(), CGRectGetMidY(self.frame) - enemyYSpawnPosition(enemyXSpawnPosition()))

The issue is that when positioning the enemy I must call the enemyXSpawnPosition function twice and when I do that I get two different values. When I'm laying out the positions I need the values to stay the same.

Is there an easier way to randomly position a node on a circle's perimeter or is their a way to fix what I've already got?


This method returns a random point on a circle given the circle's radius and center position.

    func randomPointOnCircle(radius:Float, center:CGPoint) -> CGPoint {
        // Random angle in [0, 2*pi]
        let theta = Float(arc4random_uniform(UInt32.max))/Float(UInt32.max-1) * Float(M_PI) * 2.0
        // Convert polar to cartesian
        let x = radius * cosf(theta)
        let y = radius * sinf(theta)
        return CGPointMake(CGFloat(x)+center.x,CGFloat(y)+center.y)