I've got the basic engine of a game put together rather nicely, my issue at the moment is that while running it from my computer onto my iPhone, I'm getting a strange debug message:
CCScheduler#scheduleSelector. Selector already scheduled. Updating interval from: 0.0000 to 0.0000
This debug message is being displayed every frame or nearly every frame
Now, I don't have any scheduled updates that are on interval 0, so this makes me think that it must be the generic scheduleUpdate command. I did a search entire project to see if any class had multiple scheduleUpdates and none do so now I am confused. Any thoughts?
I generally get this message when I schedule something that's already scheduled. See if there's anything like this in your code:
[self schedule:#selector(gameLogic:) interval:1.0];
- (void) gameLogic : (ccTime)dt
{
[self doLogic];
[self schedule:#selector(updateTimers:) interval:1.0];
[self schedule:#selector(gameLogic:) interval:1.0];
}
By repeatedly scheduling something inside a timed event, you'll get a warning that you've called the timer a second time.
Related
I'm using cocos2d and cocosBuilder.
I'm trying to do a starting animation, and then once it has finished, make all of the children nodes perform their idle animations.
how I'm doing the starting animation:
(void) onEnter
{
[super onEnter];
CCLOG(#"onEnter being called");
// Schedule a selector that is called every frame
[self schedule:#selector(update:)];
// Make sure touches are enabled
self.touchEnabled = YES;
//intro animation
CCBAnimationManager* animationManager = self.userObject;
animationManager.delegate = self;
[animationManager runAnimationsForSequenceNamed:#"words"];
}
and this is what my completedAnimationSequenceNamed looks like:
(void) completedAnimationSequenceNamed:(NSString *)name{
CCLOG(#"animation ended");
for(CCNode *c in [self children])
{
if([c isKindOfClass:[GameObject class]])
[c playIdleAnimation];
}
}
For some reason, my completedAnimationSequenceNamed is being called repeatedly, many times a second, causing my children to constantly restart their idle animations.
Any ideas?
I got it working, this is for anybody else running into this problem.
In order for the "(void) completedAnimationSequenceNamed:(NSString *)name" method to work properly you must have your animation start automatically (in the cocosBuilder project) instead of using running Animations from animationManager.
If I used the runAnimation method from animationManager, it (essentially) broke the callback method. But I just took that out and made the animation run automatically and it calledback as expected.
My problem is this: i do quite a bit of code in ccTouchEnded and i want for the CCTouchDispacher to stop all input until all actions on the screen are over. The thing is that when i tap the screen repeatedly ccTouchEnded gets called every timeand it ruins everything. I've tried to stop the input but i don't know which of the actions will execute..so i can't just run a CCSequence and when it's finished re-enable input.
My code looks something like this:
if (taped in a rect)..do action, change some things around,do another action, call method 1
if (condition)..do action,check something,(if (check) do action, else call method 2)
Its worth noting that the methods do different things in different layers which take different amounts of time.
So my question is this: Is there any way to check if all actions on the screen are completed?
Check that the number of running actions on the node/sprite/layer is zero:
http://www.cocos2d-swift.org/docs/api/Classes/CCNode.html#//api/name/numberOfRunningActions
Such as:
[mySprite numberOfRunningActions]==0
You have the isDone function that tells you if an CCAction is finished. From the docs:
(BOOL) - isDone return YES if the action has finished
I have a simple CCRotateBy action in a sequence; it is followed by a call to another method which confirms that the CCRotateBy completed (otherwise, that CCCallFunc would not get called in the sequence if CCRotateBy didn't complete):
-(void)correctRotation{
if (self.rotationAmount){
CCLOG(#"correcting rotation inside: %i",self.buildNum);
CCRotateBy*second=[CCRotateBy actionWithDuration:1 angle:-self.rotationAmount];
CCEaseBackInOut*bounce2=[CCEaseBackInOut actionWithAction:second];
CCCallFunc*func=[CCCallFunc actionWithTarget:self selector:#selector(stabilize)];
CCSequence*seq=[CCSequence actions:bounce2,func, nil];
[self runAction:seq];
}
}
-(void)stabilize{
CCLOG(#"stabilize before rotation: %i for %i",self.rotationAmount,self.buildNum);
self.rotationAmount=0;
CCLOG(#"stabilize after rotation: %i for %i",self.rotationAmount,self.buildNum);
}
The CCLog statements are confirming that the rotation should be happening, and that the angle of the rotation is not nil (it is always an integer). These logs also show that the CCSequence is completing. However, the sprite is not rotating on the screen. I've been pouring over this code for hours trying to figure out what could be going wrong. If the sprite's actions were being stopped, then these 3 log statements would not complete, right?
As #tassinari says try removing the bounce function.
This is from the cocos2d api reference
http://www.cocos2d-iphone.org/api-ref/1.1.0/interface_c_c_ease_back_in_out.html
Warning:
This action doesn't use a bijective function. Actions like Sequence might have an
unexpected result when used with this action.
Quick look but you're not calling CCRotateBy in your sequence. The 'second' action is not in the sequence.
I'm getting stuck to implement some Cocos2D animations for my Tetris clone(that works perfectly, no logic bugs, i just want to perform some smooth animation when deleting rows).
The current code(no animation) just drops the block position, like this:
block.position = ccp(block.position.x, block.position.y - kBlockSize);
This happens in a for loop for, classic tetris programming. But when i try to animate, like this:
id move = [CCMoveBy actionWithDuration:0.5f position:(0, -kBlockSize)];
[block runAction:move];
Some blocks just moves down once, even tough the action may be called multiple times for the same block(when breaking more than one row for example)...
Why that happens ? I know it's a little bit confusing, but the point is that i'm doing the same stuff and getting different results...i could post more code to help clarify!
Thanks!
I'm quite sure actions are parallel operations so you could be calling a CCMoveBy action before a previous one is completed. Some alternatives I have used are...
Monitor for when the action completes by using a CCSequence finishing with a CCCallFunc action that sets a flag. Something like...
id myAction = [[CCSequence runWithActions:[CCMoveBy actionWithDuration:0.5f position:(0, -kBlockSize)], [CCCallFunc actionWithTarget:self selector:#selector(myFunc)], nil]
Roll your own solution using a velocity variable in a tick or update function where you can get a hold of delta time/# of ticks since the last update
Hope some of that helps.
Thank you guys, those answers help me a lot!
I've tried CCSequences before posting here, but without success.
The problem was the following:
Inside the CCSequence that deletes a row, i have 2 actions: the first one fades out the entire row of blocks(duration of x seconds), and the second one drops all the blocks above the row(duration of y seconds).
This works fine if ONLY ONE row needs to be deleted, because if there is more than one row, the next CCSequence starts nearly the same time the previous, reading a incorrect position of the blocks above, leading to a incorrect cascade of blocks.
I solved that using a longer CCSequence, that takes a CCCallFuncND as the last argument:
id fadeOutSequence = [CCSequence actions:fadeout, destroyBlocks, notifyFadeFinish, nil];
//inside method specified for notifyFadeFinish:
id dropAbove = [CCSequence actions: dropBlocks, notifyDropFinish, nil];
//inside method specified for notifyDropFinish
//start a new delete sequence, if there is more rows to delete.
Now going to implement gravity mode, thanks again!
I'm using Cocos2d to write game for iPhone.
Here's the problem.
I have CCSprite and CCAction which is run on it.
CCSprite texture;
CCAction anim_action;
"Anim_action" is a CCRepeatForever action.
Now I want to check if this animation is running.
First I though I can use [isDone] function, but I think it doesn't work on CCRepatForever actions (I'm not sure - this opion is based on my tests)
So how to check if this animation is already running on my "texture"?
Maybe there is a way to get name of action which is running on texture at the moment?
It may be also useful!
There is a way to check if a specific action runs on your texture. Use:
CCAction *action = [texture getActionByTag:kAsignedActionTag];
where kAsignedActionTag is the tag assigned to the your animation.
anim_action.tag = kAsignedActionTag;
If your action is still running the getActionByTag method will not return nil.
I don't believe there's a way to directly tell if a CCRepeatForever action has completed since the isDone would make no sense, but there are some techniques you can use to essentially provide a callback to indicate if something is still running:
Override the step: method and call out to something that checks the interval - when it exceeds a threshold you can assume completion...kinda'
Wrap the inner action of the CCRepeatForever with a CCSequence. The first action of the sequence would be your repeated action and the second would be a CCCalFunc, again indicating that the action is still running
Subclass the CCRepeatForever and override the dealloc so you can fire a callback when the action is killed and released
You can easily use [isDone] while appling an effect
- (void)shakeThatThingOn: (BOOL)on { //you can return BOOL and get if the animation is working or not
if (on == YES){
id shaky2 = [CCShaky3D actionWithRange:3 shakeZ:NO grid:ccg(15,10) duration:5];
if (![shaky2 isDone])
[self runAction:[CCSequence actions:shaky2,[CCStopGrid action],nil]];
}
else {//this else is being called when you turn off animation (it's just 0.2s continuation after turning off - for better visual effect.
[self stopAllActions];
id shaky2 = [CCShaky3D actionWithRange:3 shakeZ:NO grid:ccg(15,10) duration:0.2];
[self runAction:[CCSequence actions:shaky2,[CCStopGrid action],nil]];
}}
and control it by simple BOOL if it's on or off.
I don't know if it's what you mean, but hope it'll help anyway.
If you know how many actions will be running on the sprite, or if the animation is the only action, then you can infer that the animation is running by checking the sprite's total number of running actions.
if ([texture numberOfRunningActions] > 0) //animation is running
or
if ([texture numberOfRunningActions] > someNumber) //if you had other actions running