Luiz - 4 months ago 14x
iOS Question

# Spawn objects at random durations without overlaying

## Explanation

I'm building a game where I'm facing some problems. I have two objects (A and B) that run by the same rule: from up to bottom, they spawn, move heading down and get removed when reach the edge. Each one of them has its particular duration before spawning, this way, sometimes, they get overlayed (as you can see below).

## Question

The question is quite simple: is there any way to make A and B spawn by different durations, but still random ones?

## Code

``````import SpriteKit

class GameScene: SKScene {

//Declarations
var A = SKSpriteNode()
var B = SKSpriteNode()
var durationA = CGFloat()
var durationB = CGFloat()

//Setup
func setupA(){
A = SKSpriteNode(imageNamed: "A")
A.position = CGPoint(x: self.frame.width / 2, y: self.frame.height)
}
func setupB(){
B = SKSpriteNode(imageNamed: "B")
B.position = CGPoint(x: self.frame.width / 2, y: self.frame.height)
}

//Actions
func actionsA(){

//Start spawning, moving and removing
let spawnA = SKAction.runBlock({
() in

//Spawn A
self.setupA()

//Move left and remove when go off screenk
let frameHeight = CGFloat(self.frame.height)
let moveA = SKAction.moveByX(0, y: -frameHeight, duration: NSTimeInterval(0.0028 * frameHeight))  //duration: faster or slower
let removeA = SKAction.removeFromParent()

let moveAndRemoveA = SKAction.sequence([moveA, removeA])

self.A.runAction(moveAndRemoveA)
})

//Spawn A each 1.75~2.25 seconds
durationA = (CGFloat(arc4random_uniform(51)) + 175.0) / 100.0
let spawnAfterDurationA = SKAction.repeatActionForever(SKAction.sequence([SKAction.waitForDuration(Double(durationA)), spawnA]))
runAction(spawnAfterDurationA)
}
func actionsB(){

//Start spawning, moving and removing
let spawnB = SKAction.runBlock({
() in

//Spawn B
self.setupB()

//Move left and remove when go off screen
let frameHeight = CGFloat(self.frame.height)
let moveB = SKAction.moveByX(0, y: -frameHeight, duration: NSTimeInterval(0.0028 * frameHeight))   //duration: faster or slower
let removeB = SKAction.removeFromParent()

let moveAndRemoveB = SKAction.sequence([moveB, removeB])

self.B.runAction(moveAndRemoveB)
})

//Spawn B each 0.5~1.0 seconds
durationB = (CGFloat(arc4random_uniform(51)) + 50.0) / 100.0
let spawnAfterDurationB = SKAction.repeatActionForever(SKAction.sequence([SKAction.waitForDuration(Double(durationB)), spawnB]))
runAction(spawnAfterDurationB)
}

override func didMoveToView(view: SKView) {
/* Setup your scene here */
actionsA()
actionsB()
}
}
``````

## Timothy Smith's attempt

``````import SpriteKit

class GameScene: SKScene {

//Declarations
var A = SKSpriteNode()
var B = SKSpriteNode()

//Setup
func setupA(){
A = SKSpriteNode(imageNamed: "A")
A.position = CGPoint(x: self.frame.width / 2, y: self.frame.height)
}
func setupB(){
B = SKSpriteNode(imageNamed: "B")
B.position = CGPoint(x: self.frame.width / 2, y: self.frame.height)
}

//Actions
func actionsA(){

//Spawn, move and remove
let spawnA = SKAction.runBlock({
() in

//Spawn A
self.setupA()

//Move left and remove when go off screenk
let frameHeight = CGFloat(self.frame.height)
let moveA = SKAction.moveByX(0, y: -frameHeight, duration: NSTimeInterval(0.0028 * frameHeight))  //duration: faster or slower
let removeA = SKAction.removeFromParent()

let moveAndRemoveA = SKAction.sequence([moveA, removeA])

self.A.runAction(moveAndRemoveA)
})

runAction(spawnA)
}
func actionsB(){

//Spawn, move and remove
let spawnB = SKAction.runBlock({
() in

//Spawn B
self.setupB()

//Move left and remove when go off screen
let frameHeight = CGFloat(self.frame.height)
let moveB = SKAction.moveByX(0, y: -frameHeight, duration: NSTimeInterval(0.0028 * frameHeight))   //duration: faster or slower
let removeB = SKAction.removeFromParent()

let moveAndRemoveB = SKAction.sequence([moveB, removeB])

self.B.runAction(moveAndRemoveB)
})

runAction(spawnB)
}

//Spawn
func spawn(){

let random = Int(arc4random_uniform(10)+1) //pick a number from 1 to 10

if random <= 8{
actionsB()
}
else{
actionsA()
}
}

override func didMoveToView(view: SKView) {
/* Setup your scene here */
runAction(SKAction.repeatActionForever(SKAction.sequence([SKAction.waitForDuration(0.5, withRange: 0.25), SKAction.runBlock(self.spawn)])))
}
}
``````

One possible solution would be to use a single function `spawn`, called randomly every 0.25 to 1.00 seconds. Inside the function, randomly pick either A or B, and spawn it. It appears that you want B to appear more frequently than A, so you could use a weighted randomness (pick a number from 0.45 to 1 and round to the nearest integer).