您的位置:首页 > 移动开发 > Cocos引擎

使用Cocos2d-x中的CCMenuItemToggle制作商店

2013-11-12 18:10 423 查看
最近一直在和同学用Cocos2d-x做一款手机游戏,期间做过一个商店的功能,在此写一篇关于使用CCMenuItemToggle来实现商店标签功能。

首先把效果发出来,资源是用的《Banana Kong》的图片,上面的字是自己加的:(W == Weapon,H == Hat, I == Inventory, S == Skill)



达到以下几个效果:

1. 进入商店默认“W标签“是选中状态

2. 点击其他的标签后,前一个标签自动还原

3. 点击一个标签,弹出属于这个标签的元素

刚开始做的时候遇到了很多问题,想过用CCMenuItem,但是CCMenuitem的按下和弹起操作时一次性完成的,并且已经封装,网上有继承CCMenuItem重写的方法,感觉比较复杂。之后想过用CCSprite直接写精灵点击事件,结果也是遇到了一些麻烦,最终用CCMenuItemToggle写了出来,如果大家有什么更好的办法写出这个效果,欢迎拍砖!

然后我们来看创建一个CCMenuItemToggle需要的步骤:

CCMenuItemImage* toggleNormal = CCMenuItemImage::create("toggleNormal", "toggleSelect"); // 未点击时的图片
CCMenuItemImage* toggleSelect = CCMenuItemImage::create("toggleSelect", "toggleNormal"); // 点击后的图片
CCMenuItemToggle* myToggle = CCMenuItemToggle::createWithTarget(this,selector,toggleNormal,toggleSelect,NULL);// 使用以上两个图片菜单创建一个开关菜单


这样就创建了一个开关菜单(Toggle == "开关")。当然最后还要传入CCMenu中。

这里又有几点需要讲的:

1. 从这三句代码可以看到如果要创建CCMenuItemToggle的话首先要创建多个CCMenuItemImage,其实也可以是其他菜单项,我们这里只讲用图片创建。想要看其他创建方式以及想要深入研究的可以看源码,这里不赘述。

2. CCMenuItemToggle::createWithTarget(this, selector, imgNormal, imgSelect, NULL); 从这一句最后的参数NULL可以看出还可以继续添加菜单,创建出多选项开关菜单。同样,我们只需要两个图片。
3. 参数selector是回调函数。

如果我们就这样实现标签效果的话,意味着我们将写四遍上述代码,还要控制他们的位置等等,这样我们就理所当然的想到了将其封装成一个函数。我们定义这样一个函数,用来专门创建开关按钮。

CCMenuItemToggle* HShop::createToggle(SEL_MenuHandler selector, char * fileNameNormal, char * fileNameSelect)
{
CCMenuItemImage* imgNormal = CCMenuItemImage::create(fileNameNormal, fileNameSelect);
CCMenuItemImage* imgSelect = CCMenuItemImage::create(fileNameSelect, fileNameNormal);
CCMenuItemToggle* imgToggle = CCMenuItemToggle::createWithTarget(this, selector, imgNormal, imgSelect, NULL);
return imgToggle;
}


于是我们就可以这样创建标签:

wToggle = HShop::createToggle(menu_selector(HShop::toggleIsPressed), fileNameNormal, fileNameSelect);// HShop是商店类

hToggle = HShop::createToggle(menu_selector(HShop::toggleIsPressed), fileNameNormal, fileNameSelect);

iToggle = HShop::createToggle(menu_selector(HShop::toggleIsPressed), fileNameNormal, fileNameSelect);

sToggle = HShop::createToggle(menu_selector(HShop::toggleIsPressed), fileNameNormal, fileNameSelect);

但是这样依然比较麻烦,这四个标签的位置是有规律的,如果我们将他们使用的图片的文件名改得有规律一点,就可以用一个for循环控制。并且将toggle改为数组形式

于是修改后的代码如下:

