SKAction.run not working until program execution paused/resumed - ios

First time using SpriteKit - tapping a start button calls startLevel method in GameScene that has a player sprite fire two SKAction.run statements in a SKAction.sequence. The startLevel method has a completion block that triggers a message to the console and updates game state.
Tapping start displays the message, but the SKAction.run statements don't work unless I first pause program execution, and then click resume before tapping the start button. If I stop the level and tap a retry button, the same startLevel method is called, and it works fine without pausing execution.
Here's the method (player, marker, and door, are all optional objects that store their sprites; when tapping start, I verified that none of the sprites are nil, none of them are paused, and GameScene and SKView are not paused):
func startLevel(finished: () -> ()) {
guard let player = player,
let marker = marker,
let door = door else {
fatalError()
}
player.sprite.run(SKAction.sequence([
SKAction.run({ marker.pop(appear: true) }),
SKAction.run({ door.slide(open: true) }),
]))
finished()
}
Here's the GameScene code that calls startLevel:
startLevel(finished: { () -> () in
print("ALERT: startLevel finished")
levelStarted = true
})
I tried adding a run method completion block with a console message, and the message never prints. It seems that the player.sprite.run method is simply ignored (unless I pause execution first), and I don't understand why. Thanks for your help.
BTW - all the code above is outside GameScene’s update method, and the marker and door methods above are both used in didBegin() and didEnd(), and they work fine there.

In iOS 11 Apple made Spritekit Scenes and objects paused by default.
What I do to combat this is...
in my SKScene
override func didMove(to view: SKView) {
//this ensures that the scene is not paused
self.isPaused = false
}
and in each of my custom objects setup or init
self.isPaused = false

Related

Swift: What is a better way to implement a game loop for dice roll game (without using wait delay)

I am building a simple dice roll game.
The game cycle is like this:
1) Roll dice and move piece
2) Check if there is extra bonus moves, if Yes then move the piece
3) Check if piece has reached its destination, if Yes then Game ends
4) End turn
I built my Game loop using SKAction.run statements and append them into an array and then run them.
The actual code is very long, so I am providing only the basic flow here.
func runDiceRoll() {
// some SKActions
}
func checkExtraMoves() {
// run some SKActions depending on runDiceRoll() outcome
}
func checkStatus() {
// code to check if Game ends, depends on checkExtraMoves() outcome
}
func endTurn() {
// code to end the player's turn and give it to the other player
}
My game loop looks something like this
func runGameCycle() {
var actions = [SKAction]()
let actionRun = SKAction.run {runDiceRoll()}
let actionCheckExtraMoves = SKAction.run {checkExtraMoves()}
let actionCheckStatus = SKAction.run {checkStatus()}
let actionEndTurn = SKAction.run {endTurn()}
let actionWait = SKAction.wait(forDuration:2.0)
actions.append(actionRun)
actions.append(actionWait)
actions.append(actionCheckExtraMoves)
actions.append(actionCheckStatus)
actions.append(actionEndTurn)
piece.run(SKAction.sequence(actions))
}
If I remove the Wait action, then the game play is not correct.
I would prefer not to use a Wait duration because it is just an estimate that the preceeding actions will be completed in 2 seconds or less.
I think it would be better if all the actions waits for the preceeding action to complete before firing. I am not sure how to use a completion handler or DispatchQueue for such purposes.
Is there a better way, more foolproof way to write the game loop?

Spawning Sprite problems in swift3 xCode

Im having some issues, I have sprites spawn on the right of the screen and work there way left then when they go off the screen they are removed from the scene and the process restarts. I want every spawn to get quicker by like 0.1seconds.
Problem is i am calling my spawn function when the game starts and its on a constant loop so i cant then update the delay.
Spawn Code:
func spawnBirdRL() {
let spawn = SKAction.run({ () -> Void in
self.createEnemyBird()
})
let delay = SKAction.wait(forDuration: (TimeInterval(spawnDuration)))
let sequence = SKAction.sequence([spawn, delay])
self.run(SKAction.repeatForever(sequence), withKey: "Spawn")
}
Which is being called in the TouchesBegan function.
It creates the enemy bird and runs the movement loop over and over
I have changed the question slightly with more information...

