how to pause DynamicAnimator - ios

i keep seeing these methods,
– dynamicAnimatorDidPause: required method
– dynamicAnimatorWillResume: required method
But i've not found a way to call them. Ive set up an animator and called <UIDynamicAnimatorDelegate> in the .h, but I cannot seem to call pause on the self.animator for some reason.
Anyone have any tips for me?
Thanks!

Those are delegate methods, which means that you don't call them, they get called for you. You implement a delegate to get informed about certain events
The dynamic animator pauses by itself when all movement stops. Try adding a gravity effect with no collision boundaries. The animator should pause when all dynamic items fall offscreen.

Related

UIViewPropertyAnimator - simply stop all animations, rather than a specific one?

In UIViewPropertyAnimator, is there a way to just stop all UIViewPropertyAnimator animations?
Or perhaps simply get all current animations - then of course you could stop them all.
Can this be done?
Or do you really have to
(a) do only one per UIViewPropertyAnimator,
and,
(b) keep a reference to each of those?
Every animation has to have atleast one UIViewPropertyAnimator instance. In order to stop the animation, we have to explicitly call stopAnimation(_:) on the animator instance.
A way would be to make a factory class to fetch UIViewPropertyAnimator instance and keep track of it in a set or array. And then use this factory class to stop or start all the animations at once. Or use one UIViewPropertyAnimator to perform all your animations and stop it.

touchesBegan() not being called on subviews

I have a class called SKButton, subclass of SKSpriteNode, which implements the touchesBegan() function to print("hello"). But when i add an SKButton object to my view, touchesBegan() never gets called on the button. Why?
You need to make sure that userInteractionEnabled is enabled on all of the superviews of your view.
Also keep in mind that coming from Swift 2.3 to Swift 3 in your project might trigger the warning for the name of the method, you update it using the default fix and then you end up like me wondering why the methods related to touches are not called despite of the fact that you set userInteractionEnabled. Fix: make sure that method name is written as per your current version of Swift!

In SpriteKit does touchesBegan run in the same thread as the SKScene update method?

In the Apple documentation here Advanced Scene Processing it describes the update method and how a scene is rendered, but it does not mention when input is processed. It is not clear if this is in in the same thread as the rendering loop, or whether it is concurrent with it.
If I have an object that I update from both the SKScene update method and the touchesBegan method (in this case of a SKSpriteNode) do I have to worry about synchronising the two accesses to my object?
So after a few days with no answer I set up some experiments. By the way, these tests are run on the simulator and not on an actual device, but I think it would be the same.
First test, I set a breakpoint in the debugger on touchesBegan and looked at the stack trace. It appears that touchesBegan is called from the first thread and from the main loop - the same place as the rest of the logic, so this looks good for a singe-threaded approach.
Second test, I overrode the various methods in the scene mentioned in the Advanced Scene Processing link above and added print statements to show th name of each function called. Then I added a print statement to the touchesBegan method.
On running the app, the output was:
update
didEvaluateActions
didSimulatePhysics
didApplyConstraints
didFinishUpdate
touchesBegan in scene
update
didEvaluateActions
didSimulatePhysics
didApplyConstraints
didFinishUpdate
update
and this pattern was repeated whenever I clicked.
No amount of clicking gave me anything else than touchesBegan being called between the didFinishUpdate (that is, the end of one cycle) and the update (the beginning of the next).
Conclusion: touches processing happens in the main loop before the update method is called. It is therefore not necessary to synchronise resources between the two methods.

Calling method when a node is removed from an SKScene

Is there a way to hook into the SKNode lifecycle in Sprite Kit? Specifically I would like to perform some code when the node gets removed from the scene.
The use case I would like to solve in a bit more detail :
I have some nodes that interact with each other, and I would like them to be notified of certain events that happen to the other nodes. For example, imagine a game where you can tap a node on the scene, and the node's details would appear on a HUD. I would like the HUD to disappear when the node gets removed from the scene.
I plan to use NSNotificationCenter as the notification engine.
Whenever a node gets removed from the scene I would like to post a notification. The easiest way would be to tie into a lifecycle method on SKNode (my nodes are subclasses of SKSpriteNode) like nodeWasRemovedFromParent, but I didn't find any such method.
How can this be done?
I put some thought into coding my own solution by overriding the removeFromParent method in my SKSpriteNode subclass, and posting a notification before calling the super implementation. I am not sure that the removeFromParent method will always be called though. For example, does it get called when I change scenes?
Thanks.
You need to subclass each node class. Override the removeFromParent method as you said. Use only the subclassed versions, otherwise your code won't take effect.
In addition you will want to override removeAllChildren and removeChildrenInArray: or just never use them.
The removeFromParent method will not be called when the scene changes. Instead, override the scene's willMoveFromView: method and send a message to registered observers or simply all child nodes recursively. Use the scene's enumeration function to do so. Note that I'm not 100% sure whether on willMoveFromView the scene's children are still attached, I assume they will.
Unfortunately it's impossible to just subclass SKNode and then expect the subclass' code to work for all other node classes, because those subclass from SKNode directly and not your custom SKNode subclass. Hence you need to subclass and add this code to every SK*Node subclass as well if you need it to be notified on removal.
See KoboldKit node classes for an example, which uses a macro to inject this "override" code into SK*Node subclasses to avoid duplicating the code. The actual functionality is in KKNodeShared: https://github.com/KoboldKit/KoboldKit/tree/master/KoboldKit/KoboldKitFree/Framework/Nodes/Framework

Does willMoveToSuperview will also deallocate the UIView on which its got called?

I was wondering if I can call willMoveToSuperview on UIView and after that retain that view to reuse later for one ? something like following
if (!CGRectIntersectsRect(cell.frame, visibleRegion)) {
[cell willMoveToSuperview:nil];
[self.resuableCells addObject:cell];
}
I am not sure about your intent here...
But WillMoveToSuperview - According to doc:
The default implementation of this method does nothing. Subclasses can override it to perform additional actions whenever the superview changes.
So your code,
[cell willMoveToSuperview:nil];
Has no effect unless you override this method in a cell subclass and implement your own logic there.
Coming to your question -
Does willMoveToSuperview will also deallocate the UIView on which its got called?
Answer is obvious - NO.
willMoveToSuperview is an observer method that the system calls as a courtesy to you in order to give you a chance to handle special cases before it completes some other hidden tasks.
It's default behavior is to do nothing, but you might want to tidy up something in your code prior to a move by overriding this method.
A proper use case might be if you had a view playing a video clip or an animation, and something else in your code is about to rip the view out of it's current hierarchy and place it in some other un-related view hierarchy. You might want the chance to pause the clip or suspend the animation before the move took place.
I doubt it's the right method to handle what you are attempting, and I definitely know you should not be calling it directly.
Feel free to post some more code to show us what you're trying to accomplish and where it's going wrong.

Resources