I'm having problems using CCMenu with scaled CCMenuItemSprite menu items. I'm trying to scale the menu item sprites differently based on which device the game is being played on (the iPad needs to scale it to about 1.5x, whereas on the iPhone it's about 0.75x)
From what I've read, we can't scale the CCSprite directly, or the CCMenuItemSprite, because when it's added to the CCMenu the touch rectangles aren't updated correctly. I believe that I have to scale the CCMenu to scale the Menu Items.
Whenever I do this my sprites appear to be scaled to the correct sizes, however it also seems to scale the CCMenu position coordinates, but in the opposite direction as what I'd expect. Also once I go over a certain threshold the menu seems to disappear altogether.
Does anyone have any suggestions on how I should be scaling Sprites in a CCMenu?
Thanks in advance.
Buzzrick
Try this Code........
CCMenuItemImage *Btn1 = [CCMenuItemImage itemWithNormalImage:#"button1.png" selectedImage:#"button1_active.png" target:self selector:#selector(button1_click:)];
CCMenuItemImage *Btn2 = [CCMenuItemImage itemWithNormalImage:#"button2.png" selectedImage:#"button2_active.png" target:self selector:#selector(button2_click:)];
CCMenu *Action_menu = [CCMenu menuWithItems:Btn1,Btn2, nil];
[Action_menu setPosition:ccp( 79, 288)];
float delayTime = 0.3f;
for (CCMenuItemFont *each in [Action_menu children])
{
each.scaleX = 0.0f;
each.scaleY = 0.0f;
CCAction *action = [CCSequence actions:
[CCDelayTime actionWithDuration: delayTime],
[CCScaleTo actionWithDuration:0.5F scale:1.0],
nil];
delayTime += 0.2f;
[each runAction: action];
}
[self addChild:Action_menu];
My suggestion? Don't!
Internally CCMenu scaled the menu items whenever you touch them. You'll notice this if you tap and hold an item, it's scaled up (zoomed in). So whatever scaling you apply to menu items is lost at the latest when the menu item gets touched.
And then, as you noticed, scaling affects the touch area of an item. It can lead to items responding to touches outside the item, or not responding to touches depending on zoom level. I also wouldn't scale the CCMenu for the same reasons.
Long story short, if you have to apply scaling to your menu items, write your own menu item code. Possibly by basing it on the CCMenu code and stripping out what you don't need and making your desired changes.
But really the easiest way is to supply the menu item images using the file suffixes -hd, -ipad and -ipadhd and scaled correspondingly. Trying to get this right with the scale property is just painful.
Here's how I resolved it in the end:
Basically I created the menu elements first, THEN I sorted out the positioning/scaling/rotation. This seems to work much better.
This code sample below is where i'm using a single sprite to create two opposing left/right arrow buttons
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:#"ButtonSprites.plist"];
CCSpriteBatchNode *buttonSprites = [CCSpriteBatchNode batchNodeWithFile:#"ButtonSprites.png"];
[self addChild:buttonSprites];
CCSprite *arrowLeftSprite = [CCSprite spriteWithSpriteFrameNameOrFile:#"PageArrow"];
CCSprite *arrowLeftSpriteSelected = [CCSprite spriteWithSpriteFrameNameOrFile:#"PageArrow"];
arrowLeftSpriteSelected.opacity = 128;
CCSprite *arrowRightSprite = [CCSprite spriteWithSpriteFrameNameOrFile:#"PageArrow"];
CCSprite *arrowRightSpriteSelected = [CCSprite spriteWithSpriteFrameNameOrFile:#"PageArrow"];
arrowRightSpriteSelected.opacity = 128;
float buttonWidth = screenSize.width * ButtonWidthPercent;
int contentPixelWidth = arrowLeftSprite.contentSize.width;
float scale = buttonWidth / contentPixelWidth;
CCMenuItemSprite *pageLeftMenu = [CCMenuItemSprite itemFromNormalSprite:arrowLeftSprite selectedSprite:arrowLeftSpriteSelected target:self selector:#selector(buttonPageLeft:)];
CCMenuItemSprite *pageRightMenu = [CCMenuItemSprite itemFromNormalSprite:arrowRightSprite selectedSprite:arrowRightSpriteSelected target:self selector:#selector(buttonPageRight:)];
// First perform the creation
CCMenu *menu = [CCMenu menuWithItems: mainMenu, pageLeftMenu, pageRightMenu, nil];
menu.position = ccp(0, 0);
// THEN deal with layout,rotation, and scaling
pageLeftMenu.scale = scale;
pageLeftMenu.rotation = 180;
pageRightMenu.scale = scale;
float arrowHeight = screenSize.height * 0.2;
pageLeftMenu.position = ccp(screenSize.width * 0.1, arrowHeight);
pageRightMenu.position = ccp(screenSize.width * 0.9, arrowHeight);
[self addChild:menu z:2];
Related
My Cocos2D app utilizes a number of CCMenuItemSprite's for buttons (e.g. back button). When the button is on the left half of a landscape scene, it fails to respond to the touch. The buttons on the right half of the screen work fine. The code to initialize the button is straight forward:
CCSprite *normalSprite = [CCSprite spriteWithFile:#"MenuArrowButtonOblongNormal_iPad.png"];
CCSprite *selectedSprite = [CCSprite spriteWithFile:#"MenuArrowButtonOblongSelected_iPad.png"];
CCMenuItemSprite *backButton = [CCMenuItemSprite itemFromNormalSprite:normalSprite
selectedSprite:selectedSprite
target:self
selector:#selector(returnToOptionsMenu)];
if (screenSizeInPixels.width == 1136.0f) {
[backButton setScaleX:0.9375f];
[backButton setScaleY:0.8322f];
buttonHeight = 0.9f;
}
CCMenu *sceneSelectMenu;
sceneSelectMenu = [CCMenu menuWithItems: backButton,nil];
[sceneSelectMenu alignItemsVerticallyWithPadding:screenSize.height * 0.059f];
[sceneSelectMenu setPosition:ccp(screenSize.width*0.15,
screenSize.height * buttonHeight)];
[self addChild:sceneSelectMenu];
// And finally the back button label
CCLabelTTF *backButtonLabel;
backButtonLabel = [CCLabelTTF labelWithString:NSLocalizedString(#"Back", #"Enables user to exit the current screen and view the previous screen")
fontName:#"Marker Felt"
fontSize:scaledFontSize*1.3];
backButtonLabel.color = ccc3(255,255,255);
[backButtonLabel setAnchorPoint:ccp(0.5,0.5)];
backButtonLabel.position = ccp(screenSize.width * (0.14+labelOffset),
screenSize.height * labelHeight);
[self addChild:backButtonLabel z:2];
This is an older app that utilized Cocos2D version 1.1-RC0. I have made several updates to this code based on the suggested changes in iPhone 6 and 6+ update patch for cocos2d 2.1. But these primarily address resolution/scale factor issues.
If no one has seen this issue, can you suggest where in the cocos2D I might investigate to determine why the touches are not being detected/acted upon?
I've made a CCLayer that holds CCSprite and two CCLabelBMFont's. My goal is to create a customized "button" which will scale down when pressed. I've ran into problems with touch and scaling of this layer.
First is the touch, I can't touch the layer bounding box accurately even if I convert the touch like this:
CGPoint currentTouchLocation = [self convertTouchToNodeSpace:touch];
Touch is handled like this:
// Touching shop item?
if(CGRectContainsPoint([self boundingBox], currentTouchLocation)) {
NSLog(#"Pressing item");
mShopItemPushed = true;
return true;
}
return false;
Seems like there is no realistic size boundingBox for a CCLayer with it's contents by default so I figure I need to overwrite one based on the CCLayer contents? Any ideas how I can do this correctly?
Second problem is the scaling of this CCLayer based "button". If I get a touch handling to work somehow, scaling the layer down by half causes the scaled layer to move off tens of pixels from the original position. There are no anchors set but still moves the layer quite a bit to the side and up when scaling. How can I prevent this behavior?
Here is some code of the CCLayer based button:
+(id) shopItem:(NSString*)fileName : (CGPoint)position : (NSString*)itemName : (int)itemPrice
{
return [[[self alloc] initWithShopItemData:fileName:position:itemName:itemPrice] autorelease];
}
-(id) initWithShopItemData:(NSString*)fileName : (CGPoint)position : (NSString*)itemName : (int)itemPrice
{
self = [super init];
[self setPosition:position];
mShopItemPushed = false;
mPicture = [CCSprite spriteWithSpriteFrameName:fileName];
[mPicture setPosition:CGPointMake(position.x - (3.0f * [DeviceSpecific cellSize]), position.y)];
[self addChild:mPicture z:1];
// Make price string
NSString* price = [NSString stringWithFormat:#"%d", itemPrice];
mItemPrice = [CCLabelBMFont labelWithString:price fntFile:[DeviceSpecific scoreAndCoinFont]];
[mItemPrice setScale:0.5f];
[mItemPrice setAnchorPoint:CGPointMake(1.0f, 0.5f)];
[mItemPrice setPosition:CGPointMake(position.x + (3.5f * [DeviceSpecific cellSize]), position.y)];
[self addChild:mItemPrice z:1];
mItemName = [CCLabelBMFont labelWithString:itemName fntFile:[DeviceSpecific scoreAndCoinFont]];
[mItemName setScale:0.5f];
[mItemName setAnchorPoint:CGPointMake(0.0f, 0.5f)];
[mItemName setPosition:CGPointMake(mPicture.position.x + [DeviceSpecific cellSize], mPicture.position.y)];
[self addChild:mItemName z:1];
self.isTouchEnabled = YES;
return self;
}
The [DeviceSpecific cellSize] is just a measuring unit to keep the distances correct on different devices.
I solved this by overwriting the boundingBox -function with a rect based on the outer limits of the items in this layer. Scaling problem remained so I just made another indicator for received touches.
how could I tweak CCMenuItemSprite to support only one sprite?
Currently I have:
[CCMenuItemSprite itemWithNormalSprite:one selectedSprite:selectedOne]
But would like to have:
[CCMenuItemSprite itemWithNormalSprite:one]
EDIT: I want to modify CCMenuItem to work only with one CCSprite and not two. So I need to change also the internal methods.
You can just use the same (normal) sprite as the selected sprite. When clicked, the button will then do nothing.
You could just use
[CCMenuItemSprite itemWithNormalSprite:one selectedSprite:one]
this way, nothing would happen when you select the sprite
try this, just change colour of seleted sprite.
CCSprite *sprite1 = [CCSprite spriteWithFile:#"Button.png"];
CCSprite * sprite2 = [CCSprite spriteWithFile:#"Button.png"];
sprite2.color = ccc3(128, 128, 128);
CCMenuItemImage *itemEasyLevelImage = [CCMenuItemImage itemWithNormalSprite:sprite1
selectedSprite:sprite2
block:^(id sender){}];
Using CCMenu I have create Two Buttons Up and Down Here is the code
CCSprite *normlUp = [CCSprite spriteWithFile:#"Up.png"];
CCSprite *selectedUp = [CCSprite spriteWithFile:#"Up.png"];
selectedUp.color = ccGREEN;
CCMenuItemSprite *up = [CCMenuItemSprite itemFromNormalSprite:normlUp selectedSprite:selectedUp target:self selector:#selector(upItemTouched)];
up.position = CGPointMake(-220, -115);
CCSprite *normlDown = [CCSprite spriteWithFile:#"Down.jpeg"];
CCSprite *selectedDown = [CCSprite spriteWithFile:#"Down.jpeg"];
selectedDown.color = ccGREEN;
CCMenuItemSprite *down = [CCMenuItemSprite itemFromNormalSprite:normlDown selectedSprite:selectedDown target:self selector:#selector(downItemTouched)];
down.position = CGPointMake(-220,-140 );
CCMenu *upDown = [CCMenu menuWithItems:up,down,nil];
[self addChild:upDown z:4];
How to write upItemTouched and downItemTouched Methods
Also the sprite should move smoothly on the screen
I am New to cocos2d so please accept my simple questions........
Use CCMenuItemSprite assigning adding selector to the sprite, so when you touch down/up sprite that selector method will be called.
so, when "up" is touched, set one boolean to true and when "down" is touched, set another boolean to true.
Now in update/tick method check which boolean in true and then move the sprite.
When done moving, in touchesEnded method just set those boolean to false.
So I'm making a game, and in this game I need to have a certain sprite to appear multiple times.
It's simply an image, with two buttons. One button underneath the image, and one above.
I am using Cocos2d, so any mention of sprite will be the CCSprite class. And the image is actually just a line.
Is there an easy way to implement something like this? I don't want to have to make a separate sprite for the image, and then add each button. Is there a way I can do this all in one sprite?
I'm assuming that I'll probably have to manually add everything (create a method that will create an image and position the buttons relative to the image), but I'm hoping I'm wrong and there is an easier/more efficient way of doing this.
Thanks!
I think you are looking for CCMenuItem and CCMenu
CCSprite *enabledSprite = [CCSprite spriteWithFile:#"myButtonSprite.png"];
CCSprite *selectedSprite = [CCSprite spriteWithFile:#"myButtonSprite.png"];
CCSprite *disabledSprite = [CCSprite spriteWithFile:#"myButtonSprite.png"];
CCMenuItemSprite *item [[[CCMenuItem alloc] initWithNormalSprite:enabledSprite
selectedSprite:selectedSprite
disabledSprite:disabledSprite
target:delegate
selector:selector] autorelease];
item.position = ccp(240, 160);
CCMenu *menu = [CCMenu menuWithItems:item, nil];
menu.position = ccp(0, 0);
[self addChild:menu];