Does running a SKTransition on a SKScene destroy the origin SKScene? - ios

Does running a SKTransition on a SKScene destroy the origin SKScene?
For example:
SKTransition *reveal = [SKTransition revealWithDirection:SKTransitionDirectionDown duration:1.0];
GameConfigScene *newScene = [[GameConfigScene alloc] initWithSize: CGSizeMake(1024,768)]];
// Optionally, insert code to configure the new scene.
[self.scene.view presentScene: newScene transition: reveal];
Will the current scene be destroyed when the transition is executed? Or is still on memory? Has the new scene a reference to the old scene?

Lets assume that your scene property is like this #property(weak) SKScene *scene; then the answer is YES, will be destroyed when you present another scene or pop it from the stack.
If you have your property like #property(strong) SKScene *scene, then the answer is NO, your scene will stay in memory until you do this self.scene = nil;
But remember that the SKView retinas the presented scene so you should nil it somewhere in your app to avoid retain cycles (when you have strong property).

Adding to the previous answers, if you're still unsure and want to easily check when/if the original scene is deallocated, you can do this simply by overriding the dealloc method and logging a message/setting a breakpoint to see if it was invoked by the runtime. Put this in your old scene:
-(void)dealloc {
NSLog(#"Old scene deallocated");
}
By default (if not strongly referenced elsewhere), it will be deallocated after the entire transition has finished and the new scene has fully moved to your view. So, for the duration of the transition, both scenes will exist in the memory.

ARC will deallocated the old scene, unless you specifically strong referenced it elsewhere.
It is not referenced in the new scene by default.

Related

Presenting SKScene BAD ACCESS crash

I'm building a fairly simple game in SpriteKit. This is my first experience with SpriteKit and so far it has gone smoothly. I have gotten to the point now that I want to present a new SKScene when the player completes the game. I'm getting a Bad Access crash that I can't seem to diagnose.
I think I am presenting the scene correctly:
UnlockRockets *scene = [[UnlockRockets alloc] initWithSize:self.scene.size];
[self.view presentScene:scene];
Every time I get the following error on the presentScene: line - Thread 1: EXC_BAD_ACCESS (code=1, address = 0x10)
Looking at the thread trace it appears the crash might be originating at [SKNode isPaused]
Any advice would be great, I'm completely lost on this one.
i think problem in your initWithSize method inside UnlockRockets class
I have had the same issue with SKView present scene, even when scene was absolutely new without any configurations. So I solved it by using this.
myScene *newScene = [myScene sceneWithSize:size];
newScene.scaleMode = SKSceneScaleModeResizeFill;
SKView *currentskView = (SKView*) self.scene.view;
SKScene *currentScene = (SKScene*) self.scene;
[currentScene removeAllChildren];
[currentScene removeFromParent];
[currentskView presentScene:newScene];
also I've noticed that if declare strong reference for the scene - it's works in the way you did, but in that case scene live in memory even if it's invisible, and xCode notifies that there are memory warnings.

How to completely unload SpriteKit Scene

When I hit the retry button in my game, I want it to reload the MainScene. I am doing this with:
-(void)retry
{
SKTransition *transition = [SKTransition fadeWithDuration:.4];
MainScene *gameOver = [[MainScene alloc] initWithSize:self.size];
[gameOver didMoveToView:self.view];
[self.scene.view presentScene:gameOver transition:transition];
}
However, this is causing the memory/CPU usage to increase (by a lot) each time I hit retry. After about 10-20 retries, there is a noticeable lag.
I made all my SKEmitterNode and SKSpriteNode static and that fixed the memory problem, so I suspect that my sprites, emitters, etc are not being released from the memory and are being re-loaded every time I hit retry, doubling it.
I am loading the sprites/emitters like this:
#implementation MainScene {
SKEmitterNode *_bubbleEmitter;
SKSpriteNode *_sunglasses;
...
}
- (id)initWithSize:(CGSize)size
{
if (self = [super initWithSize:size])
{
_sunglasses = [SKSpriteNode spriteNodeWithImageNamed:#"sunglasses"];
[_sunglasses setPosition:CGPointMake(self.size.width/2, self.size.height + 10)];
[self addChild:_sunglasses];
...
}
return self;
}
Am I loading the sprites or the retry wrong?
This may or may not be the cause, but it's certainly wrong to call this method yourself:
[gameOver didMoveToView:self.view];
The didMoveToView: method is sent to the scene by the SKView when you present the scene. That means this method will actually run twice.
Also verify that your scenes are deallocating properly by implementing:
-(void) dealloc
{
NSLog(#"dealloc: %#", self);
}
Watch for the log or set a breakpoint to confirm the scene deallocates. If it isn't, check for memory leaks and retain cycles.

Cocos2d v3 modal pause view implementation

I am trying to make my pause screen in my game. I am using the framework Cocos2d V3 RC4 in IOS and XCODE and SpriteBuilder. I read a lot of post and i think that i have two aproachs posible:
1º Push a total scene foward the main scene. (THIS WORK FINE TO ME)
In the MAIN SCENE i call this to pause the game
CCScene *pausa = [CCBReader loadAsScene:#"Pausa"];
[[CCDirector sharedDirector] pushScene:pausa];
and then in the Pause class i call this to pop the pause scene and take back the Main scene:
[[CCDirector sharedDirector] popScene];
2º Take a CNode in front of the MAIN SCENE, making it with transparency, opaque, and disableing the main scene touch, animations, actions, etc… (THIS DOESN’t WORK FOR ME AND I WHANT THIS !!!)
I doit in this way:
In the main Scene:
CCScene *pausa = [CCBReader loadAsScene:#"Pausa"];
[self addChild:pausa];
AND I TRY with ALL THIS METHODS:
// [self unscheduleAllSelectors];
// [self stopAllActions];
// [self setPaused:TRUE];
// [self setUserInteractionEnabled:FALSE];
The node is added but Have not Touch exclusively… The Node that is behind I can touch it…
I try olso with :
[[CCDirector sharedDirector] pushScene:pausa];
(in the main scene) with result obviosly bad, and i try with
[self setExclusiveTouch:TRUE];
in the pause didLoadFromCCB method but also I cant make it have a Exclusive touch. i Can STILLPRESS buttons and sprites from the back Node…
What I am doing Wrong, And how is the correct code/aproach tu use to handle a pause node like I want for method 2??
Resuming... I only want a Modal Window... (like in zk framework, in java, the Window (CNode in Cocos2d) come in front and the background keep disabled and in grey)
Thanks for read and hope someone can help
Here is my implementation from a game that I am doing
- (void) pauseGame
{
CCLOG(#"Pause game");
_contentNode.paused = YES;
_contentNode.userInteractionEnabled = NO;
_gamePausedNode = (GamePausedNode *)[self loadCCBWithNameAndPositionInCenter:#"PausedNode"];
[self addChild:_gamePausedNode];
}
gamePausedGame is a CCNode, but it could be CCSprite as well. It is not actually a CCScene, nor is it loaded by one because a modal view like this is not really a scene.
You usually want to group the CCNode objects together in one CCNode like my _contentNode so you can pause them with one click.
Update : I have edited the code to the bare minimals
CCPhysicsNode *_physics;
_physics.paused = true;// It will pause your game but not actions.
_physics.paused = false;// It will resume your spinning and falling of sprites while button is pressable like during pause game.

Why I can't reset my CCParticleSystemQuad from the parent CCLayer?

I've added an additional CCLayer to my "GameScene" that becomes visible ([self addChild:_congratsScreen]) whenever my character collects a given amount of objects on the screen.
Within my GameScene.h I've declared my child layer (CClayer *congratsScreen) and I'm synthesizing it on my GameScene.m. I'm allocating the child CCLayer in the GameScene's init method so it is holding the reference to the child layer in this instance variable.
On my GameScene I have a few CCParticleSystemQuad instances, and it's super simple to invoke both stopSystem and resetSystem to replay my particles animation, but if I try to do the same thing on the CCParticleSystemQuad that was initialized on the child layer, the resetSystem doesn't work after I remove the child from my GameScene and add it back again. Does something happens with the CCLayer's components once it is removed from a parent layer's scene?
I don't have the code at the moment so I will try to write some pseudo-code to illustrate how it's being done:
How it is being initialized on ChildLayer.m:
_sparkling= [CCParticleSystemQuad particleWithFile:#"sparkling.plist"];
Then, somewhere on GameScene.m I have:
- (void) showCongrats {
//pathetic way to create a modal panel
[self setTouchable = NO];
[[[self _congratsLayer] _sparkling] resetSystem];
[self addChild:_congratsLayer];
}
- (void) hideCongrats {
//let them continue playing
[self setTouchable = YES];
[[[self _congratsLayer] _sparkling] stopSystem];
[self removeChild:_congratsLayer];
}
So, it works on the first time I invoke showCongrats, the reference is good and I can manipulate the particles, but once I hide the layer, continue playing the game and show the congratulations panel again, it shows a frozen animation of the particles from the last invocation, the resetSystem no longer works. Any ideas?
I would add some breakpoints in the code and walk through it but if I had to guess I would say that when you are calling removeChild you are losing the data that you had in your init method and something funky is happening.

Learning Cocos2D book out of date with scenes

I'm trying to learn Cocos2D from Learning Cocos2D, A hands-on guide by Rod Strougo & Ray Wenderlich, but it uses Cocos 1, not 2 which is out now. I imagine the book is still relevant later on, but in the first chapter I'm running into an issue telling the director to run a scene, because it seems like that whole process is now different in Cocos2D 2.
I'd rather not have to buy a different book, so I was hoping that changing the way to run a scene is fairly simple.
This is what the book says to do:
find the -applicationDidFinishLaunching method and comment out:
[[CCDirector sharedDirector]runWithScene: [HelloWorld scene]];
and add:
[[CCDirector sharedDirector]runWithScene:[GameScene node]];
I can't find anything that looks like that in AppDelegate, instead it looks like this has something to do with the new way:
[director_ pushScene: [IntroLayer scene]];
My attempts to adapt what the tutorial says to the new way has so far failed, but maybe it is an easy fix.
Incase it is the GameScene which is outdated:
GameScene.h
#import <Foundation/Foundation.h>
#import "cocos2d.h"
#import "BackgroundLayer.h"
#import "GameplayLayer.h"
#import "CCScene.h"
#interface GameScene : CCScene
{
}
#end
GameScene.m
#implementation GameScene
-(id)init
{
self = [super init];
if (self != nil)
{
BackgroundLayer *backgroundLayer = [BackgroundLayer node];
[self addChild:backgroundLayer z:0];
GameplayLayer *gameplayLayer = [GameplayLayer node];
[self addChild:gameplayLayer z:5];
}
return self;
}
#end
The issue you are having is with the class method +scene. That is used when creating the scene within a layer instead of initializing a scene and having that instance create its own child layers. You will understand the differences later in the book when you get more into the scene -> layer relationship.
Comment out [director_ pushScene: [IntroLayer scene]]; in -applicationDidFinishLaunching and replace it with the following:
[director_ pushScene:[GameScene node]];
That should work just fine for your needs. It will create an instance of GameScene (subclass of CCScene) with your two CCLayer subclass instances as children, those being the backgroundLayer and gameplayLayer you instantiate in the GameScene -init method.
If you are curious as to why calling [GameScene scene] was not working for you, that is because you never declared such a method in your interface. It is a little confusing, but basically you would instead create a Game Layer subclass of CCLayer and in your .h file, declare this class method:
+ (CCScene *)scene;
In your implementation .m file, you would define that method as such:
// Class initializer method
+ (CCScene *)scene {
CCScene *scene = [CCScene node]; // Create a container scene instance
GameLayer *gameLayer = [GameLayer node]; // Create an instance of the current layer class
[scene addChild:gameLayer]; // Add new layer to container scene
return scene; // Return ready-made scene and layer in one
}
Then when you call [GameLayer scene] that +scene method creates the scene for that layer and adds it as a child. It is quicker, but can be more troublesome with multiple layers in my experience.
Have you tried this:
[[CCDirector sharedDirector] pushScene:[IntroLayer scene]];

Resources