环境:
cocos2dx-3.17.2
python3.7.0
目前仅做了android版本,其他平台类似,测试代码就在cpp-test里面,使用AndroidStudio打开编译运行即可。
测试用例目前只完成类SceneTest,代码在tscene.py,其他测试用例只需同样编写就行,底层有未完成的陆续补充。
近来时间非常紧张,欢迎有心人一同完善。具体内容看代码仓库README.md。
git@gitee.com:aiastefan/cocos2dx-py.git
思路:
在cocos2d启动初始化glview时(Cocos2dxActivity.java),开启一个task异步拷贝python脚本代码到android应用目录,glview启动完成或者脚本拷贝完成,在AppDelegate启动处启动python脚本,代码如(py_cocos2d.cpp):
// 主循环,相当于main
void startup()
{
/* see doc: https://docs.python.org/3.7/c-api/init.html#pre-init-safe */
PLOGD("=====python will start up=====");
int res = PyImport_AppendInittab("C_base",&PyInit_pybase); //初始化模块
res = PyImport_AppendInittab("C_2d",&PyInit_py2d);
res = PyImport_AppendInittab("C_3d",&PyInit_py3d);
res = PyImport_AppendInittab("C_math",&PyInit_pymath);
res = PyImport_AppendInittab("C_physics",&PyInit_pyphysics);
res = PyImport_AppendInittab("C_renderer",&PyInit_pyrenderer);
res = PyImport_AppendInittab("C_ui",&PyInit_pyui);
res = PyImport_AppendInittab("C_platform",&PyInit_pyplatform);
res = PyImport_AppendInittab("C_extensions",&PyInit_pyextensions);
// 尝试一:java层把python3.7m.MP3解压到appFile文件夹下
//char dest[256];
//sprintf(dest,"%s/%s", appFilePath,"python3.7m.zip");
const char *fullPythonPath = appFilePath;
//cocos2d::FileUtils::getInstance()->fullPathForFilename("python3.7m.MP3").c_str();// assets/python3.7.MP3
//dest;
unsigned int len = 0;
wchar_t *homePath = Py_DecodeLocale(fullPythonPath,&len);
PLOGD("=====fullpythonpath: %s len: %d",fullPythonPath,len);
//Py_SetPythonHome(homePath);//把python3.7m.MP3脚本文件路径设置进去
Py_SetPath(homePath);
PLOGD("=====python will Initialize=====");
Py_Initialize();
if (!Py_IsInitialized()) {
//log
PLOGD("=====Py_Initialize failed!");
return;
}
PLOGD("=====python Initialize ok=====");
// 将当前路径加入解释器的搜索路径
PyRun_SimpleString("print 'hello pycocos2d'");
PyRun_SimpleString("import sys");
char dest[256];
sprintf(dest,"sys.path.append('%s/%s')", appFilePath,"site-packages");// "pyscripts"
PLOGD("=====sys.path %s",dest);
PyRun_SimpleString(dest);
sprintf(dest,"sys.path.append('%s/%s')", appFilePath,"pylib-dynload");// "pyscripts"
PLOGD("=====sys.path %s",dest);
PyRun_SimpleString(dest);
sprintf(dest,"sys.path.append('%s/%s')", appFilePath,"pyscripts");// "pyscripts"
PLOGD("=====sys.path %s",dest);
PyRun_SimpleString(dest);
sprintf(dest,"sys.path.append('%s/%s')", appFilePath,"pyscripts/core");// "pyscripts"
PLOGD("=====sys.path %s",dest);
PyRun_SimpleString(dest);
// sprintf(dest,"sys.path.append('%s/%s')", appFilePath,"pyscripts/2d");// "pyscripts"
// PLOGD("=====sys.path %s",dest);
// PyRun_SimpleString(dest);
// sprintf(dest,"sys.path.append('%s/%s')", appFilePath,"pyscripts/3d");// "pyscripts"
// PLOGD("=====sys.path %s",dest);
// PyRun_SimpleString(dest);
// sprintf(dest,"sys.path.append('%s/%s')", appFilePath,"pyscripts/math");// "pyscripts"
// PLOGD("=====sys.path %s",dest);
// PyRun_SimpleString(dest);
// sprintf(dest,"sys.path.append('%s/%s')", appFilePath,"pyscripts/ui");// "pyscripts"
// PLOGD("=====sys.path %s",dest);
// PyRun_SimpleString(dest);
// sprintf(dest,"sys.path.append('%s/%s')", appFilePath,"pyscripts/platform");// "pyscripts"
// PLOGD("=====sys.path %s",dest);
// PyRun_SimpleString(dest);
// sprintf(dest,"sys.path.append('%s/%s')", appFilePath,"pyscripts/renderer");// "pyscripts"
// PLOGD("=====sys.path %s",dest);
// PyRun_SimpleString(dest);
// sprintf(dest,"sys.path.append('%s/%s')", appFilePath,"pyscripts/physics_2d");// "pyscripts"
// PLOGD("=====sys.path %s",dest);
// PyRun_SimpleString(dest);
// sprintf(dest,"sys.path.append('%s/%s')", appFilePath,"pyscripts/actions");// "pyscripts"
// PLOGD("=====sys.path %s",dest);
// PyRun_SimpleString(dest);
sprintf(dest,"sys.path.append('%s/%s')", appFilePath,"yourapp");// "pyscripts"
PLOGD("=====sys.path %s",dest);
PyRun_SimpleString(dest);
wchar_t* pythonHome = Py_GetProgramFullPath();//Py_GetPythonHome();
if (pythonHome != nullptr) {
char* pythonHomeStr = Py_EncodeLocale(pythonHome,NULL);
PLOGD("=====python home: %s",pythonHomeStr);
}
// 获取python解释器版本号
PyObject *platform = PyImport_ImportModule("platform");
DDD
if (platform != nullptr) {
PyObject *funcVersion = PyObject_GetAttrString(platform,"python_version");
DDD
PyObject *sVer = PyUnicode_AsEncodedString(PyEval_CallObject(funcVersion,NULL),"utf-8","~E~");
PLOGD("=====python interpreter version: %s",PyBytes_AS_STRING(sVer));
} else {
PLOGD("=====import platform not found");
}
// 获取python解释器搜索路径
PyObject *sys = PyImport_ImportModule("sys");
PyObject *funcPath = PyObject_GetAttrString(sys,"path");
PyObject *sPath = PyUnicode_AsEncodedString(PyObject_Repr(funcPath),"utf-8","~E~");
PLOGD("=====python interpreter path: %s",PyBytes_AS_STRING(sPath));
// 主循环,需要提供main.py脚本
// PyObject *mMain = PyImport_ImportModule("main");
// if (!mMain) {
// PLOGD("=====err not main");
// Py_Finalize();
// return;
// }
// DDD
// PyRun_SimpleString("import main");
// DDD
// PyRun_SimpleString("main.bootstrap()");
// DDD
//pyApplicationDidFinishLaunching();
}
void pyApplicationDidFinishLaunching()
{
DDD
PyObject *mMain = PyImport_ImportModule("main");
if (!mMain) {
PLOGD("=====err not main");
Py_Finalize();
return;
}
DDD
PyRun_SimpleString("import main");
PyRun_SimpleString("main.applicationDidFinishLaunching()");
DDD
}
通过PyRun_SimpleString(“main.applicationDidFinishLaunching()”)调用python的main.py模块对应函数,后续逻辑都在python层写。
这里贴上tscene.py的代码,其他测试用例照样扩展。
import traceback
import C_2d
import pytest.basetest
import pylog
import pymenu
import pyaction
import pytransition
import pydirector
class SceneTest(pytest.basetest.TestSuite):
def __init__(self):
super().__init__()
try:
pylog.logi("init SceneTest")
self.add_testcase("SceneTestScene", SceneTestScene)
except:
pylog.loge(traceback.format_exc())
class SceneTestScene(pytest.basetest.TestCase):
def __new__(cls, t_suite, idx):
return super().__new__(cls)
def __init__(self, t_suite, idx=0):
pylog.logi("===== SceneTestScene %d" % idx)
super().__init__("SceneTestScene", "SceneTestLayer1")
self.set_test_suite(t_suite)
if idx == 0:
layer1 = SceneTestLayer1(t_suite) # 默认测试index=0开始
self.addChild(layer1)
elif idx == 1:
layer2 = SceneTestLayer2(t_suite)
self.addChild(layer2)
elif idx == 2:
layer3 = SceneTestLayer3(t_suite)
self.addChild(layer3)
"""
以下是各实例test
"""
class SceneTestLayer1(C_2d.CLayer):
def __init__(self, t_suite):
super().__init__()
self.test_suite = t_suite
pylog.logi("init SceneTestLayer1")
item1 = pymenu.MenuItemFont("Test pushScene", self.push_scene)
item2 = pymenu.MenuItemFont("Test pushScene w/transition", self.push_scene_tran)
item3 = pymenu.MenuItemFont("Quit", self.quit)
menu = pymenu.Menu(item1, item2, item3)
menu.alignItemsVertically()
self.addChild(menu)
w, h = pydirector.GetInstance().getWinSize()
sprite = C_2d.CSprite(pytest.basetest.s_pathGrossini)
self.addChild(sprite)
sprite.setPosition(w-40, h/2)
rotateby = pyaction.RotateBy(2, 360)
repeat = pyaction.ActionInterval().RepeatForever(rotateby)
sprite.runAction(repeat)
def push_scene(self):
try:
pylog.logi("push scene")
scene = SceneTestScene(self.test_suite, 1)
pydirector.GetInstance().pushScene(scene)
except:
pylog.loge(traceback.format_exc())
def push_scene_tran(self):
pylog.logi("push scene transition")
scene = SceneTestScene(self.test_suite, 1)
dest = pytransition.TransitionSlideInT(1, scene)
pydirector.GetInstance().pushScene(dest)
def quit(self):
pydirector.GetInstance().popScene()
class SceneTestLayer2(C_2d.CLayer):
def __init__(self, t_suite):
super().__init__()
self.test_suite = t_suite
pylog.logi("init SceneTestLayer2")
item1 = pymenu.MenuItemFont("Test replaceScene", self.replace_scene)
item2 = pymenu.MenuItemFont("Test replaceScene w/transition", self.replace_scene_tran)
item3 = pymenu.MenuItemFont("GoBack", self.go_back)
menu = pymenu.Menu(item1, item2, item3)
menu.alignItemsVertically()
self.addChild(menu)
w, h = pydirector.GetInstance().getWinSize()
sprite = C_2d.CSprite(pytest.basetest.s_pathGrossini)
self.addChild(sprite)
sprite.setPosition(40, h/2)
rotateby = pyaction.RotateBy(1, 360)
repeat = pyaction.ActionInterval().RepeatForever(rotateby)
sprite.runAction(repeat)
def replace_scene(self):
try:
pylog.logi("push scene")
scene = SceneTestScene(self.test_suite, 1)
pydirector.GetInstance().replaceScene(scene)
except:
pylog.loge(traceback.format_exc())
def replace_scene_tran(self):
pylog.logi("push scene transition")
scene = SceneTestScene(self.test_suite, 1)
dest = pytransition.TransitionSlideInT(1, scene)
pydirector.GetInstance().replaceScene(dest)
def go_back(self):
pydirector.GetInstance().popScene()
class SceneTestLayer3(C_2d.CLayerColor):
def __init__(self, t_suite):
super().__init__()
self.test_suite = t_suite
pylog.logi("init SceneTestLayer3")
欢迎有心人加入,更欢迎实力大牛,解决部分未解之谜,以及代码封装不好的地方。直接gitee留言即可。