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
Related
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.
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.
How do you handle the setAction message in Objective-C++? (Not Objective-C.)
For example, suppose I have:
my_class.mm
NSSegmentedControl *segmented = [[NSSegmentedControl alloc] init];
[segmented setSegmentCount:5];
// etc.
[segmented setAction:???];
Application: I am programming in Qt (C++) and need a wrapper around some Cocoa widgets I want to use directly. I am inheriting from QMacCocoaViewContainer but can't figure out how to handle the "clicks" of the NSSegmentedControl I am wrapping. Eventually this will emit a standard Qt signal.
action is just a selector - it is used in tandem with target. so write an objc method for target+action which calls through or does what you really want. actions' arguments are the sender, but you can omit that if you don't need it. the sender will be whatever is sending the message (e.g. the control). it's no different in ObjC++ - this has to be wrapped in an objc method because the target must be an objc object.
so it would look like this:
obj.action = #selector(pressDoStuff:);
and the method is:
- (void)pressDoStuff:(id)sender
#Justin has the right answer; I'll accept it, but also include the final solution in case it helps others. The trick is you need a proxy class, as #smparkes noted.
Ignoring the .h files for brevity:
mac_control.mm
MacControl::MacControl(QWidget *parent) : QMacCocoaViewContainer(NULL, parent) {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSSegmentedControl *segmented = [[NSSegmentedControl alloc] init];
// Set up NSSegmentedControl...
// The proxy class marshalls between Objective-C and C++.
proxy_ = [[MacControlProxy alloc] init];
[proxy_ setTarget:this];
[segmented setTarget:proxy_];
[segmented setAction:#selector(handleToggle:)];
setCocoaView(segmented);
[segmented release];
[pool release];
}
MacControl::~MacControl() {
delete proxy_;
}
void MacControl::TriggerAction(int index) {
// Trigger the action in Qt/C++.
}
mac_control_proxy.mm
#implementation MacControlProxy
- (id)init {
[super init];
target_ = NULL;
return self;
}
-(void) handleToggle: (id)sender {
if (target_) {
target_->TriggerAction([sender selectedSegment]);
}
}
-(void) setTarget: (MacToolbarButtonControlImpl*)target {
target_ = target;
}
#end
I'm following up on Dave Mateer's answer (which was super helpful!).
I was having issues setting the C++ target (from within a objective-C++ class) and used [NSValue valueWithPointer:theTargetCxxClass] to pass the target to the Proxy.mm class.
So, inside of my Objective-C++ class, rather than doing this:
[proxy_ setTarget:this];
I did this:
[proxy_ setTarget:[NSValue valueWithPointer:this]];
or
[proxy_ setTarget:[NSValue valueWithPointer:ptrToMyCxxObject]];
And doing this got rid of an error about passing a C++ class (which does not extend type "id") to the Objective-C++ proxy class.
Inside of the proxy class, you then need to use NSValue's pointerValue method and then cast back to the C++ class in order to send a message to it.
-(void) myButtonAction: (id)sender {
((MyCxxClass*)[target pointerValue])->someMethodInMyCxxClass();
}
I first was alerted to the "valueWithPointer" trick in this post.
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.