I am developing a Cocos3d based iOS project. I am running a scene once the app is launched and clicked on "Start scene" option. I have a Back button in the scene. Clicking on this Back, will take us to app home screen. Clicking on again "Start scene" option, currently it launches the previous scene itself. But, whenever Back button is clicked , i want to stop the running scene and unlock all the resource. And then again "Start scene" option, it should launch scene freshly.
Could someone advise, how to stop the running scene and unload all resources pod etc.?
Thank you!
You can try the following to stop displaying a Cocos2D CCScene (including any 3D scenes being displayed), and releasing all cached objects:
CC3Texture.shouldCacheAssociatedCCTextures = NO; // Breaks links between Cocos3D textures and Cocos2D textures
[CCDirector.sharedDirector end]; // Removes active CCScene and clears Cocos2D caches
[CC3OpenGL.sharedGL clearOpenGLResourceCaches]; // Clears Cocos3D caches
If you are using a CC3ViewController subclass, and you don't expect to need any OpenGL for a while, then you can also use the terminateOpenGL method to perform all of the above, plus completely shutdown OpenGL. See the CC3DemoMultiScene demo app for examples of doing this.
This seems like such a basic concept but there is really no good answer.
I currently have a pretty basic setup, in my game's scene, I have an enum gameState which is currently either inGame or gamePaused.
I have my button set up, and I have it so pressing simply toggles gameState.
Then, to make it work, I have two separate update methods: One for when gamePaused, one for when inGame.
This works for 95% of my game, as the updates in my game can be pretty readily started and stopped without any issues. There are some issues I cannot tackle though.
First and foremost are actions. I use SKActions for a bit of my project (some movement, scaling, fading...) and this method does NOT pause them. This can be catastrophic in certain points. Secondly, this doesn't handle particles, physics, and a few other things that are not directly associated to my update methods.
The only clue I have is self.view.paused = YES, but that isn't going to work either.
First off, this DOES fix my actions, particles, and physics problem... kinda. But This question suggests that SKActions aren't actually PAUSED by this, but actually STOPPED completely. Is this true? If it is, then it won't work smoothly either because my actions are thrown out of whack.
Also, pausing the view seems to do what it says: stop everything. EVERYTHING. Newbie question here, but how am I supposed to get any code to run at that point? It's all cut off. Is this where I need subViews? I have never used a subView yet, but it sounds like its what I want in this case.
Simply put, there are a lot of unanswered questions for me, and I don't know how to proceed. I'm hoping there's some 'standard procedure' for pausing in Sprite Kit, but with pausing the view halting actions I truly have no idea where to proceed.
Should I move away from using actions? Is my idea of a pause subView sound?
I don't want to babble, all I want to know is how you go about pausing in your average Sprite Kit project. Additional info provided upon request.
Pausing a node will pause (not stop) the node's actions, and i suppose pause will also be applied to all children of the paused node in the same way. All other unpaused nodes will continue to run their actions to completion.
You should have a "game layer" node with all game nodes in them that you want to pause, and then just pause that "game layer" node. Then have a "pause game menu" node where you add all the pause menu stuff you need which will continue to function normally even if the game layer is paused.
Be very sure you do not use performSelector or NSTimer or GCD or any other scheduling methods besides actions or the scene's update: method because those will not adhere to a node's paused state.
Pausing the view effectively freezes everything in it, pausing the scene according to some will not pause the update: calls - but I have not verified this myself. If this were the case you can always check inside the update method whether a given node that you send a message to is paused and if so, decide not to send certain messages to that node.
I just called a map function on all children of the scene and set the paused property to true
self.children.map{($0 as SKNode).paused = false}
By setting it to true you can easily undo the freeze.
EDIT:
Better use a for-loop to iterate over the children.
for node in self.children as [SKNode] {
node.paused = false
}
I can tell you what I did in my game:
Pause the SKView on -applicationWillResignActive: (or equivalent, using NSNotifications),
Un-pause the SKView on -applicationDidBecomeActive: (or equivalent, using NSNotifications),
For the actual game scene only, I set a boolean flag _isPaused when resigning active, and if it is true I just skip the -update: method (frame updates). (I also show the "paused" menu when the user resumes the app).
...But my game is a simple puzzle game, and there's no long actions that should continue past the pause/resume. I can not confirm right now that all actions are aborted, but I think it's not the case.
I also used self.children.map{($0 as SKNode).paused = false} and it does work if you create a var layer of type SKSpriteNode and add it on top of the scene. But I also have an NSTimer I'm using to spawn sprites on the scene. Everything currently on the scene is paused, but sprites keep appearing and moving across the screen. It is not pausing the spawning.
I tried pausing the NSTimer when I call the above code by setting repeats to false, then setting it to true when I remove the layer but it doesn't work. I also tried self.scene?.view?.paused = true but that freezes everything and the layer I create does not even appear onscreen.
You need to set the delegate for the View!
func PauseGame(){
self.scene.view.paused = true
}
fun playGame(){
self.scene.pause = false
}
This function is work perfectly if you are not using the NSTimer to call a function. If you use NSTimer your view will pause perfectly but when you play the game again by play game functionality you see that all the functions that use the NSTimer function that runs in the back end and your screen full with your sprite-kits. So when you use NSTimer in the function you have to first pause the NSTimer functions also after that this function work perfectly.
//For Pause
func pauseGame() {
scene?.view?.paused = true
}
//For play.
func playGame() {
scene?.view?.paused = false
}
I am developing a game with cocos2d. Naturally, I have a menu button.If it's clicked , there will be "void" called , where I stop all current actions with [[CCDirector sharedDirector] pause]; and introduce a menu.
Also, I have sprites that are stopped and have instructions if they are touched (just some MoveTo actions). When I click on sprites during pause there appears a mistake(as I think, because of that instruction).
So, I assume, that sprites should be untouchable during game pause. How can I make a single sprite untouchable? Are there better ways to avoid such a mistake?
Once you use [[CCDirector sharedDirector] pause]; then your complete cocos2d is paused. So if you have written some cocos2d actions inside the touch callback or written something to do like move sprite etc on touch then you will encounter a crash. Instead try to stop all actions and schedulers on the scene and proceed further. You can stop all actions and schedulers as below:
[self pauseSchedulerAndActions];//This will pause all the scheduler and actions running on current scene. Note this will not unschedule the update().
To stop the update method as well do-
[self unscheduleUpdate]; //This will stop the cocos2d update method
Once you paused this way now you can perform any action on the sprite and once done then you can resume as below:
[self resumeSchedulerAndActions];
[self scheduleUpdate];
I'm having an issue going back and forth between my Menu scene and Preferences scene in my cocos2d project. I start in the Menu and when a user clicks a button it takes them to the preferences scene.
[[CCDirector sharedDirector] pushScene:[CCTransitionSlideInR transitionWithDuration:.3 scene:prefScene]];
The preferences scene has a back button to take the user back to the menu.
[[CCDirector sharedDirector] popScene];
This works fine unless the user exits the preferences scene and then tries to go back into it. The second time the preferences scene is opened all of the buttons animate when they are touched but are otherwise unresponsive.
Thanks for the help!
I have had something similar, there were two solutions I found:
Quick and Dirty is to create the preferences scene instance as you need it (lazy loading), this will reduce memory of keeping it around unless you need it, but you will have to initialize it each time, however it should be new clean copy each time, and if the user doesn't click preferences every time probably faster to load the whole game.
Make sure the preferences scene cleans itself up before it disappears, this especially means stop all Scheduled selectors or interval timers and remove delegates and touch events.
I have a UISplitviewController app that's structured like the picture in this question:
UISplitViewController on iPad with Storyboards?
When I click on either Game #1 or Game #2, their respective game run.
However, if I click on the second game (either #1 or #2), I get this
error:
Terminating app due to uncaught exception
'NSInternalInconsistencyException', reason: 'You can't run an scene
if another Scene is running. Use replaceScene or pushScene instead'
How can I check to see if there's already an existing Cocos2d scene
and replace it when the second game is clicked? Ideally, I think I should keep both games running so
the user can click back to the other game. Is
this possible?
I tried to simply replace this line: [director runWithScene:scene];
with this line: [director replaceScene:scene];
Unfortunately, I get an error CCTextureAtlas.m, in method:
-(void) drawNumberOfQuads: (NSUInteger) n fromIndex: (NSUInteger) start {...}
[Update]
I think I might need to stop the scene so everything is cleaned up properly. When I click on my Help screen, for example, my controller's viewWillDisappear gets called. This does not happen when switching between Cocos2d view controllers.
After following these instructions, and only creating the EAGLView once, I almost have it working, but I get a black screen for the second scene. Note that I do briefly see the new scene.
How can I check to see if there's already an existing Cocos2d scene
and replace it when the second game is clicked?
if ([[CCDirector sharedDirector] runningScene] == nil) {
[[CCDirector sharedDirector] runWithScene:sceneToRun];
} else {
[[CCDirector sharedDirector] replaceScene:sceneToRun];
}