cocos2dx 3.3 如何为创建一个按钮

2015年02月10日 11:24 0 点赞 0 评论 更新于 2025-11-21 16:09

在使用 Cocos2d-x 开发游戏时,按钮往往是不可或缺的元素,例如游戏开始时的菜单选择界面就会用到按钮。本教程将逐步指导你如何使用 Cocos2d-x 创建不同类型的按钮,包括简单按钮、开关按钮和单选按钮。阅读本教程前,假设你已经掌握使用 Cocos2d-x 制作简单游戏的技能或具备同等相关经验。

一、使用 Cocos2d-x 菜单系统创建按钮的优势

最初,我尝试在 Cocos2d-x 中添加按钮时,考虑创建一个精灵(sprite)来代表按钮,并检测其何时被按下。这种方法可行,但 Cocos2d-x 提供了更简单的方式——使用菜单系统。

Cocos2d-x 的菜单系统包含一个 Menu 对象,其中又包含一系列的 MenuItemMenuItem 可以是文本或图片,菜单系统还具备一些实用的逻辑,如排列菜单项、高亮显示被按下的菜单项、开关菜单项等。接下来,我们将实践如何使用 Cocos2d-x 的方式创建一个简单的按钮。

二、创建一个简单的按钮

1. 准备工作

打开 Visual Studio,创建一个新的工程并命名为 Buttons。你需要准备一些按钮的图片,可以自行创建或下载已有的图片,将这些图片拖到 resource 文件夹下。

2. 代码实现

2.1 添加成员变量

打开 Classes 分组下的 HelloWorldScene.h 文件,在 HelloWorld 类中添加一个成员变量:

LabelTTF* label;

2.2 在 init 方法中添加代码

HelloWorldScene.cpp 文件的 init 方法中添加以下代码:

// 创建一个用于显示的标签
label = LabelTTF::create("Last button: None", "Marker Felt", 32);
label->setPosition(Point(visibleSize.width / 2 + origin.x, origin.y + visibleSize.height - 80));
label->setHorizontalAlignment(TextHAlignment::CENTER);
this->addChild(label);

// 创建按钮的标准方法
auto starMenuItem = MenuItemImage::create(
"ButtonStar.png",
"ButtonStarSel.png",
CC_CALLBACK_1(HelloWorld::starMenuCallback, this)
);
starMenuItem->setPosition(Point(160, 220));
auto starMenu = Menu::create(starMenuItem, NULL);
starMenu->setPosition(Point::ZERO);
this->addChild(starMenu, 1);

首先,为了方便调试,我们创建了一个 label。这里使用了新的创建函数,可指定 label 的大小和文字对齐方式。将 label 的位置设置在窗口中上方,并将文本设置为居中对齐,这在处理不同对齐方式的文本时是常用技术。

接下来的代码用于创建按钮。使用 MenuItemImage 类创建一个菜单项,并为按钮指定未选中和选中时显示的图片(即单击和未单击时显示的图片)。创建完菜单项后,为按钮的点击事件指定一个回调函数(后续会给出该函数代码)。最后,创建一个 Menu 来包含这个按钮(若有多个按钮,以 NULL 结尾)。

注意,我们在原点位置创建按钮,这里指定的是菜单的中心点位置。然后,指定菜单项相对于菜单位置的偏移量(160,220),这样菜单项在屏幕上会显示在(160,220)的位置。因为菜单项的 position 是相对于菜单的中心点,将菜单的中心点(锚点)设置为(0, 0),与屏幕坐标原点重合后,为每个菜单项指定坐标点就更方便。

2.3 添加按钮回调函数

init 方法后面添加按钮回调函数:

void HelloWorld::starMenuCallback(Object* pSender)
{
label->setString("Last button: * ");
}

3. 编译运行

编译并运行程序,你将看到相应的运行结果。

三、创建开关按钮

1. 开关按钮简介

开关按钮是游戏中常用的按钮类型,一次仅显示一张图片,单击时会切换到另一张图片。可用于制作控制面板的可见性控制器,以充分利用设备有限的屏幕空间。

2. 代码实现

2.1 添加成员变量

HelloWorldScene.h 中添加两个成员变量:

MenuItemImage* _plusItem;
MenuItemImage* _minusItem;

2.2 添加开关按钮代码

在为场景添加 StartMenu 之后,添加以下代码:

_plusItem = MenuItemImage::create("ButtonPlus.png", "ButtonPlusSel.png");
_minusItem = MenuItemImage::create("ButtonMinus.png", "ButtonMinusSel.png");
MenuItemToggle* toggleItem = MenuItemToggle::createWithCallback(
CC_CALLBACK_1(HelloWorld::plusMinusButtonCallback, this),
_plusItem,
_minusItem,
NULL
);
auto toggleMenu = Menu::create(toggleItem, NULL);
toggleMenu->setPosition(Point(160, 290));
this->addChild(toggleMenu, 1);

首先,像之前创建简单按钮一样,创建两个 MenuItemImage。不同的是,将它们添加到 MenuItemToggle 中,该类会管理当前应显示的菜单项,并在开关元素之间进行切换。

注意,创建 MenuItemImage 时未设置回调函数(可将其设为 NULL),而是为 MenuItemToggle 类设置了回调函数。这样代码逻辑更清晰,当 MenuItemImageMenuItemToggle 中时,MenuItemImage 上的选择器不会被调用,只有 MenuItemToggle 的选择器会被调用。

2.3 实现回调函数

init 方法后面添加回调函数:

void HelloWorld::plusMinusButtonCallback(Object* pSender)
{
MenuItemToggle* toggleItem = (CCMenuItemToggle*)pSender;
if (toggleItem->selectedItem() == _plusItem) {
label->setString("Visible button: +");
} else if (toggleItem->selectedItem() == _minusItem) {
label->setString("Visible button: -");
}
}

MenuItemToggle 中的 selectedItem() 方法可告知我们当前哪个子菜单项可见(注意,当前可见的不等于被单击的)。

3. 编译运行

编译并运行程序,查看运行结果。

四、创建单选按钮

1. 单选按钮实现背景

Cocos2d-x 的源代码中没有直接实现单选按钮,因此我们需要自行实现。本教程使用我自己编写的单选按钮实现。

2. 代码实现

2.1 下载并添加文件

下载 RadioMenu.hRadioMenu.cpp,将它们拖到 Classes 文件夹下。在 HelloWorldScene.cpp 的顶部添加以下代码:

#include "RadioMenu.h"

2.2 添加单选按钮代码

init 方法后面,紧跟添加开关按钮的代码,添加以下代码:

auto* menuItem1 = MenuItemImage::create(
"Button1.png",
"Button1Sel.png",
this,
menu_selector(HelloWorld::but1Callback)
);
auto* menuItem2 = MenuItemImage::create(
"Button2.png",
"Button2Sel.png",
this,
menu_selector(HelloWorld::but2Callback)
);
auto* menuItem3 = MenuItemImage::create(
"Button3.png",
"Button3Sel.png",
this,
menu_selector(HelloWorld::but3Callback)
);
auto* radioMenu = RadioMenu::create(menuItem1, menuItem2, menuItem3, NULL);
radioMenu->setPosition(Point(220, 360));
radioMenu->alignItemsHorizontally();
radioMenu->setSelectedItem_(menuItem1);
menuItem1->selected();
this->addChild(radioMenu, 10);

首先,像之前一样创建 MenuItemImage,但将它们添加到 RadioMenu 类中,该类确保一次只有一个菜单项被选中。这里设置默认情况下第一个菜单项被选中。

新的知识点是,利用 Cocos2d-x 的布局功能,调用 alignItemsHorizontally() 方法水平对齐菜单中的所有菜单项。注意,菜单项是相对于菜单的中心点布局的,因此无需将菜单的中心点设置为(0,0),而是将菜单往中间靠右挪动一些,以确保菜单项完整显示。

2.3 添加回调函数

void HelloWorld::but1Callback(Object* pSender)
{
label->setString("Last button: button1 ");
}
void HelloWorld::but2Callback(Object* pSender)
{
label->setString("Last button: button2 ");
}
void HelloWorld::but3Callback(Object* pSender)
{
label->setString("Last button: button3 ");
}

3. 编译运行

编译并运行程序,查看运行结果。

五、菜单系统背后的原理

查看菜单系统的实现,会发现所有菜单项都是 Node 的子类,而 MenuLayer 的子类。根据 Cocos2d-x 最佳实践,应尽量减小层次结构,因此建议将尽可能多的菜单项放到一个菜单中。由于 Layer 派生自 Node,它可以运行动作,即可以对 Menu 执行动作。

六、总结

本教程提供了创建不同类型按钮的完整源代码,希望对你有所帮助。如果你在使用 Cocos2d-x 的按钮时有任何好的建议或想法,欢迎分享!

作者信息

boke

boke

共发布了 3994 篇文章