crash when back to game scene? - cocos2d-iphone

when the game scene is done, and i replace to menuScene , everything is ok, but when i replace it back to the gameScene , i allways get the same crash, and just cant figure out what could be the cause to this:
the crash is in the CCscheduler.m class in the next method :
-(void) update: (ccTime) dt
{
if( elapsed == - 1)
elapsed = 0;
else
elapsed += dt;
if( elapsed >= interval ) {
impMethod(target, selector, elapsed); **//this line gets exc_BAD ! !**
elapsed = 0;
}
}
#end
any direction? is it memory? or timers? what should i check for ?
thanks.

Well, it seems to me that you haven't unscheduled all selectors and the function is called on a deallocated object. Try calling [self unscheduleAllSelectors] on your scenes before replacing them.

Related

How to animate through an a container for windows.draw()?

I have a container of objects:
std::vector<sf::Drawable> gameObjects;
My goal is to iterate through these objects and draw them:
for (auto it : gameObjects)
{
window.draw(*it);
}
You can assume these methods are already implemented. What I mean by 'animate': I want these objects drawn one at a time, rather than all at once immediately.
void Run::render()
{
window.clear(colorWindow);
for (auto it : gameObjects)
{
window.draw(*it);
}
window.display();
}
That is, have every render() draw an additional object in the container. Do you know how I can go about doing this? Thank you in advance.
edit: I've tried something unconventional - I dont think it's good practice, but it works:
int count = 0;
int countReset = 1;
...
while (countReset > count)
{
objects.at(count++).draw(window);
}
countReset++;
count = 0;
You should never make decisions about your game in your rendering. You should have an update method somewhere, that makes decisions on how input and time passed affect your game world. Rendering should only do one thing: rendering. No decision making, no data manipulation.
You could for example use a compound class to indicate which object should be drawn or you could derive your own base class from sf::Drawable and implement a bool IsVisible() const; method. Either way, the decision if it's drawn is made elsewhere, the rendering is only executing commands what to render specifically:
struct MaybeDrawn
{
bool IsVisible;
sf::Drawable Object;
};
...
std::vector<MaybeDrawn> gameObjects;
...
void Run::render()
{
window.clear(colorWindow);
for (auto it : gameObjects)
{
if(it->IsVisible)
{
window.draw(it->Object);
}
}
window.display();
}
Your decision, how and when to set the bool to true should happen in your Update/ChangeWorld method. Maybe you want to have a look here for a general description on how to structure a game and how to build a timer.
Alternatively, you could leave your program as it is and insert and/or delete from your vector in your decision making method.
Use a static counter for your index in list of objects. Measure time and incremente the counter if a time period has elapsed. So next time is drawn next object in list.
#include <chrono>
void Run::render()
{
// actual time
std::chrono::high_resolution_clock::time_point actTime = std::chrono::high_resolution_clock::now();
// remember time
static bool init = false;
std::chrono::high_resolution_clock::time_point lastTime;
if ( !init )
{
lastTime = actTime;
init = true;
}
// delta time
long microseconds = std::chrono::duration_cast<std::chrono::duration<long, std::micro> >( actTime - lastTime ).count();
double deltaTms = ((double)microseconds) / 1000.0;
window.clear(colorWindow);
static size_t actObjInx = 0;
window.draw(gameObjects[actObjInx]);
// increment object index if time period has elapsed
if ( deltaTms > 100.0 ) // 0.1 seconds
{
lastTime = actTime;
actObjInx ++;
if ( actObjInx == gameObjects.size() )
actObjInx = 0;
}
window.display();
}

How to refresh sprites (remove and recreate it again)

I am trying to make a day-night background mode in my game and I want to create a control button in a option dialog that when I click on it, all background are change without exiting the dialog. I have just made it run OK by re-open the scene but it also quit the option dialog.
I have an initBackground() method like this
void MenuScene::initMenuBackground() {
setBackgroundMode();
CCSize winSize = CCDirector::sharedDirector()->getWinSize();
//calculate system hour time
time_t now = time(0); // get time now
tm * ltm = localtime(&now);
double hour = ltm->tm_hour;
int curHourTime = (int) hour;
CCLOG("MenuScene hour is: %dh", curHourTime);
CCAnimation* caveAnim1 = CCAnimation::createWithSpriteFrames (senspark::Utils::createFramesArray("cave-%d.png", 3), 0.2f);
CCAnimation* caveAnim2 = CCAnimation::createWithSpriteFrames(senspark::Utils::createFramesArray("cave-%d.png", 3, 0, true), 0.2f);
cloudSpr->runAction(CCRepeatForever::create(CCSequence::create(CCMoveTo::create(30, ccp(winSize.width+100, cloudSpr->getPositionY())),
CCMoveTo::create(0, ccp(-100, cloudSpr->getPositionY())),
NULL)));
cloudNightSpr->runAction(CCRepeatForever::create(CCSequence::create(CCMoveTo::create(30, ccp(winSize.width+100, cloudSpr->getPositionY())),
CCMoveTo::create(0, ccp(-100, cloudSpr->getPositionY())),
NULL)));
//night
if ( ((curHourTime < 6 || curHourTime > 18) && (_isAuto==true)) || _isNight==true) {
caveNightSpr->runAction(CCRepeatForever::create(CCSequence::create(CCAnimate::create(caveAnim1),
CCAnimate::create(caveAnim2),
CCDelayTime::create(0.2f),
NULL)));
cloudSpr->setVisible(false);
startGoldSpr->setVisible(false);
backgroundSpr->setVisible(false);
backgroundSkySpr->setVisible(false);
backgroundNightSpr->setScaleX(CCDirector::sharedDirector()->getWinSize().width/designSize.width);
backgroundSkyNightSpr->setScaleX(CCDirector::sharedDirector()->getWinSize().width/designSize.width);
}
//daytime
if ( ((curHourTime > 6 && curHourTime < 18) && (_isAuto==true)) || _isDay==true) {
caveSpr->runAction(CCRepeatForever::create(CCSequence::create(CCAnimate::create(caveAnim1),
CCAnimate::create(caveAnim2),
CCDelayTime::create(0.2f),
NULL)));
cloudNightSpr->setVisible(false);
startGoldNightSpr->setVisible(false);
backgroundNightSpr->setVisible(false);
backgroundSkyNightSpr->setVisible(false);
backgroundSpr->setScaleX(CCDirector::sharedDirector()->getWinSize().width/designSize.width);
backgroundSkySpr->setScaleX(CCDirector::sharedDirector()->getWinSize().width/designSize.width);
}
and I don't know how to refresh these Sprite (remove and then recall them again).
Sorry for my bad English. Any help would be appreciated.
From what i understand from your question, you need to remove sprite from the scene and add it again.
CCNode/Sprite has this method removeFromParentAndCleanup(bool cleanup)
Also you can remove all child from a CCNode/Sprite with
removeAllChildrenWithCleanup(bool cleanup).
Node/Sprite can be assigned special setTag(), which can used later to remove special Sprite with removeChildWithTag(). People generally have enums to identify key elements.
I hope that answers your question.
Refrences:
http://www.cocos2d-x.org/reference/native-cpp/V2.2.3/d9/d1f/group__base__nodes.html#ga5889948f4c40933e93aaf70cb8846192
Finally figure out my issue, it's very simple that I can change the sprite image by using mySprite->setTexture(CCTextureCache::sharedTextureCache()->addImage("newImage.png"));
no more need to remove and then add it again.

How to schedule or call a method at random time interval in cocos2d iphone

I want to call a method at Irregular time interval means it should be random time plus i want it in some define range too.
Like : it should call at any second between 3 to 8 .
I tried this one :
[NSTimer scheduledTimerWithInterval: 1.0 target:self selector:#selector(myMethod:) userInfo:nil repeats: YES];
void mymethod()
{
if(arc4random() % 10 == 1)
{
// calling my method here;
}
}
This way , i am not getting randomization which i want.
Any one can please help me on this !!!
Here you can make a scheduler which will get called at random interval.
-(void)randomTimeScheduler{
int time = arc4random()%5;
int nextTimeOfCall = 3+time;
NSLog("it will be called after:%d",nextTimeOfCall);
[self performSelector:#selector(randomTimeScheduler) withObject:self afterDelay:nextTimeOfCall];
}
You have to call it from your class and then it will work as a scheduler. And it has finite interval time 3-8.

Invoke a method only once from a class

I have a shape class in which there is a method (hitTest(int,int)) that continuously checks if the mouse is inside its bounds or not. In another method, I keep on checking if the mouse has stayed there for more than 1 sec.
If it has, trigger a function (by notification/event) that runs animation
It it has not, then don't trigger the animation
If it has already triggered the animation and the animation is running but the mouse leaves the area during this, trigger an interrupt function (by notification/event)
//OnLoad _initHover = false;
void update() //called continously in the application per frame
{
if(hitTest(getMouseX(), getMouseY())){
if(!_initHover){
_initHover = true;
_hoverStartTime = getCurrentTime(); //start hover time
cout<<"Start hist test\n";
}
//If it has hovered over the video for 1.0 sec
if((ofGetElapsedTimef() - _hoverStartTime) > 1.0){
cout<<"Hitting continously for 1 sec\n";
notificationCenter->postNotification(new AnimationStartNotification);
}
}
else{
_initHover = false;
notificationCenter->postNotification(new AnimationInterruptNotification);
}
}
The above code runs fine but there's a logical issue I am facing while trying to use. There are multiple instances of the above Shape class and each class consequently has their update() method as well. The mouse cursor has which has animationStarthandler and animationStophandlers is a single class in the whole application.
Issue 1: So, even when one of the shape just notifies the animationStarthandler to fire, the other shape classes on which hit test is false set the animation to interrupt and the animation does not run.
Issue 2: When the hit test succeeds and the cursor has been in the area for more than 1 sec, the hit test will keep on sending the notification to start the animation (anim's duration 1.5 sec approx.) How do I restrict the hit test to fire the animation only once and keep on firing the same animation again and again?
If in the main method of my application, I directly try to fire the animation by calling the method playAnimation in the pointer class, I get the required result. But I want to give this hover timing and animation functionality to the ShapeClass itself. Any suggestions?
I think that you should consider adding a new boolean, which holds the information of the triggering of the animation (called in the code sample _animationTriggered). This prevents shapes that have not triggered the animation to stop it and the animation that triggered it to make it several times.
if(hitTest(getMouseX(), getMouseY()))
{
if(!_initHover)
{
_initHover = true;
_hoverStartTime = getCurrentTime();
cout<<"Start hist test\n";
}
if((ofGetElapsedTimef() - _hoverStartTime) > 1.0)
{
if (!_animationTriggered)
{
cout<<"Hitting continously for 1 sec\n";
notificationCenter->postNotification(new AnimationStartNotification);
_animationTriggered = true;
}
}
}
else
{
if ( _animationTriggered )
{
_initHover = false;
notificationCenter->postNotification(new AnimationInterruptNotification);
_animationTriggered = false;
}
}
Don't forget to initialie this new boolean in the same place as _initHover

Callback when Cocos2d CCParticleSystem has finished?

I'd like to run a callback/selector when a Cocos2d CCParticleExplosion is completely finished. How do I do this?
I tried using scheduleOnce with the same duration as the emitter, but that finish too soon since I guess the duration of the emitter controls for how long it will emit new particles, but not how long the complete animation lasts.
Try sequencing the action (using CCSequence) with a CCCAllFunc Action. After one action runs, the other runs, the CCCAllFunc can be assigned to the selector/method of your choice.
Not sure if this is acceptable, but I tested and "it works on my mac".
in CCParticleSystem.h
// experimental
typedef void (^onCompletedBlock)();
#property (readwrite, copy) onCompletedBlock onComplete;
in CCParticleSystem.m
#synthesize onComplete;
in the same file update method,
_particleCount--;
if( _particleCount == 0 && self.onComplete)
{
[self onComplete]();
[[self onComplete] release];
}
if( _particleCount == 0 && _autoRemoveOnFinish ) {
[self unscheduleUpdate];
[_parent removeChild:self cleanup:YES];
return;
}
In your code
particleSystem.autoRemoveOnFinish = YES;
particleSystem.position = ccp(screenSize.width/2, screenSize.height/4);
particleSystem.onComplete = ^
{
NSLog(#"completed ..");
};
again, quite experimental..