Cocos2dx 3.X 中CC_CALLBACK_0 1 2 3理解

本文详细介绍了C++标准库中的std::function,包括如何保存和调用自由函数、lambda表达式、成员函数,以及bind的使用方法。

c++ 11 基础 :

    std::function

        类模版 std::function是一种通用、多态的函数封装。std::function的实例可以对任何可以调用的目标进行存储、复制、和调用操作,这些目标包括函数、lambda表达式、绑定表达式、以及其它函数对象等。

用法示例:

①保存自由函数

?
1
2
3
4
5
6
7
8
void  printA( int  a)
{
     cout<<a<<endl;
}
 
  std::function< void ( int  a)> func;
  func = printA;
  func(2);

运行输出: 2

②保存lambda表达式

?
1
2
std::function< void ()> func_1 = [](){cout<< "hello world" <<endl;};
     func_1();

运行输出:hello world

③保存成员函数

?
1
2
3
4
5
6
7
8
9
10
struct  Foo {
     Foo( int  num) : num_(num) {}
     void  print_add( int  i)  const  { cout << num_+i <<  '\n' ; }
     int  num_;
};
 
  // 保存成员函数
     std::function< void ( const  Foo&,  int )> f_add_display = &Foo::print_add;
     Foo foo(2);
     f_add_display(foo, 1);

    运行输出: 3

    bind        bind是一组用于函数绑定的模板。在对某个函数进行绑定时,可以指定部分参数或全部参数,也可以不指定任何参数,还可以调整各个参数间的顺序。对于未指定的参 数,可以使用占位符_1、_2、_3来表示。_1表示绑定后的函数的第1个参数,_2表示绑定后的函数的第2个参数,其他依次类推。

下面通过程序例子了解一下用法:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#include <iostream>
using  namespace  std;
class  A
{
public :
     void  fun_3( int  k, int  m)
     {
         cout<<k<< " " <<m<<endl;
     }
};
 
void  fun( int  x, int  y, int  z)
{
     cout<<x<< "  " <<y<< "  " <<z<<endl;
}
 
void  fun_2( int  &a, int  &b)
{
     a++;
     b++;
     cout<<a<< "  " <<b<<endl;
}
 
int  main( int  argc,  const  char  * argv[])
{
     auto  f1 = bind(fun,1,2,3);  //表示绑定函数 fun 的第一,二,三个参数值为: 1 2 3
     f1();  //print:1  2  3
     
     auto  f2 = bind(fun, placeholders::_1,placeholders::_2,3);
     //表示绑定函数 fun 的第三个参数为 3,而fun 的第一,二个参数分别有调用 f2 的第一,二个参数指定
     f2(1,2); //print:1  2  3
     
     auto  f3 = bind(fun,placeholders::_2,placeholders::_1,3);
     //表示绑定函数 fun 的第三个参数为 3,而fun 的第一,二个参数分别有调用 f3 的第二,一个参数指定
     //注意: f2  和  f3 的区别。
     f3(1,2); //print:2  1  3
     
     
     int  n = 2;
     int  m = 3;
     
     auto  f4 = bind(fun_2, n,placeholders::_1);
     f4(m);  //print:3  4
 
     cout<<m<<endl; //print:4  说明:bind对于不事先绑定的参数,通过std::placeholders传递的参数是通过引用传递的
     cout<<n<<endl; //print:2  说明:bind对于预先绑定的函数参数是通过值传递的
     
     
     A a;
     auto  f5 = bind(&A::fun_3, a,placeholders::_1,placeholders::_2);
     f5(10,20); //print:10 20
     
     std::function< void ( int , int )> fc = std::bind(&A::fun_3, a,std::placeholders::_1,std::placeholders::_2);
     fc(10,20); //print:10 20
     
     return  0;
}

    CC_CALLBACK

        一、通过 HelloWorldScene 中的 closeItem 开始

在cocos2d-x 2.x 版本中:

?
1
2
3
4
5
CCMenuItemImage *pCloseItem = CCMenuItemImage::create(
                                         "CloseNormal.png" ,
                                         "CloseSelected.png" ,
                                         this ,
                                         menu_selector(HelloWorld::menuCloseCallback));

在cocos2d-x 3.0 版本中:

?
1
2
3
4
auto  closeItem = MenuItemImage::create(
                                            "CloseNormal.png" ,
                                            "CloseSelected.png" ,
                                            CC_CALLBACK_1(HelloWorld::menuCloseCallback,  this ));


