<1>cocos new "Test" -p com.qingxue.game -l lua 创建lua项目
<2>根据tools/tolua/README.mdown下提示安装必要的库
brew install python
export PYTHON_BIN=/usr/local/Cellar/python/2.7.11/bin/python
export NDK_ROOT=/Users/jianan/Documents/android-ndk-r9b
sudo easy_install pip
sudo pip install PyYAML
sudo pip install Cheetah
LibclangError: dlopen(libclang.dylib, 6): image not found. To provide a path to libclang use Config.set_library_path() or Config.set_library_file(). 方法1: 这样可以解决:./frameworks/cocos2d-x/tools/bindings-generator/clang/cindex.py 第 3395 行 改为 : library = cdll.LoadLibrary("../bindings-generator/libclang/" + self.get_filename()) 错误信息提示 找不到libclang 需要调用一下 Config.set_library_path() 或者 Config.set_library_file() 方法 这个问题是因为生成Lua绑定的时候需要 libclang 这个库 查看目录 YOUR_PROJECT/frameworks/cocos2d-x/tools/bindings-generator/libclang 会发现Cocos引擎中提供了这个库 所以,只需要设置一下libchang路径就可以了。 修改 YOUR_PROJECT/frameworks/cocos2d-x/tools/bindings-generator/generator.py 方法2: 在967行的位置: class Generator(object): def __init__(self, opts): # 加入下面两行代码,注意缩进格式 libchangPath = os.path.abspath(os.path.join(os.path.dirname(__file__), 'libclang')) cindex.Config.set_library_path(libchangPath) self.index = cindex.Index.create() ...
<3>建立要绑定的.h和.cpp文件
CustomClass.h
#ifndef __CUSTOM__CLASS #define __CUSTOM__CLASS #include "cocos2d.h" namespace cocos2d { class CustomClass : public cocos2d::Ref { public: CustomClass(); ~CustomClass(); bool init(); std::string helloMsg(); CREATE_FUNC(CustomClass); }; } //namespace cocos2d #endif // __CUSTOM__CLASSCustomClass.cpp
#include "CustomClass.h" USING_NS_CC; CustomClass::CustomClass(){ } CustomClass::~CustomClass(){ } bool CustomClass::init(){ return true; } std::string CustomClass::helloMsg() { return "Hello from CustomClass::sayHello"; }
<4>tools/tolua下写ini配置文件
1,cocos2dx_custom.ini
[cocos2dx_custom] # the prefix to be added to the generated functions. You might or might not use this in your own # templates prefix = cocos2dx_custom # create a target namespace (in javascript, this would create some code like the equiv. to `ns = ns || {}`) # all classes will be embedded in that namespace target_namespace = cc macro_judgement = android_headers = -I%(androidndkdir)s/platforms/android-14/arch-arm/usr/include -I%(androidndkdir)s/sources/cxx-stl/gnu-libstdc++/4.7/libs/armeabi-v7a/include -I%(androidndkdir)s/sources/cxx-stl/gnu-libstdc++/4.7/include -I%(androidndkdir)s/sources/cxx-stl/gnu-libstdc++/4.8/libs/armeabi-v7a/include -I%(androidndkdir)s/sources/cxx-stl/gnu-libstdc++/4.8/include android_flags = -D_SIZE_T_DEFINED_ clang_headers = -I%(clangllvmdir)s/lib/clang/3.3/include #clang_flags = -nostdinc -x c++ -std=c++11 -D CC_USE_NAVMESH clang_flags = -nostdinc -x c++ -std=c++11 win32_clang_flags = -U __SSE__ cocos_headers = -I%(cocosdir)s/cocos -I%(cocosdir)s/cocos/platform/android -I%(cocosdir)s/external -I%(cocosdir)s/external/recast/Detour -I%(cocosdir)s/external/recast/DetourCrowd -I%(cocosdir)s/external/recast/DetourTileCache -I%(cocosdir)s/external/recast/DebugUtils -I%(cocosdir)s/external/recast/fastlz -I%(cocosdir)s/external/recast/Recast -I%(cocosdir)s/external/lua/luajit/include -I%(cocosdir)s/external/lua/tolua -I%(cocosdir)s/cocos/scripting/lua-bindings/manual cocos_flags = -DANDROID cxxgenerator_headers = # extra arguments for clang extra_arguments = %(android_headers)s %(clang_headers)s %(cxxgenerator_headers)s %(cocos_headers)s %(android_flags)s %(clang_flags)s %(cocos_flags)s %(extra_flags)s # what headers to parse #headers = %(cocosdir)s/cocos/navmesh/CCNavMesh.h %(cocosdir)s/cocos/scripting/lua-bindings/manual/navmesh/lua_cocos2dx_navmesh_conversions.h #headers = %(cocosdir)s/tests/LuabindingTest/frameworks/runtime-src/Classes/CustomClass.h %(cocosdir)s/cocos/scripting/lua-bindings/manual/navmesh/lua_cocos2dx_custom_class.h headers = %(cocosdir)s/tests/LuabindingTest/frameworks/runtime-src/Classes/CustomClass.h # what classes to produce code for. You can use regular expressions here. When testing the regular # expression, it will be enclosed in "^$", like this: "^Menu*$". #classes = NavMesh NavMeshAgent NavMeshObstacle classes = CustomClass.* # what should we skip? in the format ClassName::[function function] # ClassName is a regular expression, but will be used like this: "^ClassName$" functions are also # regular expressions, they will not be surrounded by "^$". If you want to skip a whole class, just # add a single "*" as functions. See bellow for several examples. A special class name is "*", which # will apply to all class names. This is a convenience wildcard to be able to skip similar named # functions from all classes. #skip = NavMesh::[findPath], # NavMeshObstacle::[setRadius setHeight], # NavMeshAgent::[move] skip = rename_functions = rename_classes = # for all class names, should we remove something when registering in the target VM? remove_prefix = # classes for which there will be no "parent" lookup classes_have_no_parents = # base classes which will be skipped when their sub-classes found them. base_classes_to_skip = # classes that create no constructor # Set is special and we will use a hand-written constructor abstract_classes = # Determining whether to use script object(js object) to control the lifecycle of native(cpp) object or the other way around. Supported values are 'yes' or 'no'. script_control_cpp = no
2,genbindings.py
#!/usr/bin/python # This script is used to generate luabinding glue codes. # Android ndk version must be ndk-r9b. import sys import os, os.path import shutil import ConfigParser import subprocess import re from contextlib import contextmanager def _check_ndk_root_env(): ''' Checking the environment NDK_ROOT, which will be used for building ''' try: NDK_ROOT = os.environ['NDK_ROOT'] except Exception: print "NDK_ROOT not defined. Please define NDK_ROOT in your environment." sys.exit(1) return NDK_ROOT def _check_python_bin_env(): ''' Checking the environment PYTHON_BIN, which will be used for building ''' try: PYTHON_BIN = os.environ['PYTHON_BIN'] except Exception: print "PYTHON_BIN not defined, use current python." PYTHON_BIN = sys.executable return PYTHON_BIN class CmdError(Exception): pass @contextmanager def _pushd(newDir): previousDir = os.getcwd() os.chdir(newDir) yield os.chdir(previousDir) def _run_cmd(command): ret = subprocess.call(command, shell=True) if ret != 0: message = "Error running command" raise CmdError(message) def main(): cur_platform= '??' llvm_path = '??' ndk_root = _check_ndk_root_env() # del the " in the path ndk_root = re.sub(r"\"", "", ndk_root) python_bin = _check_python_bin_env() platform = sys.platform if platform == 'win32': cur_platform = 'windows' elif platform == 'darwin': cur_platform = platform elif 'linux' in platform: cur_platform = 'linux' else: print 'Your platform is not supported!' sys.exit(1) if platform == 'win32': x86_llvm_path = os.path.abspath(os.path.join(ndk_root, 'toolchains/llvm-3.3/prebuilt', '%s' % cur_platform)) else: x86_llvm_path = os.path.abspath(os.path.join(ndk_root, 'toolchains/llvm-3.3/prebuilt', '%s-%s' % (cur_platform, 'x86'))) x64_llvm_path = os.path.abspath(os.path.join(ndk_root, 'toolchains/llvm-3.3/prebuilt', '%s-%s' % (cur_platform, 'x86_64'))) if os.path.isdir(x86_llvm_path): llvm_path = x86_llvm_path elif os.path.isdir(x64_llvm_path): llvm_path = x64_llvm_path else: print 'llvm toolchain not found!' print 'path: %s or path: %s are not valid! ' % (x86_llvm_path, x64_llvm_path) sys.exit(1) project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..')) cocos_root = os.path.abspath(os.path.join(project_root, '')) cxx_generator_root = os.path.abspath(os.path.join(project_root, 'tools/bindings-generator')) # save config to file config = ConfigParser.ConfigParser() config.set('DEFAULT', 'androidndkdir', ndk_root) config.set('DEFAULT', 'clangllvmdir', llvm_path) config.set('DEFAULT', 'cocosdir', cocos_root) config.set('DEFAULT', 'cxxgeneratordir', cxx_generator_root) config.set('DEFAULT', 'extra_flags', '') # To fix parse error on windows, we must difine __WCHAR_MAX__ and undefine __MINGW32__ . if platform == 'win32': config.set('DEFAULT', 'extra_flags', '-D__WCHAR_MAX__=0x7fffffff -U__MINGW32__') conf_ini_file = os.path.abspath(os.path.join(os.path.dirname(__file__), 'userconf.ini')) print 'generating userconf.ini...' with open(conf_ini_file, 'w') as configfile: config.write(configfile) # set proper environment variables if 'linux' in platform or platform == 'darwin': os.putenv('LD_LIBRARY_PATH', '%s/libclang' % cxx_generator_root) if platform == 'win32': path_env = os.environ['PATH'] os.putenv('PATH', r'%s;%s\libclang;%s\tools\win32;' % (path_env, cxx_generator_root, cxx_generator_root)) try: tolua_root = '%s/tools/tolua' % project_root output_dir = '%s/cocos/scripting/lua-bindings/auto' % project_root cmd_args = {'cocos2dx.ini' : ('cocos2d-x', 'lua_cocos2dx_auto'), \ 'cocos2dx_extension.ini' : ('cocos2dx_extension', 'lua_cocos2dx_extension_auto'), \ 'cocos2dx_ui.ini' : ('cocos2dx_ui', 'lua_cocos2dx_ui_auto'), \ 'cocos2dx_studio.ini' : ('cocos2dx_studio', 'lua_cocos2dx_studio_auto'), \ 'cocos2dx_spine.ini' : ('cocos2dx_spine', 'lua_cocos2dx_spine_auto'), \ 'cocos2dx_physics.ini' : ('cocos2dx_physics', 'lua_cocos2dx_physics_auto'), \ 'cocos2dx_experimental_video.ini' : ('cocos2dx_experimental_video', 'lua_cocos2dx_experimental_video_auto'), \ 'cocos2dx_experimental.ini' : ('cocos2dx_experimental', 'lua_cocos2dx_experimental_auto'), \ 'cocos2dx_controller.ini' : ('cocos2dx_controller', 'lua_cocos2dx_controller_auto'), \ 'cocos2dx_custom.ini' : ('cocos2dx_custom', 'lua_cocos2dx_custom'), \ } target = 'lua' generator_py = '%s/generator.py' % cxx_generator_root for key in cmd_args.keys(): args = cmd_args[key] cfg = '%s/%s' % (tolua_root, key) print 'Generating bindings for %s...' % (key[:-4]) command = '%s %s %s -s %s -t %s -o %s -n %s' % (python_bin, generator_py, cfg, args[0], target, output_dir, args[1]) _run_cmd(command) if platform == 'win32': with _pushd(output_dir): _run_cmd('dos2unix *') print '---------------------------------' print 'Generating lua bindings succeeds.' print '---------------------------------' except Exception as e: if e.__class__.__name__ == 'CmdError': print '---------------------------------' print 'Generating lua bindings fails.' print '---------------------------------' sys.exit(1) else: raise # -------------- main -------------- if __name__ == '__main__': main()
<5>cd 到 frameworks/cocos2d-x/tools/tolua下面,运行./genbindings.py生成绑定文件
其中.hpp和.cpp在cocos/scripting/lua-bindings/auto中
生成的lua类名在cocos/scripting/lua-bindings/auto/api中
1,
cocos2d_lua_bindings.xcodeproj下的auto文件夹里面添加生成的.hpp和.cpp文件
2,
Classes下添加导出的.hpp 和 .cpp文件及其对应的.h 和 .cpp文件
3,
TARGETS Mac下:
Header Search Paths中添加搜索路径:
$(SRCROOT)/../ClassesSRCROOT指的就是Classes
<7>注册C++代码到lua中,并且运行xcode.
2.使用C++导出的lua文件 编辑AppDelegate.cpp,包含lua_myclass_auto.hpp头文件,在 LuaEngine* engine = LuaEngine::getInstance(); 后面加入 LuaStack* stack = engine->getLuaStack(); stack->setXXTEAKeyAndSign("2dxLua", strlen("2dxLua"), "XXTEA", strlen("XXTEA")); register_all_cocos2dx_custom(engine->getLuaStack()->getLuaState());
<8>cocos code ide 下:
1.构建模拟器
2.模拟器构建成功
3.浏览选择刚构建的模拟器
4.新的模拟器路径
5.运行成功
local function main() collectgarbage("collect") -- avoid memory leak collectgarbage("setpause", 100) collectgarbage("setstepmul", 5000) cc.FileUtils:getInstance():addSearchPath("src") cc.FileUtils:getInstance():addSearchPath("res") cc.Director:getInstance():getOpenGLView():setDesignResolutionSize(480, 320, 0) local var = cc.CustomClass:create():helloMsg() print(var) --create scene local scene = require("GameScene") local gameScene = scene.create() gameScene:playBgMusic() if cc.Director:getInstance():getRunningScene() then cc.Director:getInstance():replaceScene(gameScene) else cc.Director:getInstance():runWithScene(gameScene) end end
搞定!!!
参考:
http://my.oschina.net/skyhacker2/blog/298397
http://www.cocos2d-x.org/wiki/Binding_Custom_Class_To_Lua_Runtime