How do you place a ccmenuitem with a cclabel underneath it? - cocos2d-iphone

In cocos2d-iphone, I would like to use a sprite for the menu button item and I'd like to place a label underneath it describing the button.
However, I am not sure how to do this.
If I attempt to make more buttons/labels and then use
[menu alignItemsHorizontallyWithPadding:1.5f];
The position of the items is wrong.
Anyway, here is my code;
// Button
CCSprite *panel = [CCSprite spriteWithFile:#"panel.png"];
// Menu
CCMenu *menu = [CCMenu menuWithItems:nil];
CCLabelBMFont *lblFont = [CCLabelBMFont labelWithString:#"Some text" fntFile:#"arial16.fnt"];
CCMenuItemLabel *mnuLabel = [CCMenuItemLabel itemWithLabel:lblFont];
CCMenuItemSprite *mnuSprite = [CCMenuItemSprite itemFromNormalSprite:panel selectedSprite:nil disabledSprite:nil target:nil selector:nil];
[menu addChild:mnuSprite];
[menu addChild:mnuLabel];
[menu setPosition:ccp(winSize.width/2, winSize.height/2)];
[self addChild:menu z:1];

Are you sure, you need label UNDERNEATH your sprite? If I understand right, you can just create CCMenuItemSprite instance, then add label to it as a child. smth like:
CCMenuItemSprite *mnuSprite = [CCMenuItemSprite itemFromNormalSprite:panel selectedSprite:nil disabledSprite:nil target:nil selector:nil];
CCLabelBMFont *lblFont = [CCLabelBMFont labelWithString:#"Some text" fntFile:#"arial16.fnt"];
[lblFont setAnchorPoint: ccp(0.f, 0.f)];
[mnuSprite addChild: lblFont];

Related

Cocos2d - Alternative for CCNode userData

I am using CCNode userData property to define whether a touched sprite has had a node built upon it (using Ray Wenderlich's - Tower Defence Tutorial).
The problem I am having is that for every new sprite position I touch and build upon, the previous ones are not retained in the sense that I am unable to sell the building built on it using my sell method.
What is the best way to save data to an individual CCSprite that is selected by touch, and defined by a property through a for loop?
I have read that subclassing CCSprite is an option, or creating a struct for userData etc. I have tried to implement these strategies but have been unsuccessful getting them to work.
touch method with sprite property:
-(void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
for(UITouch *touch in touches){
CGPoint location = [touch locationInView:[touch view]];
location = [[CCDirector sharedDirector] convertToGL:location];
for(CCSprite *tb in self.BuildPositions){
//BuildPositions contains CCSprites from a class defining build positions and contained in a mutable array.
if(CGRectContainsPoint([tb textureRect],[tb convertToNodeSpace:location ])){
_selectedBuildPosition = tb;
[self buildMenuTapped];
}
}
}
}
build menu method:
-(void)buildMenuTapped{
[self removeChild:_buildSelectMenu cleanup:YES];
[self removeChild:_sellBuildingMenu cleanup:YES];
if (_selectedBuildPosition.userData == nil) {
CCMenuItem *buildOption = [CCMenuItemImage itemWithNormalImage:#"building.png" selectedImage:#"building.png" target:self selector: #selector(buildOption)];
buildOption.position = ccpAdd(_selectedBuildPosition.position,ccp(0,40));
_buildSelectMenu = [CCMenu menuWithItems:BuildOption, nil];
_buildSelectMenu.position = CGPointZero;
[self addChild:_buildSelectMenu z:100];
}else{
[self sellBuildingMenu];
}
}
build upon method:
-(void)buildOption{
if([self canBuyBuilding] && !_selectedBuildPosition.userData){
_playerEssence -= kBUILD_COST;
_lvl1BuildNodeInstance = [lvl1BuildNode nodeWithTheGame:self location:_selectedBuildPosition.position];
//method as seen in RW tutorial. Generates a lvl1BuildNode class node within the HelloWorldLayer.
_selectedBuildPosition.userData = (__bridge void*)(_lvl1BuildNodeInstance);
}
}
sell menu method:
-(void)sellBuildingMenu{
[self removeChild:_buildSelectMenu cleanup:YES];
[self removeChild:_sellBuildingMenu cleanup:YES];
CCMenuItem *buildingSell = [CCMenuItemImage itemWithNormalImage:#"sell.png" selectedImage:#"sell.png" target:self selector:#selector(sellBuilding)];
buildingSell.position = ccpAdd(_selectedBuildPosition.position,ccp(40,0));
_sellBuildingMenu = [CCMenu menuWithItems:buildingSell, nil];
_sellBuildingMenu.position = CGPointZero;
[self addChild:_sellBuildingMenu z:100];
}
sell method:
-(void)sellBuilding{
if (_selectedBuildPosition.userData == (__bridge void*)(_lvl1BuildNodeInstance)){
[self removeChild:_lvl1GemNodeInstance cleanup:YES];
[_buildings removeObject:_lvl1BuildNodeInstance];
_playerEssence += kBUILD_COST;
_selectedBuildPosition.userData = nil;
}else{
}
}
Thank you for your time.

How do I pause all actions while fading cclayer then resume gameplay in cocos2d?

I have this:
-(void)fadeBackground
{
ccColor4B color = {0,0,0,255};
CCLayerColor *fadeLayer = [CCLayerColor layerWithColor:color];
[self addChild:fadeLayer z:7];
fadeLayer.opacity = 0;
id fade = [CCFadeTo actionWithDuration:1.0f opacity:200];//200 for light blur
id calBlk = [CCCallBlock actionWithBlock:^{
//show pause screen buttons here
//[self showPauseMenu];
}];
id fadeBack = [CCFadeTo actionWithDuration:2.0f opacity:0];
id sequen = [CCSequence actions:fade, calBlk, fadeBack, nil];
[fadeLayer runAction:sequen];
}
How do I stop the actions while the fadein occurs and resume them when the fadeBack occurs?
[[CCDirector sharedDirector] pause]; & [[CCDirector sharedDirector] resume]; will pause and resume the schedulers and actions throughout all the Sprites/Layers or any other cocos2d Nodes.
If you want to pause/resume a particular CCLayer along with children its containing,
////for pausing
[myLayer pauseSchedulerAndActions];
for(CCNode *child in myLayer.children){
[child pauseSchedulerAndActions];
}
///for resuming
[myLayer resumeSchedulerAndActions];
for(CCNode *child in myLayer.children){
[child resumeSchedulerAndActions];
}
To pause, you can use this call, need to call same for each menu in game.
[self pauseSchedulerAndActions];
[menu pauseSchedulerAndActions];
To resume:
[self resumeSchedulerAndActions];
[menu pauseSchedulerAndActions];

Individual buttons in cocos2d

Most talk about buttons for cocos2d seems to be directed to CCMenu, where CCMenu AFAIK is meant for having a row or column in center of screen.
I need to place buttons randomly on screen and have yet to find a simple out of the box solution for this. I did try CCControlButton but didn't get it to work (CCScale9Sprite spriteWithSpriteFrameName loads incorrectly from sprite atlas).
For now I try to use this. It uses only one button in each CCMenu. So my screen will have lots of CCMenu instances, one for each button.
+(CCMenu*)button:(NSString*)spriteframename at:(const CGPoint)POINT block:(void(^)(id sender))block {
CCSprite* sprite1 = [CCSprite spriteWithSpriteFrameName:spriteframename];
CCSprite* sprite2 = [CCSprite spriteWithSpriteFrameName:spriteframename];
CCMenuItem* menuitem = [CCMenuItemImage itemWithNormalSprite:sprite1 selectedSprite:sprite2 block:block];
CCMenu* menu = [CCMenu menuWithItems:menuitem, nil];
menu.contentSize = sprite1.contentSize;
menu.position = POINT;
return menu;
}
This is a better way which I changed to.
Put this in like init:
CCMenuItem* menuitemRetry = [[self class] buttonWithSpriteframenameOff:#"retry_off.png" on:#"retry_on.png" at:ccp(198, 184) block:^(id sender) {
// Do something
}];
CCMenuItem* menuitemMenu = [[self class] buttonWithSpriteframenameOff:#"menu_off.png" on:#"menu_on.png" at:ccp(362, 184) block:^(id sender) {
// Do something else
}];
CCMenu* menuLow = [CCMenu menuWithItems:menuitemMenu, menuitemRetry, nil];
menuLow.position = CGPointZero;
[self addChild:menuLow];
This also needed
+(CCMenuItem*)buttonWithSpriteframenameOff:(NSString*)spriteframenameOff on:(NSString*)spriteframeOn at:(const CGPoint)POINT block:(void(^)(id sender))block {
CCMenuItem* menuitem = [CCMenuItemImage itemWithNormalSprite:[CCSprite spriteWithSpriteFrameName:spriteframenameOff] selectedSprite:[CCSprite spriteWithSpriteFrameName:spriteframeOn] block:block];
menuitem.position = POINT;
return menuitem;
}

CCMenu child of child selector not firing

I have a ccmenu with a ccmenuitemsprite in a ccmenuitemsprite which has the selector.
I wish for the child of child to be a play button that fires a selector but its not firing.
CCMenu *menu [CCMenu menuWithItems: nil];
CCMenuItem *bg = [CCMenuItemSprite itemFromNormalSprite:[CCSprite spriteWithFile:#"sprite_sheet.png" rect:CGRectMake(0,50,100,100)]
selectedSprite:nil
disabledSprite:nil
target:self
selector:nil];
CCMenuItem *playBtn = [CCMenuItemSprite itemFromNormalSprite:[CCSprite spriteWithFile:#"sprite_sheet.png" rect:CGRectMake(0,0,50,50)]
selectedSprite:[CCSprite spriteWithFile:#"sprite_sheet.png" rect:CGRectMake(50,0,50,50)]
disabledSprite:[CCSprite spriteWithFile:#"sprite_sheet.png" rect:CGRectMake(100,0,50,50)]
target:self
selector:#selector(onPlay:)];
[bg addChild:playBtn];
[menu addChild:bg];
[self addChild:menu];
If you want to pass the name of your images as arguments, please use the following code:
CCMenuItem *playBtn = [CCMenuItemImage itemFromNormalImage:#"image.png"
selectedImage:#"image_selected.png"
disabledImage:#"image_disabled.png"
target:self
selector:#selector(onPlay:)];
The constructor you are using is expecting a CCSprite, not an NSString.
OK, after you edited the answer, I looked more closely, and you have the playBtn as a child of bg. You can't do that. Only the direct children of CCMenu are able to send callbacks:
[menu addChild:playBtn];
I would suggest you do this actually:
CCMenuItem *playBtn = [CCMenuItemSprite itemFromNormalSprite:[CCSprite spriteWithFile:#"sprite_sheet.png" rect:CGRectMake(0,0,50,50)]
selectedSprite:[CCSprite spriteWithFile:#"sprite_sheet.png" rect:CGRectMake(50,0,50,50)]
disabledSprite:[CCSprite spriteWithFile:#"sprite_sheet.png" rect:CGRectMake(100,0,50,50)]
target:self
selector:#selector(onPlay:)];
CCMenu* menu = [CCMenu menuWithItems:playBtn, nil];
CCSprite* bg = [CCSprite spriteWithFile:#"sprite_sheet.png" rect:CGRectMake(0,50,100,100)];
[self addChild:bg];
[self addChild:menu];

how to do a function for a sprite or menu in cocos2d?

I created two CCLayers, one is gamelayer, another is howlayer. The code of gamelayer.m is
-(id)init{
if (self = [super init]) {
CCSprite *gamebg = [CCSprite spriteWithFile:#"bg.png"];
gamebg.anchorPoint = CGPointZero;
[self addChild:gamebg z:0 tag:1];
HowLayer *howLayer = [HowLayer node];
[self addChild:howLayer];
[self schedule:#selector(showthegamecontent:) interval:0.4];
}
return self;
}
the code of howlayer is
-(id)init{
if (self=[super init]) {
CCSprite *howbg = [CCSprite spriteWithFile:#"translucentbg.png"];
howbg.anchorPoint = CGPointZero;
[self addChild:howbg z:5 tag:1];
CCMenuItem *howmenu = [CCMenuItemImage itemFromNormalImage:#"how.png"
selectedImage:#"how.png"
target:self
selector:#selector(startgame:)];
CCMenu *ccMenuhowmenu = [CCMenu menuWithItems:howmenu, nil];
ccMenuhowmenu.position=ccp(517,384);
[self addChild:ccMenuhowmenu z:5 tag:2];
}
return self;
}
-(void)startgame:(id)sender{
[self removeAllChildrenWithCleanup:YES];
}
I want to do function like this:
When I click the menu on howlayer, the Howlayer will be removed (I have done), and then the game starts, calls the selector 'showthegamecontent', so how should I do?
Simple hack in your howlayer:
-(void)startgame:(id)sender{
gameLayer* parent = (gameLayer*) self.parent;
[parent showthegamecontent];
}
but it may leave you with a warning.. But it works..
The implementation without warning is that you have to store a reference to the parent with you init. Which i feel its unnecessary as you only need to reference it once.