How do I only allow one instance of an SKSpriteNode on screen at one time?

This is my first ever post - I have searched for a long time and could not find the answer.
I am making a game with SpriteKit and want the player to be able to only launch one bomb at a time- i.e they can't fire again until the previous bomb has exploded or gone off screen. Currently when the player taps the screen, they can launch as many bombs as they want.
Any help would be greatly appreciated!
Thanks,
Iain
Steve's idea works out well and is better than mine, but here is a more novice-friendly explanation IMO... Put this in your gamescene :)
var canFireMissile = true
func fireMissile() {
guard canFireMissile else { return }
canFireMissile = false // So you can't fire anymore missiles until 0.5secs later
let wait = SKAction.wait(forDuration: 0.5) // the duration of the missile animation (example)
let reset = SKAction.run { canFireMissile = true } // lets us refire the missile
let sequence = SKAction.sequence([wait, reset])
run(sequence)
}
override func mouseDown(with event: NSEvent) { // touchesBegan on iOS
fireMissile()
}
Create a SKSpriteNode property for your misssile.
Create an SKAction for the movement of the missile and give the action a key so you can refer to it by name).
When the fire button is pressed, check to see if the named action is already running; if it is, do nothing, otherwise run the ‘fireMissile’ action.

Cannot unpause game when bringing app back to Foreground

SpriteKit is automatically pausing my app when it goes into the background. This is fine, except it stays paused when the app becomes active again. I'm trying to un-pause the game in the appropriate application events, to no avail. I'm manually un-pausing the two SKViews and the game Scene that constitute the app. From inside the AppDelegate file:
func applicationWillEnterForeground(application: UIApplication) {
if let vw = self.window?.rootViewController {
let gc = vw as! GameViewController
let parView = gc.view as! SKView
parView.paused = false
gc.gameView.paused=false
gc.gameScene.paused=false
println("paused = \(gc.gameScene.paused)")
}
}
func applicationDidBecomeActive(application: UIApplication) {
if let vw = self.window?.rootViewController {
let gc = vw as! GameViewController
let parView = gc.view as! SKView
parView.paused = false
gc.gameView.paused=false
gc.gameScene.paused=false
println("paused = \(gc.gameScene.paused)")
}
}
At the end I print the pause state. If I hit the device's Home key and then return to the app, it prints false as desired. However, somewhere (not by my code) this is being immediately set back to true, and the game remains paused.
Update
I overrode the scene's paused property, and it is definitely being set back to true after I un-pause in the given events. Confusing, because from reading other questions, the typical behavior of sprite kit is to automatically un-pause the game when the app is reactivated. Yet it's doing the exact opposite for me.
Well, I basically gave up on trying to control whether the game pauses/resumes during the app's state changes. Instead I overrode the scene's paused property, so now I can just detect whenever sprite kit decides to pause or resume, and handle that accordingly. My suspicion is that my hierarchy of SKViews in my app might not be conventional, and maybe caused sprite kit difficulty in controlling the scene state, but that's only a guess.

SKView paused automatically resumes

I am designing a SpriteKit game in swift, and inside my gameplay SKScene I have a method called when I want to pause the game. It looks like this:
func pause() {
view?.paused = true
}
The game pauses perfectly, but after a seemingly arbitrary amount of time (1 second to 120 seconds), the game just unpauses/resumes gameplay, without ever calling my resume() method. I am aware that sprite kit resumes gameplay automatically upon the app becoming active, but I have set a breakpoint in applicationDidBecomeActive, and it is not called. Does anyone know why this is happening?
I know I could set my own paused property and check it every update loop, but I much prefer this elegant solution if I could get it to work!
The problem was my implementation of ADBannerViewDelegate. Here is the culprit:
func bannerView(banner: ADBannerView!, didFailToReceiveAdWithError error: NSError!) {
skView.paused = false
println("bannerView:didFailToReceiveAdWithError called inside GameViewController class")
}
I solved the problem by putting those println calls inside every method that had a .paused = false statement. Most of the time the banners load fine, but every once in a blue moon they fail and call that method.

Resources