iPhone - starting cocos2d scene from viewcontroller, closing from within scene - iphone

How do I do this?
On one of my UIViews (nib file) I have ImageView and a Button that starts full screen Cocos2d scene. From within that scene I want to close it and go back to UIView, so that user can later open the scene again but from different image in ImageView (and with different content on scene).
However, after the first time I "close" the scene the whole app reacts a lot slower to all touch events. It works fast as long as the scene is on, but when closed then performance goes down.
How should I properly close the scene so that I can restart it again? I've browsed through a lot of code samples and everywhere is just replaceWithScene:newScene.

Adding a UIView to a viewController that houses a running openGL layer slows the app, as anyone who has tried to incorporate a UIScrollView into a Cocos2D game can tell you. You are closing the scene, but likely not stopping the CCDirector, which is now running its own scheduler aside the application's scheduler. As they fight for dominance over the CPU, OpenGL invariably wins as it needs more power more often.
Ensure you are completely shutting down cocos2D and OpenGL. Even if only calling [[CCDirector sharedDirector] pause].

Related

Spritekit FPS drops when presenting UIView

I am finishing one of my project, a game made with Spritekit.
I created a small menu with UIKit (1 view and few buttons).
I connected SKScene and View Controller class to communicate so when game is finished, I am able to present menu.
I noticed problems with SKScene FPS.
I already found some informations from 2015, on apple developer forum that this problem was spotted with iOS 9 for the first time.
When I'm presenting UIView over SKScene, my FPS falls from 60 to 40.
And after I hide UIView and run game again, FPS increases back.. But in about 2-3 seconds, what gives me a lag in my animations on start of the game.
I tried with preloding all texture atlases first and nothing changed.
Than I tought my textures are too big and problem is in my animations, and I decreased all images and its quality from 32bit colors to 16... But problem was not solved.
Then I also noticed that FPS is worse, if I animate UIView..
So there is definetly problem with combining SpriteKit and UIKit.
I could pause scene before presenting UIView and unpause second or two after my view disappear again, and yeah maybe users wouldn't notice problem..
But what if I want to run my Scene in background of my UIView (like endless scrolling backgrouns), so background would move constantly when user enter menu?
I know, I could do the menu with SpriteKit, but this approach seemed to work fine 2 years ago when I was last time using SpriteKit.
Okay.. I am posting an answer, if somebody else is searching a solution for similar FPS problems.
After your comments and recommendations what to do, I tried few different things and figured out some problems.
I tested it on two physical devices iPhone 6S and iPad 2. Of course results on iPad 2 are a bit worse.
UIKit and SpriteKit are surely not working best together.
I figured out that there are no big problems with just presenting other UIViews or UIButtons over SpriteKit scene - FPS drops a bit but not really much, that this would make some big impact on your scene (2-3 FPS).
Biggest problems came in if you're trying to animate Views with some basic animations. In that case FPS (in time that animation is happening) drops to 40 - 35 FPS, and the biggest problem with this is, that sometime it just wont raise again until you make another animation or run scene again.
I still don't know why this is happening, but it happens randomly. Sometimes FPS raises and sometimes not.
Another thing that also have big impact on SpriteKit frame rate are Ads if you're using them.
I am using AdMobs and in their documentation it's well written, that Banners or Interstitial Ads can make impact on your frame rate. I am not presenting Ads during gameplay, but also if you're presenting them in menu, this will decrease your FPS and when you run your game and your FPS drops again for a bit, the result will be even worse.
So I suggest you run your Scene with delay or hide banner a bit earlier so it won't have impact on your start of the game.
I found solution for my problem with pausing the scene as soon as gameplay ends, so when menu appear my Scene is on pause mode. And after I run my game again I am un-pausing my Scene. It's not the best solution for my case, but it works much better now.
I suggest to use SpriteKit also for your menu creation, this way you won't have such problems. Or even better - use some other game engine for your game creation.

Unity - LoadLevelAsync hiccups on scene switch

