问题
I have been struggling with this for days, for some reason my SKScenes are not deallocating correctly, this results in bounded memory growth as each time i exit and enter a scene the memory jumps up. This means after say 10 rounds of the game the App crashes. As far as i'm aware after much checking i do not have any retain cycles or strong references to the scenes themselves and whilst i know textures are cached and held in memory surely once preloaded the memory shouldn't be going up each time.
This is how i setup the skview and first scene in the viewcontroller:
-(void)loadStartScreen{
SKView *theView = (SKView *) self.view;
theView.showsFPS = YES;
theView.showsNodeCount = YES;
//Sprite Kit applies additional optimizations to improve rendering performance
theView.ignoresSiblingOrder = YES;
// Create and configure the scene.
MainMenuScene *theScene = [MainMenuScene sceneWithSize:theView.bounds.size];
theScene.scaleMode = SKSceneScaleModeAspectFill;
theScene.backgroundColor = [UIColor grayColor];
// Present the scene
[theView presentScene:theScene];
This is the code from within my MainMenuScene to create and move to the next scene:
SKScene *theScene;
SKTransition *theTransition;
switch (theTag.intValue) {
case 0: // start game
// stop music
[[appDelegate musicPlayer]stop];
theScene = [[GameLevelScene alloc] initWithSize:self.view.bounds.size];
// transition type
theTransition = [SKTransition fadeWithDuration:1.0];
break;
case 1: // settings
theScene = [[SettingsScene alloc] initWithSize:self.view.bounds.size];
// transition type
theTransition = [SKTransition flipHorizontalWithDuration:1.0];
break;
case 2: // iap
theScene = [[IAPScene alloc] initWithSize:self.view.bounds.size];
// transition type
theTransition = [SKTransition flipHorizontalWithDuration:1.0];
break;
case 3: // unlocks screen
NSLog(@"scene is %@",self.view.scene);
theScene = [[deletmet alloc] initWithSize:self.view.bounds.size];
// transition type
theTransition = [SKTransition flipHorizontalWithDuration:1.0];
NSLog(@"scene is after %@",self.view.scene);
break;
case 4: // level complete
theScene = [[LevelCompleteScene alloc] initWithSize:self.view.bounds.size];
// transition type
theTransition = [SKTransition flipHorizontalWithDuration:1.0];
break;
case 5: // cheats
theScene = [[CheatsScene alloc] initWithSize:self.view.bounds.size];
// transition type
theTransition = [SKTransition flipHorizontalWithDuration:1.0];
break;
default:
break;
}
Now i know that you should use "[self.view presentScene:]" as the SkView holds the scene but because nothing is working i've been experimenting to see why the scene does not seem to deallocate. When i try pressing the button for case 2 following i get the resulting NSlogs:
[self presentScene:theScene];
NSLOG result = "IAP SCENE DEALLOC" but the user is not taken to the next scene.
[self presentScene:nil];
NSLOG result = "IAP SCENE DEALLOC" but the user is not taken to the next scene.
[self.view presentScene:theScene];
No nslog results even though the current MainMenuScene has an NSLOG for dealloc
[self.view presentScene:nil];
NSLOG result = IAP SCENE DEALLOC and the screen becomes grey
Now this is all very odd as surely when i do get a DEALLOC NSLOG message it should be giving me the NSLOG for the dealloc of the current scene aka MainMenuScene rather than the scene it should be loading.
Am i doing something wrong? Am i working with the SKView incorrectly, any help would be greatly appreciated as i have read a variety of posts all of which have not helped.
- Update: This is the code for each scene that i am moving back and forth between, notice the lack of actions or any strong references to self:
Main Menu:
#import "MainMenuScene.h"
#import "SKScene+SceneUtils.h"
#import "GameLevelScene.h"
#import "SettingsScene.h"
#import "CreditsScene.h"
#import "IAPScene.h"
#import "UnlocksScene.h"
#import "LevelCompleteScene.h"
#import "CheatsScene.h"
#import "AppDelegate.h"
#import "UserDetails.h"
#import "ItemBannerLabel.h"
#import "ItemWindow.h"
#import "TextureList.h"
#import "TextureLoader.h"
@interface MainMenuScene(){
SKSpriteNode *backgroundImage;
SKSpriteNode *topBar;
SKSpriteNode *bottomBar;
SKSpriteNode *ladybirds;
SKLabelNode *title;
SKLabelNode *subtitle;
SKLabelNode *coffee;
ItemWindow *settingsWin;
ItemWindow *iapWin;
ItemWindow *unlocksWin;
AGSpriteButton *startButton;
AGSpriteButton *continueButton;
AGSpriteButton *settingsButton;
AGSpriteButton *iapButton;
AGSpriteButton *unlocksButton;
SKEmitterNode *theParticles;
//SKAction *delay;
//AppDelegate *appDelegate;
}
@end
@implementation MainMenuScene
#pragma mark - Scene Appears
-(void)didMoveToView:(SKView *)view {
// setup UI
[self createUI];
// setup view
[self setupView];
}
-(void)willMoveFromView:(SKView *)view{
}
#pragma mark - CreateUI
-(void)createUI{
// scene size
self.scene.size = [[TextureList sharedManager]returnTextureSize:@"kMMBg"];
// background
self.scene.backgroundColor = [SKColor colorWithRed:0/255.0 green:0/255.0 blue:0/255.0 alpha:1.0];
// masked background
backgroundImage = [SKSpriteNode spriteNodeWithTexture:[SKTexture textureWithImageNamed:kMMBg] size:[[TextureList sharedManager]returnTextureSize:@"kMMBg"]];
backgroundImage.position = screenCenter;
backgroundImage.zPosition = self.zPosition+1;
[self addChild:backgroundImage];
ladybirds = [SKSpriteNode spriteNodeWithTexture:[SKTexture textureWithImageNamed:kMMLadybirds] size:[[TextureList sharedManager]returnTextureSize:kMMLadybirds]];
ladybirds.position = CGPointMake(CGRectGetMaxX(self.frame)-ladybirds.frame.size.width/2, screenCenter.y);
ladybirds.zPosition = bottomBar.zPosition+5;
[self addChild:ladybirds];
// buttons
startButton = [[AGSpriteButton alloc]initWithTexture:[SKTexture textureWithImageNamed:kMMStartBtn] color:[UIColor clearColor] size:[[TextureList sharedManager]returnTextureSize:kMMStartBtn]];
[startButton setLabelWithText:@"" andFont:[UIFont fontWithName:kFontName size:kFontSizeButton] withColor:nil];
startButton.position = CGPointMake(ladybirds.position.x-ladybirds.frame.size.width/4, ladybirds.position.y-ladybirds.frame.size.height/16);
startButton.zPosition = ladybirds.zPosition+1;
[startButton addTarget:self selector:@selector(buttonPressed:) withObject:[NSNumber numberWithInt:0] forControlEvent:AGButtonControlEventTouchUpInside];
[self addChild:startButton];
// emitter
theParticles = [NSKeyedUnarchiver unarchiveObjectWithFile:[[NSBundle mainBundle] pathForResource:@"FlowerPetalParticle" ofType:@"sks"]];
theParticles.zPosition = backgroundImage.zPosition+1;
theParticles.position = CGPointMake((CGRectGetMinX(self.scene.frame)),startButton.position.y);
theParticles.particlePositionRange = CGVectorMake(0.0, CGRectGetMaxY(self.frame)-topBar.frame.size.height-bottomBar.frame.size.height);
if ([[[UserDetails sharedManager]userDevice]isEqualToString:@"ipad"]) {
theParticles.particleLifetime = 8.0;
theParticles.particleScale = 0.5;
theParticles.particleScaleRange = 0.2;
}
[self addChild:theParticles];
topBar = [SKSpriteNode spriteNodeWithColor:[UIColor whiteColor] size:[[TextureList sharedManager]returnTextureSize:kMMTopBar]];
topBar.position = CGPointMake(screenCenter.x, CGRectGetMaxY(self.frame)-topBar.frame.size.height/2);
topBar.zPosition = theParticles.zPosition+1;
[self addChild:topBar];
bottomBar = [SKSpriteNode spriteNodeWithColor:[UIColor whiteColor] size:[[TextureList sharedManager]returnTextureSize:kMMBottomBar]];
bottomBar.position = CGPointMake(screenCenter.x, CGRectGetMinY(self.frame)+bottomBar.frame.size.height/2);
bottomBar.zPosition = theParticles.zPosition+1;
[self addChild:bottomBar];
settingsWin = [[ItemWindow alloc]initWithImageNamed:kMMCreditsBtn withLabel:@"SETTINGS" setLabelTop:NO];
settingsWin.theLabel.fontColor = [UIColor blackColor];
settingsWin.theLabel.fontSize = 15;
settingsWin.position = CGPointMake(CGRectGetMinX(self.frame)+settingsWin.frame.size.width/2+20, CGRectGetMinY(self.frame)+settingsWin.frame.size.height/2+25);
settingsWin.zPosition = bottomBar.zPosition+1;
[self addChild:settingsWin];
settingsButton = [[AGSpriteButton alloc]initWithTexture:nil color:nil size:CGSizeMake(settingsWin.size.width*2, settingsWin.size.height*2)];
[settingsButton setLabelWithText:@"" andFont:[UIFont fontWithName:kFontName size:kFontSizeButton] withColor:nil];
settingsButton.position = settingsWin.position;
settingsButton.zPosition = settingsWin.zPosition+1;
[settingsButton addTarget:self selector:@selector(buttonPressed:) withObject:[NSNumber numberWithInt:1] forControlEvent:AGButtonControlEventTouchUpInside];
[self addChild:settingsButton];
iapWin = [[ItemWindow alloc]initWithImageNamed:kMMIapBtn withLabel:@"SHOP" setLabelTop:NO];
iapWin.theLabel.fontColor = [UIColor blackColor];
iapWin.theLabel.fontSize = 15;
iapWin.position = CGPointMake(settingsWin.position.x+iapWin.frame.size.width+30, settingsWin.position.y);
iapWin.zPosition = bottomBar.zPosition+1;
[self addChild:iapWin];
iapButton = [[AGSpriteButton alloc]initWithTexture:nil color:nil size:CGSizeMake(iapWin.size.width*2, iapWin.size.height*2)];
[iapButton setLabelWithText:@"" andFont:[UIFont fontWithName:kFontName size:kFontSizeButton] withColor:nil];
iapButton.position = iapWin.position;
iapButton.zPosition = iapWin.zPosition+1;
[iapButton addTarget:self selector:@selector(buttonPressed:) withObject:[NSNumber numberWithInt:2] forControlEvent:AGButtonControlEventTouchUpInside];
[self addChild:iapButton];
unlocksWin = [[ItemWindow alloc]initWithImageNamed:kMMUnlockBtn withLabel:@"UNLOCKS" setLabelTop:NO];
unlocksWin.theLabel.fontColor = [UIColor blackColor];
unlocksWin.theLabel.fontSize = 15;
unlocksWin.position = CGPointMake(iapWin.position.x+unlocksWin.frame.size.width+30, iapWin.position.y);
unlocksWin.zPosition = bottomBar.zPosition+1;
[self addChild:unlocksWin];
unlocksButton = [[AGSpriteButton alloc]initWithTexture:nil color:nil size:CGSizeMake(unlocksWin.size.width*2, unlocksWin.size.height*2)];
[unlocksButton setLabelWithText:@"" andFont:[UIFont fontWithName:kFontName size:kFontSizeButton] withColor:nil];
unlocksButton.position = unlocksWin.position;
unlocksButton.zPosition = unlocksWin.zPosition+1;
[unlocksButton addTarget:self selector:@selector(buttonPressed:) withObject:[NSNumber numberWithInt:3] forControlEvent:AGButtonControlEventTouchUpInside];
[self addChild:unlocksButton];
// Labels
title = [[SKLabelNode alloc]initWithFontNamed:kFontName];
if ([[[UserDetails sharedManager]userDevice]isEqualToString:@"iphone4"]) {
title.fontSize = 60;
}
else{
title.fontSize = 75;
}
title.fontColor = [UIColor blackColor];
title.position = CGPointMake(topBar.frame.size.width/4, topBar.position.y-10);
title.zPosition = topBar.zPosition+1;
title.text = @"FLOWERS";
[self addChild:title];
subtitle = [[SKLabelNode alloc]initWithFontNamed:kFontName];
if ([[[UserDetails sharedManager]userDevice]isEqualToString:@"iphone4"]) {
subtitle.fontSize = 24;
}
else{
subtitle.fontSize = 30;
}
subtitle.fontColor = [UIColor grayColor];
subtitle.position = CGPointMake(title.position.x, title.position.y-title.frame.size.height/2-10);
subtitle.zPosition = topBar.zPosition+1;
subtitle.text = @"THE BEAUTIFUL MEADOW";
[self addChild:subtitle];
AGSpriteButton *testButton3 = [[AGSpriteButton alloc]initWithTexture:[SKTexture textureWithImageNamed:kMMIapBtn] color:[UIColor clearColor] size:[[TextureList sharedManager]returnTextureSize:kMMIapBtn]];
[testButton3 setLabelWithText:@"" andFont:[UIFont fontWithName:kFontName size:kFontSizeButton] withColor:nil];
testButton3.position = CGPointMake(bottomRight.x-testButton3.frame.size.width/1.5, bottomRight.y+settingsButton.frame.size.height/1.5);
testButton3.zPosition = interfaceLayer;
[testButton3 addTarget:self selector:@selector(buttonPressed:) withObject:[NSNumber numberWithInt:4] forControlEvent:AGButtonControlEventTouchUpInside];
[self addChild:testButton3];
AGSpriteButton *testButton4 = [[AGSpriteButton alloc]initWithTexture:[SKTexture textureWithImageNamed:kMMIapBtn] color:[UIColor clearColor] size:[[TextureList sharedManager]returnTextureSize:kMMIapBtn]];
[testButton4 setLabelWithText:@"" andFont:[UIFont fontWithName:kFontName size:kFontSizeButton] withColor:nil];
testButton4.position = CGPointMake(testButton3.position.x-testButton4.frame.size.width, bottomCenter.y+settingsButton.size.height/1.5);
testButton4.zPosition = interfaceLayer;
[testButton4 addTarget:self selector:@selector(buttonPressed:) withObject:[NSNumber numberWithInt:5] forControlEvent:AGButtonControlEventTouchUpInside];
[self addChild:testButton4];
if ([[[UserDetails sharedManager]userDevice] isEqualToString:@"ipad"]) {
title.fontSize = 105;
title.position = CGPointMake(topBar.frame.size.width/6+20, topBar.position.y+10);
subtitle.position = CGPointMake(title.position.x, title.position.y-title.frame.size.height/2-10);
subtitle.fontSize = 41;
settingsWin.theLabel.fontSize = 25;
iapWin.theLabel.fontSize = 25;
unlocksWin.theLabel.fontSize = 25;
settingsWin.position = CGPointMake(CGRectGetMinX(self.frame)+settingsWin.frame.size.width/2+20, CGRectGetMinY(self.frame)+settingsWin.frame.size.height+25);
iapWin.position = CGPointMake(settingsWin.position.x+iapWin.frame.size.width+30, settingsWin.position.y);
unlocksWin.position = CGPointMake(iapWin.position.x+unlocksWin.frame.size.width+30, settingsWin.position.y);
}
}
#pragma mark - Setup View
-(void)setupView{
// setup music players slightly quieter music now
/*appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
[self fadeVolumeIn:[appDelegate musicPlayer] toVolume:0.45];
[[appDelegate soundFxPlayer]setVolume:0.25];
[[appDelegate soundFxPlayer]play];
// no continue if the user has not progressed past level 1
if ([[UserDetails sharedManager]userCurrentLevel] <= 1) {
continueButton.userInteractionEnabled = NO;
continueButton.hidden = YES;
}
else{
continueButton.userInteractionEnabled = YES;
continueButton.hidden = NO;
}*/
}
#pragma mark - Interaction
-(void)buttonPressed:(NSNumber*)theTag{
SKScene *theScene;
SKTransition *theTransition;
switch (theTag.intValue) {
case 0: // start game
// stop music
//[[appDelegate musicPlayer]stop];
theScene = [[GameLevelScene alloc] initWithSize:self.view.bounds.size];
// transition type
theTransition = [SKTransition fadeWithDuration:1.0];
break;
case 1: // settings
theScene = [[SettingsScene alloc] initWithSize:self.view.bounds.size];
// transition type
theTransition = [SKTransition flipHorizontalWithDuration:1.0];
break;
case 2: // iap
theScene = [[IAPScene alloc] initWithSize:self.view.bounds.size];
// transition type
theTransition = [SKTransition flipHorizontalWithDuration:1.0];
break;
case 3: // unlocks screen
theScene = [[UnlocksScene alloc] initWithSize:self.view.bounds.size];
// transition type
theTransition = [SKTransition flipHorizontalWithDuration:1.0];
break;
case 4: // level complete
theScene = [[LevelCompleteScene alloc] initWithSize:self.view.bounds.size];
// transition type
theTransition = [SKTransition flipHorizontalWithDuration:1.0];
break;
case 5: // cheats
theScene = [[CheatsScene alloc] initWithSize:self.view.bounds.size];
// transition type
theTransition = [SKTransition flipHorizontalWithDuration:1.0];
break;
default:
break;
}
// play sound
[self menuButtonPressed];
[self.view presentScene:theScene transition:theTransition];
}
@end
Settings Screen:
#import "SettingsScene.h"
#import "SKScene+SceneUtils.h"
#import "AGSpriteButton.h"
#import "ItemBannerLabel.h"
#import "TextureList.h"
#import "UnlockController.h"
#import "UserDetails.h"
#import "TutorialFlowerTarget.h"
#import "CreditsScene.h"
@interface SettingsScene(){
AGSpriteButton *backButton;
AGSpriteButton *resetButton;
AGSpriteButton *resetTutorialsButton;
AGSpriteButton *creditsButton;
ItemBannerLabel *titleLabel;
SKLabelNode *copyrightLabel;
UIAlertView *resetGameAlert;
UIAlertView *resetTutAlert;
SKScene *theScene;
SKTransition *theTransition;
SKSpriteNode *menuBg;
}
@end
@implementation SettingsScene
#pragma mark - SCENE APPEARS
-(void)didMoveToView:(SKView *)view {
// setup UI
[self createUI];
}
#pragma mark - CREATE UI
-(void)createUI{
// background
self.scene.backgroundColor = [UIColor whiteColor];
menuBg = [[SKSpriteNode alloc]initWithTexture:[SKTexture textureWithImageNamed:kMDBg] color:nil size:[[TextureList sharedManager]returnTextureSize:@"kMDBg"]];
menuBg.position = screenCenter;
menuBg.zPosition = self.zPosition+1;
[self addChild:menuBg];
// labels
titleLabel = [[ItemBannerLabel alloc]initWithBgImageNamed:kMDTitle withLabel:@"GAME SETTINGS" withfont:kFontName withSize:kFontSizeMDTitle];
titleLabel.position = CGPointMake(topLeft.x+titleLabel.frame.size.width/2+10,topLeft.y-titleLabel.frame.size.height/2-10);
titleLabel.zPosition = interfaceLayer;
[self addChild:titleLabel];
copyrightLabel = [SKLabelNode labelNodeWithFontNamed:kFontName];
copyrightLabel.text = [NSString stringWithFormat:@"COPYRIGHT © 2015 RICHARD ACHERKI"];
copyrightLabel.fontSize = kFontSizeMDSmall;
copyrightLabel.fontColor = [UIColor blackColor];
copyrightLabel.verticalAlignmentMode = SKLabelVerticalAlignmentModeCenter;
copyrightLabel.horizontalAlignmentMode = SKLabelHorizontalAlignmentModeCenter;
copyrightLabel.position = CGPointMake(bottomCenter.x, bottomCenter.y+copyrightLabel.frame.size.height);
copyrightLabel.zPosition = interfaceLayer;
[self addChild:copyrightLabel];
// buttons
if ([[[UserDetails sharedManager]userDevice]isEqualToString:@"ipad"]) {
resetTutorialsButton = [[AGSpriteButton alloc]initWithTexture:[SKTexture textureWithImageNamed:kMDButton] color:nil size:CGSizeMake([[TextureList sharedManager]returnTextureSize:kMDButton].width*4, [[TextureList sharedManager]returnTextureSize:kMDButton].height*2)];
[resetTutorialsButton setLabelWithText:@"RESET TUTORIALS" andFont:[UIFont fontWithName:kFontName size:kFontSizeButton] withColor:[UIColor whiteColor]];
resetTutorialsButton.position = CGPointMake(screenCenter.x, titleLabel.position.y-titleLabel.frame.size.height/2-resetTutorialsButton.frame.size.height/2-30);
resetTutorialsButton.zPosition = menuBg.zPosition+1;
[resetTutorialsButton addTarget:self selector:@selector(buttonPressed:) withObject:[NSNumber numberWithInt:0] forControlEvent:AGButtonControlEventTouchUpInside];
}
else{
resetTutorialsButton = [[AGSpriteButton alloc]initWithTexture:[SKTexture textureWithImageNamed:kMDButton] color:nil size:CGSizeMake([[TextureList sharedManager]returnTextureSize:kMDButton].width*2, [[TextureList sharedManager]returnTextureSize:kMDButton].height)];
[resetTutorialsButton setLabelWithText:@"RESET TUTORIALS" andFont:[UIFont fontWithName:kFontName size:kFontSizeButton] withColor:[UIColor whiteColor]];
resetTutorialsButton.position = CGPointMake(screenCenter.x, titleLabel.position.y-titleLabel.frame.size.height/2-resetTutorialsButton.frame.size.height/2-30);
resetTutorialsButton.zPosition = menuBg.zPosition+1;
[resetTutorialsButton addTarget:self selector:@selector(buttonPressed:) withObject:[NSNumber numberWithInt:0] forControlEvent:AGButtonControlEventTouchUpInside];
}
[self addChild:resetTutorialsButton];
if ([[[UserDetails sharedManager]userDevice]isEqualToString:@"ipad"]) {
resetButton = [[AGSpriteButton alloc]initWithTexture:[SKTexture textureWithImageNamed:kMDButton] color:nil size:CGSizeMake([[TextureList sharedManager]returnTextureSize:kMDButton].width*4, [[TextureList sharedManager]returnTextureSize:kMDButton].height*2)];
[resetButton setLabelWithText:@"RESET GAME" andFont:[UIFont fontWithName:kFontName size:kFontSizeButton] withColor:[UIColor whiteColor]];
resetButton.position = CGPointMake(resetTutorialsButton.position.x,resetTutorialsButton.position.y-resetTutorialsButton.frame.size.height-20);
resetButton.zPosition = menuBg.zPosition+1;
[resetButton addTarget:self selector:@selector(buttonPressed:) withObject:[NSNumber numberWithInt:1] forControlEvent:AGButtonControlEventTouchUpInside];
}
else{
resetButton = [[AGSpriteButton alloc]initWithTexture:[SKTexture textureWithImageNamed:kMDButton] color:nil size:CGSizeMake([[TextureList sharedManager]returnTextureSize:kMDButton].width*2, [[TextureList sharedManager]returnTextureSize:kMDButton].height)];
[resetButton setLabelWithText:@"RESET GAME" andFont:[UIFont fontWithName:kFontName size:kFontSizeButton] withColor:[UIColor whiteColor]];
resetButton.position = CGPointMake(resetTutorialsButton.position.x,resetTutorialsButton.position.y-resetTutorialsButton.frame.size.height-20);
resetButton.zPosition = menuBg.zPosition+1;
[resetButton addTarget:self selector:@selector(buttonPressed:) withObject:[NSNumber numberWithInt:1] forControlEvent:AGButtonControlEventTouchUpInside];
}
[self addChild:resetButton];
if ([[[UserDetails sharedManager]userDevice]isEqualToString:@"ipad"]) {
creditsButton = [[AGSpriteButton alloc]initWithTexture:[SKTexture textureWithImageNamed:kMDButton] color:nil size:CGSizeMake([[TextureList sharedManager]returnTextureSize:kMDButton].width*4, [[TextureList sharedManager]returnTextureSize:kMDButton].height*2)];
[creditsButton setLabelWithText:@"CREDITS" andFont:[UIFont fontWithName:kFontName size:kFontSizeButton] withColor:[UIColor whiteColor]];
creditsButton.position = CGPointMake(resetButton.position.x,resetButton.position.y-resetButton.frame.size.height-20);
creditsButton.zPosition = menuBg.zPosition+1;
[creditsButton addTarget:self selector:@selector(buttonPressed:) withObject:[NSNumber numberWithInt:2] forControlEvent:AGButtonControlEventTouchUpInside];
}
else{
creditsButton = [[AGSpriteButton alloc]initWithTexture:[SKTexture textureWithImageNamed:kMDButton] color:nil size:CGSizeMake([[TextureList sharedManager]returnTextureSize:kMDButton].width*2, [[TextureList sharedManager]returnTextureSize:kMDButton].height)];
[creditsButton setLabelWithText:@"CREDITS" andFont:[UIFont fontWithName:kFontName size:kFontSizeButton] withColor:[UIColor whiteColor]];
creditsButton.position = CGPointMake(resetButton.position.x,resetButton.position.y-resetButton.frame.size.height-20);
creditsButton.zPosition = menuBg.zPosition+1;
[creditsButton addTarget:self selector:@selector(buttonPressed:) withObject:[NSNumber numberWithInt:2] forControlEvent:AGButtonControlEventTouchUpInside];
}
[self addChild:creditsButton];
backButton = [[AGSpriteButton alloc]initWithTexture:[SKTexture textureWithImageNamed:kMDButton] color:nil size:[[TextureList sharedManager]returnTextureSize:kMDButton]];
[backButton setLabelWithText:@"BACK" andFont:[UIFont fontWithName:kFontName size:kFontSizeButton] withColor:[UIColor whiteColor]];
backButton.position = CGPointMake(bottomRight.x-backButton.frame.size.width/2-10, bottomRight.y+backButton.frame.size.height/2+10);
backButton.zPosition = menuBg.zPosition+1;
[backButton addTarget:self selector:@selector(buttonPressed:) withObject:[NSNumber numberWithInt:3] forControlEvent:AGButtonControlEventTouchUpInside];
[self addChild:backButton];
}
#pragma mark - BUTTON PRESSED
-(void)buttonPressed:(NSNumber*)theTag{
if (theTag.intValue == 0) { // reset tutorials
resetTutAlert = [[UIAlertView alloc]initWithTitle:@"RESET TUTORIALS" message:@"Are you sure you want to reset tutorials?\nThis will cause all tutorials to show again when playing the game." delegate:self cancelButtonTitle:@"No" otherButtonTitles:@"Yes", nil];
[resetTutAlert show];
}
else if (theTag.intValue == 1) { // reset game
resetGameAlert = [[UIAlertView alloc]initWithTitle:@"RESET THE GAME" message:@"Are you sure you want to wipe your game progression?\nThis will remove all unlocks, scores and level progression." delegate:self cancelButtonTitle:@"No" otherButtonTitles:@"Yes", nil];
[resetGameAlert show];
}
else if (theTag.intValue == 2) { // credits menu
// play sound
[self menuButtonPressed];
theScene = [[CreditsScene alloc] initWithSize:self.view.bounds.size];
theTransition = [SKTransition flipHorizontalWithDuration:1.0];
[self.view presentScene:theScene transition:theTransition];
}
else if (theTag.intValue == 3) { // main menu
// play sound
[self menuButtonPressed];
// scene to move to
theScene = [[MainMenuScene alloc] initWithSize:self.view.bounds.size];
// transition type
theTransition = [SKTransition flipHorizontalWithDuration:1.0];
[self.view presentScene:theScene transition:theTransition];
}
}
#pragma mark - RESET TUTORIALS
-(void)resetTutorials{
for (id theObject in [[UserDetails sharedManager]userTutorials]) {
TutorialFlowerTarget *theTut= [[[UserDetails sharedManager]userTutorials]objectForKey:theObject];
[theTut setTriggered:NO];
}
[[UserDetails sharedManager]saveData];
}
#pragma mark - RESET UNLOCKS
-(void)resetUnlocks{
[[UnlockController sharedManager]resetGame];
}
回答1:
I could be wrong but I suspect your button class is your offender. When you call...
[testButton4 addTarget:self selector:@selector(buttonPressed:) withObject:[NSNumber numberWithInt:5] forControlEvent:AGButtonControlEventTouchUpInside];
You pass self
being that scene. In the button class the method..
-(void)addTarget:(id)target selector:(SEL)selector withObject:(id)object forControlEvent:(AGButtonControlEvent)controlEvent
{
//check whether selector is already saved, otherwise it will get called twice
if (marrSelectors == nil)
{
marrSelectors = [NSMutableArray new];
}
NSMutableDictionary *mdicSelector = [[NSMutableDictionary alloc]init];
[mdicSelector setObject:target forKey:@"target"];
[mdicSelector setObject:[NSValue valueWithPointer:selector] forKey:@"selector"];
if (object)
{
[mdicSelector setObject:object forKey:@"object"];
}
[mdicSelector setObject:[NSNumber numberWithInt:controlEvent] forKey:@"controlEvent"];
[marrSelectors addObject:mdicSelector];
}
Note this..
[mdicSelector setObject:target forKey:@"target"];
target is your scene and it is being tossed into a dictionary in that is tossed into an array. So in theory that button now has a strong reference to your scene and your scene has a reference to that button.
To test this theory set all of your buttons to nil before calling
[self.view presentScene:theScene transition:theTransition];
And if I am correct that should break the strong reference to each other. Hopefully that helps and is the issue.
回答2:
In a game I'm working on I have a method for going on to the next scene. It looks like this:
func proceedToNextLevel() {
// Go to next level
self.physicsWorld.removeAllJoints()
self.enumerateChildNodesWithName("cube", usingBlock: {
(node: SKNode!, stop: UnsafeMutablePointer <ObjCBool>) -> Void in
// do something with node or stop
node.removeFromParent()
})
player.removeFromParent()
hud.removeFromParent()
}
Each level is a scene that inherits this method. (I have a GameScene.swift, and every level is a subclass of it)
This method in each level looks like this:
override func proceedToNextLevel() {
super.proceedToNextLevel()
let transition = SKTransition.revealWithDirection(SKTransitionDirection.Right, duration: 3)
let newScene: LevelFourScene = LevelFourScene.unarchiveFromFile("LevelFourScene") as! LevelFourScene
newScene.scaleMode = SKSceneScaleMode.AspectFit
self.view?.presentScene(newScene)
}
Obviously this is swift and your game is in Objective C but hopefully you get the idea.
回答3:
Based on your posted code, I suggest you add this to your MainMenu:
-(void) willMoveFromView:(SKView *)view {
[self removeAllChildren];
backgroundImage = nil;
topBar = nil;
bottomBar = nil;
ladybirds = nil;
title = nil;
subtitle = nil;
coffee = nil;
settingsWin = nil;
iapWin = nil;
unlocksWin = nil;
startButton = nil;
continueButton = nil;
settingsButton = nil;
iapButton = nil;
unlocksButton = nil;
theParticles = nil;
}
Add this to your SettingsScene:
-(void) willMoveFromView:(SKView *)view {
[self removeAllChildren];
backButton = nil;
resetButton = nil;
resetTutorialsButton = nil;
creditsButton = nil;
titleLabel = nil;
copyrightLabel = nil;
resetGameAlert = nil;
resetTutAlert = nil;
theScene = nil;
theTransition = nil;
menuBg = nil;
}
Keep in mind that SK uses its own caching which you have no control over. This means you will see an increase in memory the first couple of times you switch scenes but it will level out at some point. I suggest you move back and forth 15 to 20 times and see what happens.
来源:https://stackoverflow.com/questions/30218195/skscene-fails-to-deallocate-memory-resulting-in-bounded-memory-growth