?
1
2
3
4
5
6
7
8
void  HelloWorld::menuCloseCallback(Object* pSender)
{
     Director::getInstance()->end();
 
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
     exit (0);
#endif
}

注意到在3.0版本中使用到 CC_CALLBACK_1 这样一个宏定义。

?
1
2
3
4
5
// new callbacks based on C++11
#define CC_CALLBACK_0(__selector__,__target__, ...) std::bind(&__selector__,__target__, ##__VA_ARGS__)
#define CC_CALLBACK_1(__selector__,__target__, ...) std::bind(&__selector__,__target__, std::placeholders::_1, ##__VA_ARGS__)
#define CC_CALCC_CALLBACK_1(HelloWorld::menuCloseCallback,this)LBACK_2(__selector__,__target__, ...) std::bind(&__selector__,__target__, std::placeholders::_1, std::placeholders::_2, ##__VA_ARGS__)
#define CC_CALLBACK_3(__selector__,__target__, ...) std::bind(&__selector__,__target__, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3 ##__VA_ARGS__)

这里主要注意两点:一是 std::bind,二是##_VA_ARGS_; ##_VA_ARGS_是可变参数宏

原来还有 CC_CALLBACK_0 1 2 3;而其中又有什么区别呢?

1、首先我们看看3.0版本中MenuItemImage的create方法:

?
1
MenuItemImage * MenuItemImage::create( const  std::string& normalImage,  const  std::string& selectedImage,  const  ccMenuCallback& callback)

其中的回调参数是 ccMenuCallback 

?
1
typedef  std::function< void (Object*)> ccMenuCallback

来这里使用到了 C++ 中的 function 语法。

注意到 在 CC_CALLBACK_  的宏定义的中使用到的是 C++ 的 bind 语法,怎么不一致了呢? -- 见下面第四点 function


2、看回 CC_CALLBACK_  的宏定义

原来 CC_CALLBACK_  的宏定义中后面的 0 1 2 3分别表示的是 不事先指定回调函数参数的个数。

例如说 CC_CALLBACK_ 1 表示的是,回调函数中不事先指定参数是一个,而事先指定的回调函数的参数 可以任意多个

而且要注意到其中 不指定回调函数参数  和  指定回调函数参数  的顺序,注意不事先指定的在前,事先指定的在后

下面通过例子说明这一点:

假设回调函数:

?
1
2
// a selector callback
     void  menuCloseCallback(Object* pSender, int  a, int  b);
?
1
2
3
4
5
6
7
8
9
void  HelloWorld::menuCloseCallback(Object* pSender, int  a, int  b)
{
     std::cout<<a<< "  " <<b<<std::endl;
     Director::getInstance()->end();
 
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
     exit (0);
#endif
}

注意到在回调函数中输出 a b

?
1
2
3
4
auto  closeItem = MenuItemImage::create(
                                            "CloseNormal.png" ,
                                            "CloseSelected.png" ,
                                            CC_CALLBACK_1(HelloWorld::menuCloseCallback, this ,1,2));


注意中其中 指定了两个参数 1 2 

运行,在 点击closeItem  的时候,就会输出这两个事先指定的参数 1  2。

那么,不事先指定的参数是在什么时候传入的呢?

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void  MenuItem::activate()
{
     if  (_enabled)
     {
         if ( _callback )
         {
             _callback( this );
         }
         
         if  (kScriptTypeNone != _scriptType)
         {
             BasicScriptData data( this );
             ScriptEvent scriptEvent(kMenuClickedEvent,&data);
             ScriptEngineManager::getInstance()->getScriptEngine()->sendEvent(&scriptEvent);
         }
     }
}

    注意到其中的  _callback(this);  对了,这个时候就传入了 这个不事先指定的回调函数参数。

这样,closeItem 的回调函数的 void HelloWorld::menuCloseCallback(Object* pSender,int a,int b) 的三个参数都知道了。

第一个 不事先指定,在menu item调用 activate 的时候,_callback(this) 传入,this 也即是这个 menu item;第二、三个参数是事先指定的 1,2。


已经知道  CC_CALLBACK_  的宏定义是 std::bind 那么我们可以直接使用std::bind。

如下:

?
1
2
3
4
auto  closeItem = MenuItemImage::create(
                                            "CloseNormal.png" ,
                                            "CloseSelected.png" ,
                                            std::bind(&HelloWorld::menuCloseCallback,  this ,std::placeholders::_1,1,2));