// 创建商店里的标签
for(int i = 0; i < AllToggle; i++)
{
char fileNameNormal[50];	// 未选中图片的文件名
char fileNameSelect[50];	// 选中图片的文件名
sprintf(fileNameNormal, "Toggle_Normal%d.png", i);
sprintf(fileNameSelect, "Toggle_Select%d.png", i);
toggle[i] = HShop::createToggle(menu_selector(HShop::toggleIsPressed), fileNameNormal, fileNameSelect);
toggle[i]->setTag(i);	// 为每个标签设置Tag值
float padding = 4;		// 标签之间的间隔
toggle[i]->setPosition(ccp(48 + toggle[0]->getContentSize().width/2, (visibleSize.height/2 + 3 * (padding + toggle[0]->getContentSize().height)/2) - (toggle[0]->getContentSize().height + padding) * i));	// 标签位置,这个大家自己调一下,因为visibleSize是为了适应分辨率专写的
double f = CCDirector::sharedDirector()->getContentScaleFactor();	// 调整一下大小,这个大家看情况
}
toggle[weaponToggle]->setSelectedIndex(1);	// 我们刚进入的时候武器标签是被选中的
toggle[weaponToggle]->setEnabled(false);	// 选中的标签不能再点击
CCMenu *toggleMenu = CCMenu::create(toggle[0], toggle[1], toggle[2], toggle[3], NULL);	// 加入到CCMenu对象中
toggleMenu->setAnchorPoint(ccp(0, 0));
toggleMenu->setPosition(ccp(origin.x, origin.y - 1));
this->addChild(toggleMenu, 0);


1. 这里我把需要的文件都改为Toggle_NormalX.png这种形式的(X代表数字),这样就可以用for循环控制载入相应图片。

2. 使用setSelectedIndex(int n)函数可以把标签设置为需要的状态,n对应的即是函数CCMenuItemToggle* imgToggle = CCMenuItemToggle::createWithTarget(this, selector, imgNormal, imgSelect, NULL);中从第三个参数到之后的各种状态

接下来我们就可以点击各种标签了,并且被点击后的标签不能再被点击(实现选中状态),但是现在呈现的状态确实这样的


这样明显是不对的,应该点击了”I标签“后,”W标签“应该恢复,于是剩下的操作我们就在回调函数toggleIsPressed()中进行操作,先贴代码:



void HShop::toggleIsPressed(CCObject * menuItem)
{
CCMenuItemToggle* tmp = (CCMenuItemToggle*)menuItem;

switch(tmp->getTag())
{
case weaponToggle:
toggle[weaponToggle]->setEnabled(false);
toggle[hatToggle]->setSelectedIndex(0);			toggle[hatToggle]->setEnabled(true);
toggle[inventoryToggle]->setSelectedIndex(0);	toggle[inventoryToggle]->setEnabled(true);
toggle[skillToggle]->setSelectedIndex(0);		toggle[skillToggle]->setEnabled(true);

break;
case hatToggle:
toggle[hatToggle]->setEnabled(false);
toggle[weaponToggle]->setSelectedIndex(0);		toggle[weaponToggle]->setEnabled(true);
toggle[inventoryToggle]->setSelectedIndex(0);	toggle[inventoryToggle]->setEnabled(true);
toggle[skillToggle]->setSelectedIndex(0);		toggle[skillToggle]->setEnabled(true);

break;
case inventoryToggle:
toggle[inventoryToggle]->setEnabled(false);
toggle[weaponToggle]->setSelectedIndex(0);		toggle[weaponToggle]->setEnabled(true);
toggle[hatToggle]->setSelectedIndex(0);			toggle[hatToggle]->setEnabled(true);
toggle[skillToggle]->setSelectedIndex(0);		toggle[skillToggle]->setEnabled(true);
mc->createInventoryCard();
CCScrollView* tem= (CCScrollView*)this->getChildByTag(1);
tem->setContentOffset(ccp(0, -(containLayer->getContentSize().height - MYSCROLLVIEW_HEIGHT)), true);
break;
case skillToggle:
toggle[skillToggle]->setEnabled(false);
toggle[weaponToggle]->setSelectedIndex(0);		toggle[weaponToggle]->setEnabled(true);
toggle[hatToggle]->setSelectedIndex(0);			toggle[hatToggle]->setEnabled(true);
toggle[inventoryToggle]->setSelectedIndex(0);	toggle[inventoryToggle]->setEnabled(true);

break;
default:
break;
}
}


这样,用一个switch语句分别处理这四个标签被按下后的操作,他们的操作都可以总结为:

1. 被点击后不能再进行点击 toggle[XXX]->setEnabled(false);

2. 之前被点击的标签应该复原 toggle[XXX]->setSelectedIndex(0);

其实第二点是可以优化的,我的代码写得非常冗余——点击一个菜单,要复原其他三个菜单。之前我想过用一些方法解决,但是都出了一些莫名其妙的问题,具体我猜是回调函数里这个CCObject * menuItem参数的问题,我使用CCMenuItemToggle* tmp来操作被点击的Toggle总是出问题,如果有哪位大侠解决了的话希望不吝赐教!

这样就实现了我们的标签功能,差不多就这样吧,欢迎拍砖!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: