I'm confused with the addChild: behavior in Cocos2D, because of the following:
I have a CCNode subclass that owns a CCSprite and a Box2DBody.
Im the -init method of this subclass, i add the sprite to a CCSpriteBatchNode of the main GameScene, like this:
//Ball class, CCNode subclass with a CCSprite and a b2Body
-(id)initBallInWorld:(b2World *)word spriteFile:(NSString *)file
{
//self = [super init] blablabla
CCSpriteBatchNode *batch = [GameScene getSpriteBatch]; //singleton
//create Box2dBody inside the world
//create a CCSprite
[batch addChild:sprite]; //Here is the confusion!
}
In the main GameScene i do:
Ball *ball = [Ball ballInWorld...]
If i do [self addChild:ball], the physics works as expected, but if i don't, the ballSprite gets stuck at (0, 0)..why is that? The batch is already added to the GameScene, and the ballSprite is already added to the batch, this extra addChild seems weird to me!
Thanks!
Thanks for the comments, but i figure it out.
When i call the static [Ball ballInWorld:] the CCSprite is not retained in the Ball class, but only inside the CCSpriteBatchNode, so i have to use addChild:ball or use [[Ball alloc]init ...]to keep the sprite reference alive.
GameScene is a CCLayer, i think thats ok to use it as a singleton.
Related
I try to make a Code Connection with my game object (which is located in Enemy.ccb) in SpriteBuilder.
It works perfect when I just load my object and add it to the stage.
CCNode *enemy = [CCBReader load:#"Enemy"];
[self addChild:enemy];
Unfortunately it will not work when I set the custom class of the object to 'Enemy'. The asset is loading and its custom class is initializing, but it is not shown. What I am doing wrong?
EDIT:
Here's my simple implementation of the Enemy class. It is subclassed from CCSprite:
#implementation Enemy
- (id)init {
self = [super init];
if (self) {
CCLOG(#"Enemy created");
}
return self;
}
#end
What is the difference between Subclass of CCScene and Subclass of CCNode when adding new cocos2d CCNode class? I used CCScene when I was following cocos2d-tutorials, but in the cocos2d + SpriteBuilder project default MainScene class is subclass of node, so can somebody explain it to me?
Very little. Open CCScene's header file and you see it subclasses CCNode. If you open CCScene's implementation file you'll essentially see this (assuming we are talking about cocos2d v3):
#implementation CCScene
// -----------------------------------------------------------------
// Private method used by the CCNode.scene property.
-(BOOL)isScene {return YES;}
-(id)init
{
if((self = [ super init ]))
{
CGSize s = [CCDirector sharedDirector].designSize;
_anchorPoint = ccp(0.0f, 0.0f);
[self setContentSize:s];
self.colorRGBA = [CCColor blackColor];
}
return( self );
}
// -----------------------------------------------------------------
- (void)onEnter
{
[super onEnter];
// mark starting scene as dirty, to make sure responder manager is updated
[[[CCDirector sharedDirector] responderManager] markAsDirty];
}
// -----------------------------------------------------------------
- (void)onEnterTransitionDidFinish
{
[super onEnterTransitionDidFinish];
// mark starting scene as dirty, to make sure responder manager is updated
[[[CCDirector sharedDirector] responderManager] markAsDirty];
}
// -----------------------------------------------------------------
#end
What you see above is the scene's implementation. It is essentially a node with the content size set to the design size (view size if it is not set), an anchor point of (0,0), a flag that marks it as a scene (which is privately used by CCNode), and a black color for its RGBA. A CCNode does not assume this stuff (for example content size of a node is 0,0 whereas the scene has a a content size of the view/design).
Nodes are the base class for many cocos2d classes. A scene, as you see, is just a node with a meaningful name, a set content size the size of the view (unless you specify a design size), and a black color. On the other hand a sprite is also a node but with other properties related to sprites.
I haven't bothered to use Sprite Builder, but I'd assume by what you've wrote that everything is added to a CCNode, which is ultimately added to a CCScene. Since there is no CCLayer, I'd assume it is simply just using a CCNode to act as the default layer. Someone else can confirm since I've never had a reason to use Sprite Builder but that sounds like it would be the case.
I am developing game in cocos2dx.In Cocos2d for calling parent layer method from NSObject i had used this:
-(void)EnableTouch
{
CCScene *current = [[CCDirector sharedDirector] runningScene];
if (current) {
id layer = [current getChildByTag:8];
if (layer) {
[indicator stopAnimating];
[layer EnableTouch];
}
}
}
and i can call EnableTouch method of my parent layer...Now same thing i want to do with cocos2dx.
Here I have called Myclass.mm which is NSObject type(Objective C++ Source) from Info.cpp which has same type(Objective C++ Source) by making object like this:
Myclass *object=[[Myclass alloc]init];
[object temp];
Now,I want to call parent layer method(Info.cpp) after completion of process in temp function for that what I have to do? I have tried this:
CCScene *current=CCDirector::sharedDirector()->getRunningScene();
CCLayer *layer=(CCLayer *)current->getChildByTag(88);
Info *gamescene=dynamic_cast<Info *>(layer);
gamescene->temp();
But it gives error...What I have to change here?Please suggest if anyone know.
is there a reason why when you use CCTransitionFade this way.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[director_ pushScene:[CCTransitionFade transitionWithDuration:1
scene:[FirstScene node]]];
return YES;
}
and then the Second Scene is called inside the FirstScene's init to advance like a regular brand presentation of the game, why is it that if I don't put a scheduler that is a bit longer than the first CCTransitionFade timer why does it get stuck?
//in FirstScene Class
-(void) onEnter {
self = [super init];
if (self) {
[[CCDirector sharedDirector] replaceScene:
[CCTransitionFade transitionWithDuration:1.2 scene:[SecondScene node]]];
}
return self;
}
I mean I understand the reason why, but does this mean I have been doing this the wrong way? Is there a more acceptable way to do this CCTransitionFades or is it correct to use the Scheduler this way?
//in FirstScene Class
-(void) onEnter {
self = [super init];
if (self) {
[self scheduleOnce:#selector(makeTransition:) delay:1.2];
}
return self;
}
-(void)makeTransition:(ccTime)dt {
[[CCDirector sharedDirector] replaceScene:
[CCTransitionFade transitionWithDuration:1 scene:[SecondScene node]]];
}
By doing it the second way with SchedulerOnce I am able to sucessfully get what I want.
so, am I doing something wrong? Is this just a bad workaround from my side? Or is there a correct way to this situation?
Note: Made a correction because Currently I do have the code with onEnter method. but I have tried it with init and it does have the same behavior as well.
In first case when you call replaceScene from init, the order of calling functions looks something like that:
(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
[FirstScene node]
FirstSceneInit
[[CCDirector sharedDirector] replaceScene: ..
...
[director_ pushScene
The problem is because you call replaceScene when there aren't scene on screen, so the director try change the actual scene, which is NULL to FirstScene. The first scene appear on the screen after pushScene
In the second mostly works, but theoretically this solution is dangerous, because when you call init and set scheduler, then can be 2 seconds lag for example. I don't know that this is possible on cocos2d, which operate in one thread, but i think that putting replace scene in onEnter function is more elegant solution
A lot of example CCLayer subclasses I see have code that looks like this:
+(CCScene *) scene{
CCScene *scene = [CCScene node];
HelloWorldLayer *layer = [HelloWorldLayer node];
[scene addChild: layer];
return scene;
}
Who calls that method and what purpose does it serve? Does it need to be there? Is it convenient for some future purpose?
Yes, it is needed. This method is called in applicationDidFinishLaunching method of ApplicationDelegate. For example in the HellowWorld template it is called in this line in AppDelegate:
[[director_ pushScene: [HelloWorldLayer scene]]
The ccDirector can run only CCScene, and it can run only one CCScene at a time. That is why CCLayer creates a CCScene first and then adds itself as a child to it.
As an alternative, you can subclass CCScene and add your CCLayers and etc to it by overriding its init method like this:
-(id) init {
if (self = [super init]){
CCLayer *aLayer = [CCLayer node];
[self addChild: aLayer];
....
}
return self;
}
and replace this line [[director_ pushScene: [HelloWorldLayer scene]] with this [[director_ pushScene: [myScene node]] in the applicationDidFinishLaunching method of AppDelegate.
All I know is that it isn't needed, I've wondered the same thing. I think it is because they want to encourage the use of scenes a bit. Your scenes should consist of layers and you should switch between scenes.