I am trying to make a loading animation while using LoadLevelAsync to load the next scene.
The loading animation is a loading circle that continuously rotates in the middle of the screen, and I use LoadLevelAsync("NextScene") in the code. The problem is that every time right before the scene switch happens the circle will freeze for a few milliseconds before the next scene appears.
I do know that the less things the next scene contains, the shorter the freeze is, but I thought that LoadLevelAsync's purpose was for letting the user experience no lag during scene transitions. My next scene contains a background sprite, some buttons, scripts, and a 3MB audio file. The screen will always freeze for half a second before showing the next scene.
I am using Unity 4.6.3 with Pro feature. I'm also testing the results on a device. I have also tried out the AsyncOperation.allowSceneActivation with Coroutines, and unfortunately they don't work.
If anyone has a solution, or has any suggestions on smooth scene transitions, I would greatly appreciate them.
Thanks in advance.

How can I popScene a specific Cocos2D scene from another scene?

I have a game that I developed, and there are three scenes: the pause menu, the home screen menu, and the gameplay itself. During the gameplay, when the game is paused, it brings up the pause scene with:
[[CCDirector sharedDirector] pushScene:[PauseScene node]];
From the pause scene, there are three options: restart, resume, home menu. When clicking on resume it just pops the pause scene and goes back to the game scene to resume gameplay. When clicking on the home menu it keeps the gameplay scene in the background, and from the home menu screen, the gameplay is still running. So far, after much research, I have not been able to find a way to popScene (kick it out of the RAM pretty much) the gameplay scene from any scene but the gameplay scene. From the pause screen, I can use:
[[CCDirector sharedDirector] popScene];
to get rid of the pause scene, and if I run that code from a method on the gameplay scene, I can get rid of that instance of gameplay, but I need a way to popScene the gameplay node that is running in the background from the pause node. Overall, the basic question is: How can I pop a specific scene in Cocos2d from another scene?
There are two main features to change scenes in Cocos2d: pushScene/popScene and replaceScene.
The first is pushScene:
(void) pushScene: (CCScene *) scene
Suspends the execution of the running scene, pushing it on the stack
of suspended scenes. The new scene will be executed. Try to avoid big
stacks of pushed scenes to reduce memory allocation. ONLY call it if
there is a running scene.
This function utilizes a stack . It stores all the scenes in a Last In-First Out (LIFO) data structure. Basically it overlays the scenes and removes them in the reverse order of which they came. This is likely what you want to "push" (or bring up) the pause menu, and "pop" (remove) the pause scene back off to then resume gameplay.
To go back a layer, you simply call popScene:
(void) popScene
Pops out a scene from the queue. This scene will replace the running
one. The running scene will be deleted. If there are no more scenes in
the stack the execution is terminated. ONLY call it if there is a
running scene.
2.The other option, which I believe you will want, is replaceScene. This stops a currently running scene and replaces it with a completely new one. This is likely what you want for ending games or transitioning from the original main menu to the gameplay for the first time:
(void) replaceScene: (CCScene *) scene
Replaces the running scene with a new one. The running scene is
terminated. ONLY call it if there is a running scene
*Keep in mind: Use pushScene sparingly. It stores all of the scenes in memory so that they can later be popped of the stack. So don't store too many scenes and forget about them.
**Source: cocos2D website
EDIT 1:
You have a few options. Remember that replaceScene only replaces the currently running scene and is usually what you want to use. It does not "clear" the entire scene stack, so often you rarely want to use pushScene/popScene. In my demo below, I show you the issues with both. I do, however, try to conserve memory by when possible.
Using push/popScene:
1.Start running with the Home Screen.
2.When the user clicks "Play" button, use replaceScene to stop the Home Screen scene and start running the Game Play scene (keep in mind, Home Screen will no longer be running or saved anywhere in memory. if it has to remember any information, then save it to the stack with pushScene. The reason I do this is because the Home Screen will likely be the same each time and needs not continue to run while we play).
3.The user can now play for a bit. Then they want to pause for a bathroom break. They click a "Pause" button. Then use pushScene to save the current state of Game Play scene and begin running the Pause Menu scene. (Game Play is "paused" so to speak).
Your stack now looks like this:
//Bottom ----------------------> Top
[Game Play scene], [Pause Menu Scene]
4.After pausing for a bit, they could use pushScene to remove Pause Menu Scene from memory, and load the Game Play scene that is "paused" and resume play immediately.
The problem then becomes, well, what if you wanted to go from pause -> main menu. If you just used replaceScene on the Pause Menu, then the old game would linger in memory. You would need to find a way to purge that old Game Play scene.
The other option would have to be keeping Home Screen around by keeping it on the stack with a pushScene and then popping twice. This often causes "jumpy" transitions from my experience.
The preferred approach tends to be: create a Singleton Class and have that save the memory while you pause. (A Singleton Class is just a class that only ever has one instance. It is basically our "current game state" data. I recommend this tutorial.)
Using Replace Scene:
1.Start running with the Home Screen.
2.When the user clicks "Play" button, use replaceScene to stop the Home Screen scene and start running the Game Play scene (keep in mind, Home Screen will no longer be running or saved anywhere in memory. if it has to remember any information, then have a section of the Singleton Class for Home Screen data).
3.The user can now play for a bit. Then they want to pause for a bathroom break. They click a "Pause" button. Immediately "pause" your game and save all necessary sprites, game logic, etc to the Singleton Class, and then use replaceScene to quit from the Game Play scene and load Pause Scene. Then depending on their choice, you either continue play (step 4), or go to the Home Screen(step 5)
4.Reload everything necessary to render the game from the Singleton Class and replaceScene to quit from the Pause Menu and load up Game Play scene.
5.Use replaceScene to quit from the Pause Menu and load up the Home Screen.