<think>我们正在处理一个Cocos2d-x项目从3.15.1升级到3.17.2的请求。根据引用[1]的内容,从2.x升级到3.x是一个巨大的升级,但我们现在是从3.15.13.17.2,属于同一大版本内的升级,因此变化相对较小。不过,我们仍需谨慎。 根据引用[1]的建议,升级步骤包括: 1. 备份项目。 2. 下载新引擎(3.17.2)。 3. 查看官方文档和发布说明(特别是3.15.13.17.2之间的版本更新日志)。 4. 建议创建一个新的3.17.2项目,然后将旧代码迁移过去,而不是直接替换引擎。 具体步骤: 步骤1:备份当前项目 这是非常重要的,以防升级过程中出现问题。 步骤2:下载Cocos2d-x 3.17.2引擎 从Cocos2d-x的官方网站或GitHub仓库下载3.17.2版本。 步骤3:创建新的3.17.2项目 使用Cocos2d-x 3.17.2提供的命令行工具创建一个新的项目。例如: ``` cocos new MyNewProject -p com.mycompany.mygame -l cpp -d /path/to/project ``` 步骤4:迁移代码和资源 将旧项目(3.15.1)中的以下内容迁移到新项目(3.17.2)中: - Classes目录:包含所有C++源代码。 - Resources目录:包含所有资源(图片、音频、配置文件等)。 - 第三方库(如果有):需要将旧项目中使用的第三方库复制到新项目的相应位置,并更新新项目的配置文件(如CMakeLists.txt或proj.android中的build.gradle)以包含这些库。 步骤5:更新项目配置 比较新旧项目的配置文件,特别是: - 对于Android平台:比较Android.mk、Application.mk、build.gradle、proguard-rules.pro等。 - 对于iOS平台:比较xcodeproj项目设置。 - 对于其他平台(如Windows、macOS)的工程文件。 步骤6:解决API变更问题 由于是同一大版本内的升级,API变更可能不多,但仍需注意。查阅3.15.13.17.2的版本更新日志,查看是否有不兼容的修改。例如,引用[3]中展示了一段代码,其中使用了`#ifdef USING_SHADER`,这可能是特定版本中的宏定义,需要检查新版本中是否还有这个宏或者是否有替代方案。 步骤7:编译和测试 分别在不同平台上编译和测试项目,确保功能正常。 步骤8:处理编译错误和警告 由于引擎升级,可能会遇到一些编译错误或警告。根据错误信息进行修改。常见的可能包括: - 头文件路径变化。 - 被弃用的函数或类:需要替换为新的API。 - 宏定义变更:如引用[3]中的`USING_SHADER`宏,需要确认在新版本中是否仍然有效。 步骤9:运行测试 运行游戏,测试所有功能,特别是与渲染、物理、声音等相关的功能,确保没有引入新的问题。 注意事项: - 引用[2]中提到了一些Cocos2d-x的核心知识,如动作、动画、3D特效等,在升级后需要重点测试这些部分。 - 引用[4]中提到的Android面试题虽然不直接相关,但提醒我们在Android平台上需要特别注意,比如Android构建脚本的变化,以及可能需要的适配工作。 由于我们是从3.15.1升级到3.17.2,可以查看这两个版本之间的ChangeLog,重点关注修复的问题和引入的破坏性变更。 官方升级指南(如果有)应作为主要参考。 生成的相关问题: §§相关问题§§ 1. 如何查看Cocos2d-x 3.15.13.17.2的详细变更日志? 2. Cocos2d-x 3.17.2中废弃了哪些API?如何替换? 3. 升级Cocos2d-x引擎后,如何解决Android平台上的构建错误? 4. 如何将Cocos2d-x项目从3.x升级到4.x?</think>### Cocos2d-x 从 3.15.1 升级到 3.17.2 完整指南 #### 一、升级前准备 1. **备份项目** ```bash cp -R MyProject MyProject_Backup_3.15.1 ``` 确保所有代码和资源有完整备份[^1]。 2. **获取新引擎** 下载 Cocos2d-x 3.17.2 官方发布包: ```bash git clone -b v3.17.2 https://github.com/cocos2d/cocos2d-x.git ``` 3. **查看变更日志** 重点检查 [3.17.2 发布说明](https://github.com/cocos2d/cocos2d-x/blob/v3.17.2/docs/RELEASE_NOTES.md),特别关注: - API 废弃和移除 - 渲染器变更 - 物理引擎更新 #### 二、推荐升级路径(安全迁移) ```mermaid graph TD A[创建 3.17.2 新项目] --> B[迁移 Classes 代码] B --> C[迁移 Resources 资源] C --> D[更新工程配置] D --> E[解决 API 冲突] ``` 1. **创建纯净 3.17.2 项目** ```bash cd cocos2d-x-3.17.2 ./setup.py cocos new MyProject -p com.yourcompany.mygame -l cpp -d ~/projects ``` 2. **迁移关键内容** | 目录/文件 | 操作说明 | |-------------------|----------------------------| | `Classes/` | 整体复制到新项目 | | `Resources/` | 整体复制到新项目 | | `proj.android/` | 仅复制 `jni/` 和 `res/` | | `proj.ios_mac/` | 仅复制自定义 xcode 配置 | 3. **更新 CMake 配置** 修改新项目的 `CMakeLists.txt`: ```cmake # 更新引擎路径指向 3.17.2 set(COCOS2DX_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/../cocos2d-x-3.17.2) # 检查新增模块 target_link_libraries(${PROJECT_NAME} cocos2d cocos_audio cocos_network cocos_physics # 3.17.2 新增物理引擎模块 ) ``` #### 三、关键 API 变更处理 1. **渲染器适配**(引用[3]相关修改) 3.17.2 优化了渲染流程,需检查自定义 `draw()` 方法: ```cpp // 旧版本 (3.15.1) void NightLayer::draw(cocos2d::Renderer* renderer, const cocos2d::Mat4& transform, uint32_t flags) { _customCommand.init(_globalZOrder, transform, flags); _customCommand.func = CC_CALLBACK_0(NightLayer::onDraw, this, transform, flags); renderer->addCommand(&_customCommand); } // 新版本 (3.17.2) 需添加 transformFlags void NightLayer::draw(cocos2d::Renderer* renderer, const cocos2d::Mat4& transform, uint32_t flags) { _customCommand.init(_globalZOrder, transform, flags); _customCommand.func = CC_CALLBACK_0(NightLayer::onDraw, this, transform, flags); renderer->addCommand(&_customCommand, transform, flags); // 参数变更 } ``` 2. **物理引擎升级** 3.17.2 默认使用 Chipmunk2D,需检查: ```cpp // 替换废弃的创建方式 auto physicsBody = PhysicsBody::createCircle(radius); // 替换为: auto physicsBody = PhysicsBody::createCircle(radius, PhysicsMaterial(density, restitution, friction)); ``` #### 四、平台特定适配 1. **Android 构建** 更新 `proj.android/app/build.gradle`: ```gradle android { compileSdkVersion 29 // 3.17.2 要求最低 29 ndkVersion "21.4.7075529" } dependencies { implementation project(&#39;:libcocos2dx&#39;) } ``` 2. **iOS/macOS 修复** Xcode 工程中: - 删除 `libcurl` 和 `libz` 的重复链接 - 在 `Build Settings` > `Other Linker Flags` 添加 `-lc++` #### 五、验证与测试 1. **编译检查** ```bash # Windows cmake -S . -B build -G "Visual Studio 16 2019" -A x64 cmake --build build --config Debug # Android cocos compile -p android -m debug ``` 2. **核心功能测试清单** - [ ] 场景切换 - [ ] 物理碰撞检测 - [ ] 音效播放 - [ ] 粒子特效渲染 - [ ] 文本渲染(含中文) > **重要提示**:升级后若遇到 `Shader` 相关错误(如引用[3]),需检查 `CC_USE_METAL` 宏定义,3.17.2 默认开启 Metal 渲染支持[^1]。 #### 六、常见问题解决 1. **链接错误**: 检查 `target_link_libraries` 是否包含所有 `cocos_xxx` 模块 2. **资源加载失败**: 在 `AppDelegate.cpp` 添加资源搜索路径: ```cpp FileUtils::getInstance()->addSearchPath("Resources/"); ``` 3. **C++11 语法报错**: 在 CMake 中显式启用: ```cmake set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED ON) ``` 官方升级文档参考:[Cocos2d-x 3.17.2 Migration Guide](https://github.com/cocos2d/cocos2d-x/blob/v3.17.2/docs/MIGRATION.md)[^1] ---
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值