I am trying to simply execute a function after 3 seconds in swift 2. I have tried numerous things and none work. It is a sprite kit game in swift 2, Pleas tell me how to do this..
calling the function now looks like this
self.adjustScore()
EDIT Solved like this, thanks googe page 4
let triggerTime = (Int64(NSEC_PER_SEC) * 1)
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, triggerTime), dispatch_get_main_queue(), { () -> Void in
self.adjustScore()
})
})
Normally I would downvote the above answers, but the OP did not specify it is SpriteKit in the question title. In SpriteKit, you do not want to use NSTimers or dispatch timers, because if you pause the scene, you do not pause these timers. Instead, use a combination of SKAction.waitForDuration and SKAction.runBlock to achieve the desired effect
self.runAction(SKAction.sequence([SKAction.waitForDuration(3),SKAction.runBlock({[[unowned self] in self.adjustScore()})])
Try this:
let time = dispatch_time(DISPATCH_TIME_NOW, Int64(3.0 * Double(NSEC_PER_SEC)))
dispatch_after(time, dispatch_get_main_queue()) {
self.adjustScore()
}
Related
I have decided to break off my very painful relationship with SKAction.playSoundFileNamed and move on to using SKAudioNodes in our project -- the breaking point was their being totally broken by interruptions without any consistency.
We are trying to create an extension to SKAction s.t. it will mimic playing SKAudioNodes without adding delay, similar to when you set the waitForCompletion property in playSoundFileNamed to false. However, we are adding the SKAudioNode and then disposing of it after a short period (3.0 s), but in an extension this would add that 3.0 s delay onto any action. I think we must have this delay and then remove because otherwise we would be accumulating SKAudioNodes unnecessarily. Here is our current code:
func playAudioNode(node: SKSpriteNode?, sound: SoundType, delay: Double)
{
if node == nil
{
return
}
let audioNode = audioNodeDictionary[sound]!.copy() as! SKAudioNode
node!.addChild(audioNode)
let playSound = SKAction.run
{
audioNode.run(.play())
}
node!.run(SKAction.sequence([SKAction.wait(forDuration: delay), playSound, SKAction.wait(forDuration: 3.0), SKAction.removeFromParent()]))
}
Does anyone use SKAudioNodes in a similar ad hoc way and use them in SKAction sequences and have any thoughts on best way to implement this?
I'm working with Swift language. I wrote an animation for a timer that lasts for 30 seconds and is full. Now I want to stop this animation, but I do not know how! I want to be able to start again from the beginning. Animation.
Thanks if you have a solution or a method that helps me🙏
You can try
self.myView.layer.removeAllAnimations()
Two possible ways:
Somewhere store variable for total time. And in every timer repeat increase this value. When total time reaches 30 seconds, remove animation
When you start animation, set action which gets executed after specific time
First possible way:
var time: Double = 0
#objc func timerChangedValue() {
time += 1
if time == 30 {
view.layer.removeAllAnimations()
view.layoutIfNeeded()
}
}
Second possible way:
DispatchQueue.main.asyncAfter(deadline: .now() + 30) {
self.view.layer.removeAllAnimations()
self.view.layoutIfNeeded()
}
I want to timeout and break out of this loop in 5 seconds. Only thing I could find online is having a count variable increment every second and then breaking if the count is 5, but was wondering if there's an easier, less codier way. Please help!
locationManager.startUpdatingLocation()
while (locationManager.location == nil) {
//searching...
}
locationManager.stopUpdatingLocation()
The problem with having a while loop is that it will block the user's use of the application if it's on the main thread. Instead of doing that, you should start updating the location and then schedule a background thread using GCD (assuming you're on OSX; GCD isn't available on Linux yet) to run in a five seconds to disable the location manager. You could also schedule it to run in one second, check to see if it's present and then either attempt again or just let it run for five seconds.
you can create a delay function like this:
func delay(delay:Double, closure:()->()) {
dispatch_after(
dispatch_time( DISPATCH_TIME_NOW, Int64(delay * Double(NSEC_PER_SEC))), dispatch_get_main_queue(), closure)
}
and after use it like this:
delay(5){
locationManager.location = //something different from nil or you can try with break sentence ; not sure if with break will work though .
}
I would need help with this while loop - what I'm trying to do is slow down the whole process of removing and adding new circles while radius is changing every time this happens. I'm becoming really desperate, I've tried using both dispatch_after and sleep inside the loop (which I found online) but neither of them is suitable, they basically stop the whole app. If I put them in the while loop, nothing happens. Thanks in advance!
while radius < 100 {
self.removeAllChildren()
addCircle()
radius++
print(radius)
}
Basically you just need to do few simple things:
Wait for a certain duration and add a node to the scene
Repeat this step forever (or certain number of times)
Here is the example of how you can do it. The important part is action sequence. You create the step above, and repeat it forever. Each time you check radius value and based on that you stop the action (remove it by the key). And that's it. You can change spawning speed by changing action's duration parameter.
Using NSTimer might seem like an easier solution, but NSTimer doesn't respect node's (or scene's or view's) paused state. So, imagine this situation:
You start spawning of nodes
User receive phone call and app automatically goes to background
Because NSTimer is not automatically paused, the nodes will continue with spawning. So you have to take an additional step and invalidate/restart timer by your self. When using SKAction, this is done automatically. There are some other flaws of using NSTimer in SpriteKit, search SO about all that, there are some posts which covering all this.
import SpriteKit
class GameScene: SKScene{
var radius:UInt32 = 0
override func didMoveToView(view: SKView) {
startSpawning()
}
func startSpawning(){
let wait = SKAction.waitForDuration(0.5)
// let wait = SKAction.waitForDuration(1, withRange: 0.4) // randomize wait duration
let addNode = SKAction.runBlock({
[unowned self] in //http://stackoverflow.com/a/24320474/3402095 - read about strong reference cycles here
if(self.radius >= 30){
if self.actionForKey("spawning") != nil {
self.removeActionForKey("spawning")
}
}
self.radius++
let sprite = self.spawnNode()
sprite.position = CGPoint(x: Int(arc4random()) % 300, y: Int(arc4random()) % 300) // change this to randomize sprite's position to suit your needs
self.addChild(sprite)
})
//wait & add node
let sequence = SKAction.sequence([wait, addNode])
//repeat forever
runAction(SKAction.repeatActionForever(sequence), withKey: "spawning")
}
func spawnNode()->SKSpriteNode{
let sprite = SKSpriteNode(color: SKColor.purpleColor(), size: CGSize(width: 50, height: 50))
//Do sprite initialization here
return sprite
}
}
The sleep stops the whole app because you are running the loop on the main thread.
You can solve this problem in one of two ways...
1) Use an NSTimer. Set it to the amount of time you want to delay. Put the body of the loop in the timer's trigger function and disable the timer when it has been called enough times. This is the best solution.
2) Wrap the loop in a dispatch async block to a background thread and put a sleep in the loop. If you do this though, you will have to wrap the UI code in another dispatch async block that comes back to the main thread.
I have several buttons (SKSpriteNodes) which I am trying to cycle through and animate, with a small delay between each. My code compiles, but when I run it - I only get a white screen and a crash with this error: "Message from debugger: Terminated due to memory issue". Here is my code:
var sequence = SKAction.sequence([animationUp, animationDown])
runAction(SKAction.repeatActionForever(SKAction.sequence([
SKAction.runBlock({
button1.runAction(sequence)
SKAction.waitForDuration(0.5)
button2.runAction(sequence)
SKAction.waitForDuration(0.5)
button3.runAction(sequence)
SKAction.waitForDuration(0.5)
}),
])))
So what I am trying to accomplish is an up/down animation on every button I'm drawing to the screen, with a 0.5 second delay between each button. The animation should run forever until I change the current screen. I had no problem animating these buttons simultaneously but I'd really like to add a uniform delay so that they don't all animate at the same time. Any ideas?
let waitAction = SKAction.waitForDuration(0.5)
let movementAction = SKAction.sequence([animateUp, animateDown])
let button1Block = SKAction.runBlock({
button1.runAction(movementAction)
})
let button2Block = SKAction.runBlock({
button2.runAction(movementAction)
})
let button3Block = SKAction.runBlock({
button3.runAction(movementAction)
})
let sequence = SKAction.sequence([button1Block,waitAction,button2Block, waitAction, button3Block, waitAction])
runAction(SKAction.repeatActionForever(sequence))
I'm not certain about how the SKAction.sequence initiates/destroys, but possibly your loop in .repeatActionForever(..) creates and destroys objects, whereas memory won't be released until the loop is allowed to complete.
Try to run your inner runAction block within an autoreleasepool { .. } block:
autoreleasepool {
runAction ...
}
But there is one situation we do need to autorelease, that is we
create a lot of objects in a method scope and want to release them
sooner. It is extremely useful when these objects turn to a pressure
on memory.
http://en.swifter.tips/autoreleasepool/