How to push and pop scenes properly in Cocos2D v3.x - cocos2d-iphone

I push a preloaded scene B onto scene A like this. The root node in the scene B has an animation that runs for ~2 seconds, and I want scene B to be popped when the animation is done. I think it should work like below. However it crashes on popScene. Does push/pop really work in Cocos2D v3?
SceneRedroom* sceneredroom = (SceneRedroom*)[self.ccscenewithSceneredroom getChildByName:#"SceneRedroom" recursively:NO];
[sceneredroom.animationManager setCompletedAnimationCallbackBlock:^(id sender) {
[[CCDirector sharedDirector] popScene];
}];
[[CCDirector sharedDirector] pushScene:self.ccscenewithSceneredroom];
The crashes I get are fairly random. It seems like some things are incorrectly deallocated or similar when pushing and/or popping scenes.

After further research, I managed to find a solution to the problem I was having through this post. I removed the CCDirector pause and resume in my pauseGame and resumeGame methods then added this:
//pause
[sprite.actionManager pauseTarget:sprite];
//resume
[sprite.actionManager resumeTarget:sprite];
This stopped the animation and kept the "paused" state even if the game is closed then reopened and I didn't even need to play with the AppDelegate class :). I hope this helps others too.
UPDATE: Just in case anybody else is creating a sprite using a loop, here's how I managed to create the pause and resume function for it:
[sprite.actionManager pauseAllRunningActions];
[sprite.actionManager resumeTargets:[NSSet setWithArray:spriteArray]];
note the difference between the two (resumeTarget and resumeTargets) then since resumeTargets would ask for NSSet, I simply passed the array objects into a NSSet with the above code.

void PauseScene::goToMainMenuScene(cocos2d::Ref *sender)
{
Director::getInstance()->resume();
auto scene = MainMenuScene::createScene();
Director::getInstance()->replaceScene(TransitionFade::create(TRANSITION_TIME, scene));
}
void PauseScene::resumeScene(cocos2d::Ref *sender)
{
Director::getInstance()->popScene();
}
void PauseScene::restartScene(cocos2d::Ref *sender)
{
Director::getInstance()->resume();
auto scene = GameScene::createScene();
Director::getInstance()->replaceScene(TransitionFade::create(TRANSITION_TIME, scene));
}

Related

cocos2d - Sprite doesn't show properly

I am using cocos2dx v3.11.1 with c++ to create simple game for iOS platform. But I run into strange issue with sprite movement.
Definition of main objects looks like that:
Sprite *logoBackSprite;
SpriteFrameCache *cache;
SpriteBatchNode *batchNode;
I create sprite from the plist like that:
cache = SpriteFrameCache::getInstance();
cache->addSpriteFramesWithFile("game_sprites1.plist");
batchNode = SpriteBatchNode::create("game_sprites1.png");
addChild(batchNode);
logoBackSprite = Sprite::createWithSpriteFrameName(fileName);
logoBackSprite->setPosition(Vec2(centerPoint.x-4, centerPoint.y + 200-43));
addChild(logoBackSprite, 0);
After that I call function which must perform simple moving animation for sprite. Code of this function looks like that:
void MainMenuScene::playMenuAnimations() {
float startDelay = 0.0f;
auto windowSize = Director::getInstance()->getVisibleSize();
Point centerPoint = Vec2(windowSize.width/2, windowSize.height/2);
logoBackSprite->stopAllActions();
logoBackSprite->setOpacity(0);
logoBackSprite->runAction(Sequence::create(DelayTime::create(startDelay + 0.5 + 0.75),
FadeTo::create(0.5f, 255),
nullptr));
}
But when I run application - nothing happens. Could you point me what I am making wrong? Thank you.
EDIT After few hours of experiments, I have noticed, that runAction method of sprite objects doesn't work. For example, I have created vector of sprite frames and I want to run animation. When I run application I can see this sprite, but animation still does not work. Maybe, I missed smth important?
EDIT2
Today I have noticed that any action works prefect on previous scene.
Issue solved. Problem was in bad configuration of scene where I want to run animations.
I should override onEnter() and onExit() methods. In onEnter() method of scene I call
Layer::onEnter();
Also in scene class I create init() method like that:
bool MainMenuScene::init() {
if ( !Layer::init() )
{
return false;
}
return true;
}
And animation runs perfectly!

cocos2d v3 chipmunk collision method not firing

ok so i've been messing around with chipmunk a bit, and i can get two sprites to bounce off of each other, but when i try to use the following method, it never fires,
-(BOOL)ccPhysicsCollisionBegin:(CCPhysicsCollisionPair *)pair tower:(CCNode *)nodeA BG:
(CCNode *)nodeB
{
NSLog(#"HELLO");
return YES;
}
Heres where I create the physics node:
_physics = [CCPhysicsNode node];
_physics.debugDraw = YES;
[self addChild:_physics z:1];
_physics.collisionDelegate = self;
I use this code to create the first sprite:
background = [CCSprite spriteWithImageNamed:gameLevelImage];
[background setPosition:ccp(winSize.width/2,winSize.height/2)];
background.physicsBody.collisionType = #"BG";
background.physicsBody = [CCPhysicsBody bodyWithCircleOfRadius:50 andCenter:self.position];
and this for the other :
tower = [[TowerType alloc] initWithTheGame:self location:ccp(winSize.width/2, winSize.height/2)];
[towers addObject:tower];
[self MenuItemsVisible];
tower.physicsBody = [CCPhysicsBody bodyWithCircleOfRadius:50 andCenter:tower.position];
tower.physicsBody.collisionType = #"tower";
I also have the protocol in the h file.
if anyone knows whats happening help would be greatly appreciated. (:
First of all, are both bodies under the same CCPhysicsNode?
Second, ccPhysicsCollisionBegin is just called when the collision BEGIN, so as both of your bodies are one over the other and they aparenttly will move together due to gravity the collision will never begin, because they started colliding. The cycle for collision evaluation is:
ccPhysicsCollisionBegin: called once both bodies start colliding
ccPhysicsCollisionPreSolve: called every frame update, before physics calculations
ccPhysicsCollisionPostSolve : called every frame, after physics calculations
ccPhysicsCollisionSeparates: called once they separate
Make sure your sprites are allocated properly before you try to set the collisionType. That was the issue for me in my similar case.

How do I create a more efficient portrait gallery using Cocos2d?

I'm building an app that has gallery of portraits (like a museum) and my character(s) walk past them from left-to-right-to-left. My portrait (images) are all 2048x2048. I haven't reduced their size yet because I want to make sure they can be used for the iPad version. I know their large size is an issue because it crashes when I try to load all of them at once (and it takes a long time to launch even with only 10 images).
That being said, my real issue is trying to create an efficient method for adding/removing them (sprites) as needed. I came up with something that works but it is clearly not the best way to do this.
I am hoping someone can suggest a more efficient approach.
Here is my code. You can assume another method takes care of loading the images into a mutable array called framedSprites (except I can only load 10 at a time because of the size/crashing). The following method (checkPosition) is called every time the screen position changes (via a TouchMoved swipe). As I see it, I will have to create similar statements for each image/portrait in the array (very inefficient and time consuming)...
-(void)checkPosition {
CGSize winSize = [CCDirector sharedDirector].winSize;
for (CCSprite *sprite in framedSprites) {
if (sprite.tag == 2) {
if ((sprite.position.x > 2000.0f)&&(sprite.position.x < 2010.0f)) {
CCSprite *portrait = (CCSprite *)[_backgroundNode getChildByTag:0];
if (portrait.tag == 0) {
NSLog(#"Removing a Portrait Left 2 Places From This One");
[_backgroundNode removeChildByTag:0 cleanup:YES];
}
}
if ((sprite.position.x > 1980.0f)&&(sprite.position.x < 1990.0f)) {
CCSprite *portrait = (CCSprite *)[_backgroundNode getChildByTag:0];
if (portrait == nil) {
CCSprite * framedSprite = (CCSprite *)[framedSprites objectAtIndex:0];
NSLog(#"Adding a Portrait Left, 2 Places From This One");
framedSprite.position = ccp(600,winSize.height/2); //figuring these positions is also not efficient and time consuming
[_backgroundNode addChild:framedSprite z:0 parallaxRatio:ccp(0.4f,0.5f) positionOffset:framedSprite.position];
}
}
}
}
}
You should only need to have 3 images loaded at any one time to allow scrolling in either direction (assuming you're not also allowing movement in the y direction). The one on display, one either side as a buffer and then lazy load and replace as needed.
If you don't need to see the entire image at once you could also consider cutting it into tiles using a free tool like Tilen (http://itunes.apple.com/gb/app/tilen/id409199185?mt=12) and then loading the tiles as required.

Can't get sprite position

I have somewhere in my code something that I have done so many times, but now I can't!
for (b2Body* bo = world->GetBodyList(); bo; bo = bo->GetNext())
{
CCSprite *tempSprite = (CCSprite *) bo->GetUserData();
NSLog(#"%f",tempSprite.position.x); //crashes in this line.
I am counting the bodies on my world and I can see i have 22 of them, but every time i try to do somthing with: tempSprite.position.x it crashes!
I can also print this:
if(tempSprite != NULL)
NSLog(#"YES");
Why can't I get the position?
My world is working great; the contact listener is doing just fine; can't understand that.
any help ?
solved but not clearly why
i did
[badBondSheet1 removeChild:actora cleanup:YES];
[self removeChild:actorb cleanup:YES];
[self shiftEnemies:touchPointA]; // calls the code that i have posted
when shiftEnemies is the function that i have posted-that runs on all the bodies.
i have corrected to:
[self shiftEnemies:touchPointA];
[badBondSheet1 removeChild:actora cleanup:YES];
[self removeChild:actorb cleanup:YES];
and it works.
that was because i was running over my bodies, which some of them didnt have a userData, because i already cleaned up the sprite !
so you have to destroy body and clean the sprite and then run over your bodies.
conclusion: DO NOT CLEAN YOUR SPRITE, AND DO SOMETHING ELSE BEFOR YOU DESTROY YOUR BODY !
sounds reasonable ?

cocos2d scene retaining issue

There is a scene in my application which has only two labels and a menu item. When I load this scene using replaceScene method it stays for 3-4 seconds and then gets disappeared or released. I want to keep it until cancel button is pressed. How can I do it? code is:
#implementation MyLayer
+ (id)myScene {
CCScene *aScene = [CCScene node];
MYLayer *myLayer = [MyLayer node];
[aScene addChild:myLayer];
return aScene;
}
- (id) init {
if (self = [super init]) {
//labels and menu here
}
return self;
}
And I am calling it from another scene like this:
[[CCDirector sharedDirector] replaceScene: [MyLayer myScene]];
Maybe the problem is that it's your first scene. Then you should use runWithScene method of CCDirector.
did you try replacing that scene with a "empty" init function to see if it still releases itself? It might be because of the amount of textures you are putting into memory
I did have sort of similar problems before because the images used in the new scene is too big and got auto purged by my app delegate, thus returning me an empty scene sometimes