Door closing transition in Cocos2d

I'm trying to make the door closing transition like what we can see in Kingdom Rush. (Two doors coming from the left and the right)
What I'm thinking is two approaches:
The first one could be a custom transition getting input as a door image
For this approach, I could not find a way to do it although it is my preferable way
Second approach could be creating the door closing animation on the first scene and push the second scene with the same door closed on the second scene. After that do the door opening animation.
This approach is possible but I wonder if there will be a blink in the scene transition
Has anyone come across this issue?
Thanks in advance
i'd suggest the 2nd one.
it's rather easy to that...something like this:
make an animation in a separate class and in your scene just call the animation to close at the end of the scene and replace the next scene with :[[CCDirector sharedDirector]replaceScene:[NextScene scene]];
If your scene loads relatively fast..it won't blink at all..but if it does (for some reason) make another thread and add "big things" to the next scene in a background thread so that the scene loads instantly, and in the time you animate the doors load the rest .
To detect if the doors are closed...just set a NSUserDefaults BOOL to YES in 1st scene and in the 2nd check if the door is closed.
As for the animation itself just make 2 ccsprites outside the screen and then animate them on the screen.Also..because the sprites are already in memory when you leave the scene, you won't need to load anything in the next scene..so it's instant.
Take a look to the CCTransition.m file in cocos2d sources. There in flip transition classes you can find examples of CCOrbitCamera action usage. In case of scenes it flips them relatieve to their center. But all transitions are made relatieve to node's anchor point. So you can try out different variants.

How can I implement a virtual joystick for a cocos2d game outside the cocos2d environment?

I am developing an iPad game that uses cocos2d and requires a virtual joystick. I have a prototype up and running using SneakyJoystick.
However, I realized that my game design requires me to use CCTransitions to move the user between different instances of CCScene in order to get the visual effect I want. The problem is, I don't want the user controls (like the joystick) to be affected by the CCTransitions- I want them to remain on the screen (in a different part of the screen than the part occupied by the CCScene.)
I realized the only way to do this was to keep the entire cocos2d environment in an EAGLView that occupies an area smaller than the entire screen, which allows me to keep all the user controls elsewhere on the screen, where they are unaffected by the scene transitions.
The problem is, that means SneakyJoystick is probably no longer an option, as it is a CCNode that therefore will probably only run within the cocos2d scene graph.
I am curious if anyone has an alternative solution for this situation: A way of implementing a virtual joystick outside the cocos2d environment, but that can somehow communicate fluidly with the cocos2d scene.
It would be great if I could retain the functionality of SneakyJoystick or something very similar, by either tapping into the scheduled updates of cocos2d from this non-cocos2d class, or somehow otherwise pushing user input information from the joystick class to cocos2d.
Possibly you can create an UIView and put it over the opengl view. To access the openglView use [CCDirector sharedDirector].openGLView. Create your joystick using UIView. So it will be always shown, and will be not affected by CCScene transitions.