I can't seem to get CCCallFuncO working with actionWithTarget set to (JoinedMapsLayer*)self.parent
JoinedMapsLayer is the parent node that a sprite class gets added to.
Inside the sprite class I have a method:
-(void) playAction:(NSString*)name withMessagePart:(NSString *)messagePart {
id displayMessageBox = [CCCallFuncO actionWithTarget:(JoinedMapsLayer*)self.parent
selector:#selector(displayMessageBox:)
object:[NSString stringWithFormat:messagePart]];
if([name isEqualToString:#"shiver"]){
id a1 = [CCMoveTo actionWithDuration:.05 position:ccp(self.sprite.position.x+2, self.sprite.position.y)];
id a2 = [CCMoveTo actionWithDuration:.05 position:ccp(self.sprite.position.x-4, self.sprite.position.y)];
id a3 = [CCMoveTo actionWithDuration:.05 position:ccp(self.sprite.position.x+4, self.sprite.position.y)];
id a4 = [CCMoveTo actionWithDuration:.05 position:ccp(self.sprite.position.x-2, self.sprite.position.y)];
[self.sprite runAction:[CCSequence actions:a1,a2,a3,a2,a3,a2,a3,a2,a3,a2,a3,a2,a3,a2,a3,a2,a3,a2,a3,a2,a3,a2,a3,a4,displayMessageBox, nil]];
}
else if([name isEqualToString:#"spin"]){
id a1 = [CCRotateBy actionWithDuration:.5 angle:360];
[self.sprite runAction:[CCSequence actions:a1,displayMessageBox, nil]];
}
}
It runs the actions just fine on the sprite, but I'm trying to get it to call a method in the parent node. I have a NSLog in there to check, and nothing happens. Any obvious reasons why?
In my parent node's init the class is added to a mutable array
HummingClass *hummingChar = [[HummingClass alloc] init];
[characterArr addObject:hummingChar]
And I access the class later on like:
HummingClass *hummingChar = [characterArr objectAtIndex:interactionIndex];
Interesting thing is that it doesn't crash with self.parent, so I'm thinking I'm not pointing to the parent node correctly. In the objects header I have
#import "JoinedMapsLayer.h"
#class JoinedMapsLayer
edit: even if I do a regular method call like this, it won't work:
[(JoinedMapsLayer*)self.parent displayMessageBox:#"whatever"];
I figured it out with the help of something awful forums. If a sprite is added to an array, you have to assign the parent property manually.
In init in JoinedMapsLayer, I make a temporary pointer to an array index:
tempHummingChar.parent = self;
Related
I have several layers in the scene, like TLayer,HLayer,TouchLayer. How can I get HLayer in HLayer? The solution I take is that I pass Layer to other Layer. However I met some problems recently. I push the Scene and pop Scene while TouchLayer still exists. So my problem is that is it right to pass HLayer to TouchLayer. Or is there a better way to do it in Cocos2d-x?
In the init() function in Scene:
this->setbackgroundLayer(BackgroundLayer::create());
CC_BREAK_IF(!backgroundLayer);
this->addChild(backgroundLayer);
this->setTLayer(TcharacterLayer::create(backgroundLayer->tianzige));
CC_BREAK_IF(!TLayer);
this->addChild(TLayer);
this->setHLayer(HcharacterLayer::create(testCharacter,backgroundLayer->tianzige_draw));
CC_BREAK_IF(!HLayer);
this->addChild(HLayer);
this->settouchLayer(TouchLayer::create(TLayer,HLayer));
CC_BREAK_IF(!touchLayer);
this->addChild(touchLayer);
I made my own create function:
TouchLayer* TouchLayer::create(TcharacterLayer* t,HcharacterLayer* h){
TouchLayer* pRet = new TouchLayer();
if (pRet && pRet->init(t,h))
{
pRet->autorelease();
return pRet;
}else
{
delete pRet;
pRet = NULL;
return NULL;
}
}
Here's how we've done this in the past. Define a set of tags for our layers.
typedef enum {
kBgLayerTag,
kHLayerTag,
kTLayerTag,
kTouchLayerTag
} MyLayerTags
Then while creating the layers set layer specific tags:
this->setTLayer(TcharacterLayer::create(backgroundLayer->tianzige));
CC_BREAK_IF(!TLayer);
TLayer->setTag(kTLayerTag);
this->addChild(TLayer);
And in TouchLayer access the TLayer and others like:
TcharacterLayer* myTLayer = this->getParent()->getChildByTag(kTLayerTag);
Sure, there is nothing wrong in adding a layer as a child. I would do that this way :
BackgroundLayer has all the necessary layers as children (remember to add TouchLayer as the last one and then pass Touch to others) and then you only add BackgroundLayer to your scene. There is even more simple way (probably better): to make BackgroundLayer inherit all the previous ones - but that depends on how much scenes you are going to make.
Edit:
1)
BackgroundLayer * bglayer = BackgroundLayer::create();
TcharacterLayer * tcharlayer = TcharacterLayer::create();
HcharacterLayer * hcharlayer = HcharacterLayer::create();
TouchLayer * tlayer = TouchLayer::create();
bglayer->addChild(tcharlayer);
bglayer->addChild(hcharlayer);
bglayer->addChild(tlayer);
this->addChild(bglayer);
(assuming this as a CCScene)
2)
class BackgroundLayer : public TcharacterLayer, HcharacterLayer, TouchLayer
{
...
}
In the first case you can give each layer a specific tag and then get the layer by getChildByTag(int tag) or just create fields in the BackgroundLayer class for each layer.
How can I add/remove CCMenu when the same button is clicked? I have added some code..
Thanks in advance..
CCMenu *menu;
if (!isMenuVisible) {
CCMenuItemSprite *item = [CCMenuItemSprite itemFromNormalSprite: .......];
menu = [CCMenu menuWithItems:item, nil];
[self addChild:menu];
} else {
// [menu cleanup];/// didn't work
// [menu removeFromParentAndCleanup:YES]; //// didnt work
// [menu removeAllChildrenWithCleanup:YES]; //// didn't work
}
isMenuVisible = !isMenuVisible;
}
you probably want to have the top line in your .h file, making the menu an iVar, to that the reference is kept in between successive executions of this code. Set menu to nil after you remove it.
One way - to create two menus. One for show/hide button, another for all buttons that have to be shown/hidden. It is not good way.
Another way is just to add/remove menuitems to the menu. I mean something like that:
- (void) removeItems
{
for(CCNode* item in _addedItems)
{
[item removeFromParentAndCleanup: YES];
}
[_addedItems removeAllObjects];
}
- (void) addItems
{
// create needed items and add them as children
// to your menu and add them to _addedItems array
// to be able to remove added objects
}
Also before using methods like cleanup, check it's code or at least cocos2d documentation. In your case it was comletely useless.
I am trying to subclass a CCMenuItem using the following code:
GenericButton.h
#import <Foundation/Foundation.h>
#import "cocos2d.h"
#interface GenericButton : CCMenuItemSprite {
}
+(id) itemwithTitle:(NSString*)title withBGColor: (ccColor3B) bgColor andFGColor:(ccColor3B)fgColor;
#end
GenericButton.m
#import "GenericButton.h"
#import "HelpfulClasses.h"
#implementation GenericButton
+(id) itemwithTitle:(NSString*)title withBGColor: (ccColor3B) bgColor andFGColor:(ccColor3B)fgColor{
CCSprite*genericButtonBG = [CCSprite spriteWithSpriteFrameName:#"genericButtonBG.png"];
genericButtonBG.color=bgColor;
CCSprite*genericButtonBGPressed = [CCSprite spriteWithSpriteFrameName:#"genericButtonBGPressed.png"];
genericButtonBGPressed.color=bgColor;
CCMenuItemSprite*button = [CCMenuItemSprite itemWithNormalSprite:genericButtonBG selectedSprite:genericButtonBGPressed];
CCSprite*fgButton = [CCSprite spriteWithSpriteFrameName:#"genericButton.png"];
fgButton.color=fgColor;
[button addNodeInMiddleOfParent:fgButton];
CCLabelBMFont *buttonTitle = [CCLabelBMFont labelWithString:title fntFile:#"font.fnt"];
if ([title length]>7) {
buttonTitle.scale=0.85;
}
buttonTitle.color=ccYELLOW;
[fgButton addNodeInMiddleOfParent:buttonTitle];
return button;
}
// on "dealloc" you need to release all your retained objects
- (void) dealloc
{
// in case you have something to dealloc, do it in this method
// in this particular example nothing needs to be released.
// cocos2d will automatically release all the children (Label)
// don't forget to call "super dealloc"
[super dealloc];
}
#end
But whenever I am using GenericButton*button = [GenericButton item....], in a CCScene, there is a lot of"removeChildByTag: child not found!" showing on the console. Am I doing something wrong?
Cheers
After two months you've probably figured this out yourself. Doesn't this website have a way to PM somebody? So sorry if I resurrect and old thread.
You are not including all your code for this class. However, I can point out something I saw that is an issue and could possibly be the source of your problem. In your class method you are creating and returning a pointer to "CCMenuItemSprite" called "button". This should be a pointer to your class "GenericButton".
How do I create a CCMenuItem list dynamically?
//Returns me an array with my items
Items *items = [ItemParser loadItemsForLevel:selectedLevel fromSuperLevel:selectedSuperLevel];
For an item I have a string with the name of the item that I'd like to display in my CCMenu. The number of items could vary but I want to display only 6 items at a time
and how do I remove it? I'm cleaning up from the CCLayer but I'd like to do it also from the menu list
Anyone?
Cocos2D does not provide a method to do this.
You may create your own initializer based on the original one found in "CCMenu.m".
The original looks like this (I removed code that does not add items here for clarity). Create your own init method based on the original and add a variable amount of items instead. If you like you may also set it up as a category to CCMenu.
-(id) initWithItems: (CCMenuItem*) item vaList: (va_list) args
{
if( (self=[super init]) ) {
// ... code cut for clarity
if (item) {
[self addChild: item z:z];
CCMenuItem *i = va_arg(args, CCMenuItem*);
while(i) {
z++;
[self addChild: i z:z];
i = va_arg(args, CCMenuItem*);
}
}
// ... code cut for clarity
}
return self;
}
Update:
When your menu items change then rebuild the whole menu.
I have a CCLabelAtlas that I have on a layer to display the current score within my game...the problem that I am having with it is that it does not update when I use [scoreLabel setString:]. Here's how I have it laid out:
In the header:
#interface GameScene : CCLayer {
...
CCLabelAtlas* scoreLabel;
}
And in the init:
scoreLabel = [[CCLabelAtlas alloc] initWithString:#"0" charMapFile:#"scoreCharMap.png" itemWidth:6 itemHeight:8 startCharMap:'.'];
[scoreLabel setPosition:ccp(105, 414)];
[self addChild:scoreLabel z: 6];
scoreCharMap.png is a custom map that includes ./0123456789 of my desired font. When the score is changed, I attempt to do this to get the label to update with the current score:
NSString* str = [[NSString alloc] initWithFormat:#"%d", [[GameRunner sharedInstance] currentScore]];
[scoreLabel setString: str];
[str release];
[scoreLabel draw];
Problem is that it doesn't ever update - it just sits there and displays 0. I know for a fact due to breakpoints and debugging that setString is being called, and that the string that it should be displaying is correct - but it just doesn't update. Hard-coding the value and saying [scoreLabel setString:#"1234"] does nothing, either. What am I doing wrong here? I am using Cocos2d 0.99 - thanks in advance!
Maybe this is something wrong with the font you are using? Try using one of the font maps that came with Cocos2D and see if it works for you.
The method -[CCLabelAtlas setString:] does a few things.
Can you verify that following goes right: (place a breakpoint and step through the function)
resizeCapacity doesn't fail to resize
updateAtlasvalues retreives a UTF8 character array pointer. Inspect that to see if that's the correct string, and while you're there, inspect n in the same method, which should be your string length
See code for setString below:
- (void) setString:(NSString*) newString {
if( newString.length > textureAtlas_.totalQuads )
[textureAtlas_ resizeCapacity: newString.length];
[string_ release];
string_ = [newString retain];
[self updateAtlasValues];
CGSize s;
s.width = [string_ length] * itemWidth;
s.height = itemHeight;
[self setContentSize:s];
}
Let me know what the results are, if you still need any help.