So, I want to create a slow motion effect, and I am using this method:
[[CCScheduler sharedScheduler] setTimeScale:0.5];
However, sharedScheduler is deprecated.
What is the equivalent method of creating a slow motion effect?
All answers and advice are appreciated!
You have to use [CCDirector scheduler].
CCActionManager, CCScheduler, CCTouchDispathcer (iOS) and
CCEventDispatcher (Mac) are NO LONGER singletons. Instead, they are
properties of CCDirector.
Link to documentation:
http://www.cocos2d-iphone.org/wiki/doku.php/prog_guide:migrate_to_v2.0
--
If I understand what you mean by slow motion effect correctly, you can also use actions as follows (am dry coding here so might require cleanup):
CCNode *obj = //some object;
[obj runAction:[CCSequence actions:
[CCDelayTime actionWithDuration:0.5],
[CCCallFunc actionWithTarget:self selector:#selector(YOURFUNCTION)],nil]];
Try replacing:
[[CCScheduler sharedScheduler] setTimeScale:0.5];
with:
[[[CCDirector sharedDirector] scheduler] setTimeScale:0.5];
Related
I am translating a piece of code from cococs2D to cocos2D-X. I came across the following lines that i cannot fathom out how to translate
[spriteBg runAction:[CCSequence actions:sc,[CCCallFuncO actionWithTarget:basketTimer_ selector:NSSelectorFromString([selectors objectAtIndex:0]) object:sprite], nil]];
Can someone please help me translate this to Cocos2d in Cocos2d-X ?
Kind Regards,
try this..
spriteBg->runAction::create(CCSequence::create(sc,CCCallFunc::create(this, callfunc_selector(myMethod)),NULL));
In your code the myMethod is replaced by the selector at the index 0 of the "selectors" which I'm guessing is an array of the selectors or a dictionary or something like that.
and "sc" is a predefined action which is to be run on spriteBg.
For cocos2d-x v 2.2.1:
NSSelectorFromString([selectors objectAtIndex:0] <- in cocos2d-x you can't create selector from string, so you must know function you want call, or keep selectors in container(but I never do this)
CCCalFuncO *call = CCCallFuncO::create(basketTimer_, callfuncO_selector(BasketTimerClass::BasketTimerMethod), sprite)
spriteBg->runAction(CCSequence::create(sc, call, NULL));
Every class in cocos2d-x and cocos2d-iphone have the same name, so you can easly find it in documentation:
CCSequence CCCalFuncO
I am using Cocos2d 2.1rc0.
I have this project that was working perfectly when I was not using CCSpriteBatchNode. Then I decided to use batch nodes to reduce draw calls and my problems started.
A lot of stuff is not working well. reorderChild is one. Another one is runAction and without runAction Cocos is useless.
This is an example of a method that works without batchNodes and do not work with it.
// move/rotate all objects
for (int i=0; i<[allObjects count]; i++) {
Card *object = [allObjects objectAtIndex:i];
[object stopAllActions];
CGPoint center = object.position;
center.x = center.x + 100;
center.y = center.y - 200;
CCMoveTo *moveAction = [CCMoveTo actionWithDuration:0.3f position:ccp(center.x, center.y)];
CCRotateTo *rotateAction = [CCRotateTo actionWithDuration:0.3 angle:0.0f];
CCSpawn *action = [CCSpawn actions:moveAction, rotateAction, nil];
[object runAction:[CCSequence actions: action,
[CCDelayTime actionWithDuration:0.1f],
nil]];
}
Exactly nothing happens.
I have tried to eliminate the CCSpanw and use runAction directly just with move and nothing works. If I use regular sprites, it works.
Objects in that array derive from a CCSprite based class.
Is there any workaround?
the solution is to cast the class to the object extracted from the array...
instead of
Card *object = [allObjects objectAtIndex:i];
this
Card *object = (Card *)[allObjects objectAtIndex:i];
After double-checking in a clean project that this isn't a weird side-effect of some kind, I have to say there's something fishy about your project. Hard to tell what, though.
What I did: create a sprite-batch, add a sprite to it, also store it in an array. In a scheduled method I'm receiving the sprite from the array (not casting) and run your action sequence posted above. It works fine, as expected.
The casting should not make any difference. Batched or non-batched sprite should not make any difference either.
If it does, something really weird is going on. After all the card object is the same with or without casting. If it were not actually running the runAction method, you'd be receiving an "unrecognized selector sent to instance" error. But that's not the case.
Try again without casting, after rebooting your device, your machine, cleaning the project in Xcode and rebuilding. Also test in debug and release configurations. I've had the weirdest issues that were gone after doing one of the above, and definitely all of the above. If that doesn't fix things, you can be sure it's a problem with the code (memory leak is my alltime favorite) or the project settings (ie uncommon compiler optimizations sometimes can have side-effects).
Step into the runAction method if it really doesn't run the action - I'm sure it will add the action to the action manager. Try with and without casting to see if there really is a different code path taken. I doubt it.
I have been building the SpaceViking project described in the book "Learning Cocos2D". I had got to chapter 10 on Box2D when I started to experience problems. I then attempted to upgrade cocos2D from version 1 to version 2.0. After making the necessary changes to fix deprecations, the code no longer works. Specifically, I have found that when game objects or enemy objects are created, their init methods are no longer being called. For example, when the following line is executed:
RadarDish *radarDish = [[RadarDish alloc] initWithSpriteFrameName:#"radar_1.png"];
the RadarDish init method is not called. I then looked into the execution of initWithSpriteFrameName in both version 1 and version 2 and found that CCSprite.m has change such that the init method is no longer called. In the version 2 source code, initWithSpriteFrameName method calls initWithSpriteFrame which calls initWithTexture which calls:
-(id) initWithTexture:(CCTexture2D*)texture rect:(CGRect)rect rotated:(BOOL)rotated
{
if( (self = [super init]) ) {
Consequently, RadarDish init method is not called. Instead, CCNode init method is called. However in version 1, initWithSpriteFrameName calls initWithSpriteFrame which calls initWithTexture which has this code:
// IMPORTANT: [self init] and not [super init];
if( (self = [self init]) ){
[self setTexture:texture];
[self setTextureRect:rect];
}
That allows the RadarDish init method to be called.
What can I do to resolve this? It seems unlikely that the book would need to change to support the upgrade to cocos2d v2.0, so I suspect I must be missing something else. But if I am wrong, then what would be the way to change this code to cause the RadarDish init method to be called?
Ok, I was wrong. "cocos2d 2.x is different in many details from v1.x so can't expect v1.x code to just work under 2.x". If you are going to follow the book "Learning Cocos2D", I would recommend loading cocos2d-iphone version 1.0.1. Otherwise, you will be faced with many incompatibilities as well as a lot of deprecations to fix.
But if you really want to use the latest cocos2d, then there are some things you should do. 1) Follow the instructions in this link. 2) You are going to have a lot of deprecations and changes to fix, so use this link to understand how to fix those deprecations and changes. 3) You'll need to update the Joystick classes also, so go to this link to get those changes, 4) you'll have to google the rest to find solutions.
Now as for the solution to the problem I mentioned here, there are likely multiple solutions but I will offer one below (thanks to Sylvan's answer above):
In each of the GameObjects, EnemyObjects, and PowerUps, I added a method to override initWithFrameName. This will circumvent the use of the objects init method. For example, for the RadarDish, I added the following:
-(id) initWithSpriteFrameName:(NSString*)frameName {
if( (self=[super init]) ) {
if ((self = [super initWithSpriteFrameName:frameName])) {
CCLOG(#"### RadarDish initialized");
[self initAnimations]; // 1
characterHealth = 100.0f; // 2
gameObjectType = kEnemyTypeRadarDish; // 3
[self changeState:kStateSpawning]; // 4
}
}
return self;
}
This allows the GameObject and GameCharacter init methods to run before the CCSprite's initWithSpriteFrameName method to run.
The Viking GameObject had to have a slightly different solution because it is initialized with initWithSpriteFrame rather than initWithSpriteFrameName. But the override implementation is basically the same as the example of RadarDish above.
(Aside from all the changes necessary to overcome the deprecations) The above change allowed everything else in the examples of "Learning Cocos2D" to remain intact.
Good Luck.
I think you are having trouble because you are keeping your init method as it was and not modifying it. You are calling a method initWithSpriteFrameName: on your RadarDish class but that class doesn't have that method name, so it looks to its superclass. I think you could have simply renamed your init method to initWithSpriteFrameName: and you would have been fine. Like this:
// RadarDish.m
-(id) initWithSpriteFrameName:(NSString*)frameName {
if ((self = [super initWithSpriteFrameName:frameName])) {
// init anything here
}
return self;
}
Just don't also have a method named init and expect it to get called.
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
I am totally new to cocos2d and Objective C. I just started studying the HelloWorld example that came with cocos2d package, and just couldn't figure out where in the application the -init() function within HelloWorldScene.m is getting called.
Here is the tutorial that I was following:
http://www.bit-101.com/blog/?p=2123
Thanks in advance!
jtalarico is correct. I'd like to expand on his answer a bit.
In general, some form of [init] is called by convention whenever an object gets instantiated. For many objects, [init] is all that is needed, but some objects have more complex forms, such as [initWithSomething].
In Cocos2d, the init function is generally called by the [node] method, which is often used to construct an object in Cocos2d. For example, look in CCNode.m, and you will see this code:
+(id) node
{
return [[[self alloc] init] autorelease];
}
Other objects have other constructors, but this is the main example.
So, if you subclass CCNode, you can override the [init] method and do your own stuff when an object gets created. Just be sure to call [super init] so that CCNode can do its own initialization, too.
The init() method is being overridden in the scene. It is getting called within the base class when an instance of the scene is created. By overriding it, you get the opportunity to fire your own code.