CCSpriteBatchNode not being retained? - ios

I have an app that uses sprite sheets and is a Cocos2D/UIKit app. In the init method of my scene I do this:
spriteSheet = [CCSpriteBatchNode batchNodeWithFile:#"TheSpriteSheet.pvr.ccz"];
[self addChild:spriteSheet z:1];
Now when the game is over, I do this:
[[[CCDirector sharedDirector] actionManager] removeAllActions];
[self unscheduleAllSelectors];
This causes the CCSprites that are currently still as a child to remain there so once I finish my UIKit view transition to my other UIViewController I try to call a method back in my CCLayer class (the class the scene is in) to remove all the children that were in my CCSpriteBatchNode, the app crashes with EXC_BAD_ACCESS.
Now I HAVE to call the method at this point because I want to achieve the effect of the enemies still being on screen while I am doing my custom view transition so they don't magically disappear before I finish switching views. Also I do not do replaceScene anywhere or release my batch node explicitly so I don't know why this is happening.
Anyway how would I fix this issue?
Thanks!

Related

Presenting previous scene makes it partillay unresponsive

A SpriteKit game presents MainMenuScene then LevelSelectionScene and finally the GamePlayScene. Once the game is over, in GamePlayScene, the user is transferred back to MainMenuScene like so:
MainMenuScene *newScene = [MainMenuScene sceneWithSize:self.view.bounds.size];
[self.view presentScene:newScene transition:[SKTransition fadeWithDuration:0.5]];
It takes me to the scene but the buttons, that worked previously, don't work anymore. I press them, they seem to do their little animation as if they're being pressed but they don't present me appropriate scenes they're supposed to.
I have a very specific bundle of code activated every time a scene is about to be left and I don't actually know if it influences this whole conundrum:
-(void)willMoveFromView:(SKView *)view
{
/* Remove anything stuck in memory. */
[self removeAllActions];
[self removeAllChildren];
[self removeFromParent];
[self.scene removeAllActions];
[self.scene removeAllChildren];
[self.scene removeFromParent];
//[self.scene.view removeFromSuperview]; <--TOTALLY DESTROYS ALLS SCENES IN THE GAME. Don't use it.
}
Has any had previously working scenes presented as partially working duds?
From what you said looks like the button is triggering the animation but not the action, still not much information to be sure how to exactly fix it, probably the creation of the actions of the button is working. Double check if the part of the code that creates the SKActions is actually running and active.
So I poked around and found out the culprit is in the class I used to create buttons. It's called AGSpriteButton and I highly recommend it (You can find it on github). It has built-in SELECTORS, ACTIONS and BLOCKS functionality offered by default that is very easy to tap into. I'm not sure as to why, but SELECTORS stopped functioning correctly. I just switched to ACTIONS calling my methods & everything works perfectly.

How to 'resume' game on SKScene1 after transitioning to SKScene2?

Perhaps I'm not using the correct keywords to search but I haven't had any luck in finding out how to do this. I am developing a game for the AppStore using Xcode's sprite kit. I have the main game play on SKScenePlay.m and when we click a pause button (an SKSpriteNode) on SKScenePlay, I transition to SKScenePause with the following code:
SKScene *PauseScene = [[SKScenePause alloc] initWithSize:self.size];
[self.view presentScene:PauseScene];
I have a resume button on the SKScenePause that does the following to transition back to SKScenePlay:
SKScene *PlayScene = [[SKScenePlay alloc] initWithSize:self.size];
SKTransition *reveal = [SKTransition flipHorizontalWithDuration:0.5];
[self.view presentScene: PlayScene transition:reveal];
but when I go back to SKScenePlay, the game is reset (score, player position, et cetera). How would I, after pausing the game to go from SKScenePlay to SKScenePause, transition from SKScenePause to back to SKScenePlay while saving the state of everything in SKScenePlay?
P.S: To actually pause the game, all of the SKSpriteNode's (which are the objects in my game that move and fall around) are children of an SKNode *background, and I set background.paused=true and this pauses all the SKActions in SKScenePlay.
Using your current code, you can't. At least not in any short and simple way. Your code trashes the PlayScene and transitions to PauseScene.
Your choices are to:
1) Include pause code in your PlayScene to handle whatever it is you need done without transitioning to a new scene.
2) Save all your relevant data in your PlayScene before transitioning to PauseScene and loading the saved data when transitioning back to PlayScene.
There's really no reason to have a new scene for a pause menu, so I would recommend you work to incorporate your pause code into your PlayScene.
1)You need to add children view controller in the container view controller in a stack. So You just put the view of new view controller above first one.
2)when you press "play" or "resume" button you just remove top view controller from the stack and game resumes.
I have made absolutely the same but on swift.
hope it helps.

Cocos2d v3 - Detecting touch without adding the new node as a child

I'm trying to convert my game from cocos2d v2.x to v3, and I'm having a hard time figuring out how the new touch mechanism works.
In my project, I have an NSObject (a non cocos2d object). Previously, when I wanted this object to respond to touch events using the cocos2d touch mechanism, I marked it as a CCTargetedTouchDelegate:
#interface ControlCenter : NSObject <CCTargetedTouchDelegate>
I then added the object to the touch dispatcher:
[[[CCDirector sharedDirector] touchDispatcher] addTargetedDelegate:self priority:0 swallowsTouches:NO];
and finally used the ccTouch methods to handle the touches.
Now, I understand that in Cocos2d v3 touch handling is different. So let's say I have my current scene (using CCNode), and after adding
self.userInteractionEnabled = true;
winSize = [[CCDirector sharedDirector] viewSize];
self.contentSize = winSize;
and overriding the touch methods, I am able to handle touches from this scene. I can't get my ControlCenter object to respond to touches though. I changed it to a CCNode, enabled the user interaction flag and set the content size, but without actually adding the object as a child of my current scene, it won't respond to touches.
So, my question is this: Is there a way to make a CCNode respond to touch events without actually adding it as a child of the current scene? Is there a way to directly add it as a responder, like in cocos2d v2?

Is it possible to end an SKAction mid-action?

I have a subclass of SKSpriteNode (monsterNode). It automatically runs around the screen using vectors to follow the player. I am currently using the following action to make it run around:
SKAction *actionMove = [SKAction moveTo:actualDistance duration:time];
[self runAction:actionMove completion:^ {
_currentState = SVGMonsterStateIdle;
}];
I am wondering if its possible to make it so the monsterNode actually STOPS running the action if it hits the boundary of the iOS device screen. I currently have SKSpriteNode boundaries on the edges of the screen, linked with a contact delegate to notify if the monster and walls make contact. However, that means nothing if I can't actually stop the monster's actionMove action from going to completion. The monster needs to stop at the boundaries of the screen. If it is not possible to stop an SKAction mid-execution, is there a roundabout way to do so?
Look at the SKNode.h header file - it has two functions listed:
- (void)removeActionForKey:(NSString *)key;
- (void)removeAllActions;
The latter will work: [monsterNode removeAllActions];

Cocos2d scaling sprite causes artifact

I am on the master branch so that it will work with ARC.
I have implemented a method whereby the sprite will scale by a factor of 1.1 when a user touches the sprite. Multiple touches will queue up multiple scaling actions, built on top of each other. Every now and then I get a strange artifact where the smaller version of the sprite shows up on top of the scaled version.
Here's a screenshot:
More background: I'm using a texture atlas so I use:
sprite = [super spriteWithSpriteFrameName:anObject.filename];
to initialize the sprite. Is this a bug in openGL/cocos2d? Any advice on how to stop this artifact?
EDIT:
I am subclassing CCSprite but as far as I can tell there is only one instance of the sprite (the call to super was in a class method). Basically the user will define a list of actions that the sprite will do. The action list can also be interrupted using:
[self stopAllActions]
I've had actions using subclasses of CCMoveBy and CCRotateBy with no issues. It's only the most recent subclass of CCScaleBy that is causing this artifact. In the subclasses of these actions I'm not changing anything in the actions, just tracking certain variables so that I can properly resume the action after the interrupt.
Are you perhaps subclassing CCSprite, and in your subclass did you add a CCSprite instance variable as well?
In that case you'll be showing two sprites. The super class sprite and the instance variable sprite. If the other sprite shows up only sometimes this may depend on the order of adding sprites as childs, or the zOrder property.

Resources