zoukankan      html  css  js  c++  java
  • python与c的集成

    记得在大学里和同学一起进行游戏开发,可到了后来完全无法继续下去,现在想想原因,一是自己的水平有限,另一个就是没做到游戏引擎与数据的分离,也就是没有理解脚本。那时的我根本就不知道什么叫做脚本编程,现在随着工作的深入也渐渐理解了一点。

    虽然脚本语言有很多种,但是我毫不犹豫了选择了python,我觉得它真的是一个好东西,但是我用到的只是它最基本的东西,毕竟我只是用它来进行游戏方面的脚本编程。所以我最先关心的就是怎么将它与c集成,即可以与系统引擎进行交互。(主要参考图书《游戏脚本高级编程》)

     

    1.  首先就是在编译器中把python安装目录include/libs/加入,对于这点我在vc6中可以,但是在dev c++中即使加入了编译也会出错,说找不到python头文件,这点比较郁闷,不过考虑到一般windows编程都用的是vc,所以并没有什么影响吧!!!

    然后用#include <Python.h>就可以把python的主头文件包含进来了。

    但是在调试的时候,会出现说找不到python25_d.lib的链接错误,出现这个错误的原因是python_d.lib是库的调试后形式,当我们以debug模式编译工程时,python就用这个lib文件,但是这个文件是不可用的。对于这点,最快的办法就是强制要求python在任何情况下都是用非调试版本,就可以了。要做到这一点

    a)  python目录include文件夹下,打开pyconfig.h,找到如下语句

    #                     ifdef _DEBUG

    #                            pragma comment(lib,"python25_d.lib")

    #                     else

    #                            pragma comment(lib,"python25.lib")

    #                     endif /* _DEBUG */

    python25_d.lib改成python25.lib

    b)  找到

    #ifdef _DEBUG

    #       define Py_DEBUG

    #endif

    将其用/**/屏蔽

           这样就可以了。

    2.  Python初始化
    python
    的初始化很简单我们只需在程序开始时调用Py_Initialize(),结束的时候调用Py_Finalize()就可以了

    3.  PyObject
    c语言程序中,我们使用PyObject来操纵python对象,一个PyObejct就是一个结构体,他表示某个与python相关的数据。只不过我们处理的都是该对象的指针。

    PyObject *t;  //t is a pointer to the python object

    4.  Reference counting
    对于python,跟directx比较类似,都采用了一种引用计数的机制,我们不需要自己去释放python对象,只需减少它的引用计数就可以了,当计数为0时,系统自己会安全释放。

    对于减少引用计数,我们使用Py_XDECREF(),而增加引用计数则是由代码负责完成。

    5.  载入脚本
    我们首先写一个python脚本,命名为test.py

     

    printf “Hello World”

           然后我们在主程序中调用,如下

                  PyObject *pName = PyString_FromString("test");

             PyObject * pModule = PyImport_Import(pName);

       

               if(!pModule)

               {

                   printf("could not open script /n");

                   return 0;           

               }

           这样就可以在控制台上面看见Hello World了。

    6.  调用脚本定义函数
    我们在test.py中定义一个函数,

     

    def GetMax(X, Y):

           print "/tGet Max was called from the host with",X,"and",Y

           if X > Y:

                  return X

           else:

                  return Y

     

    对于python,它提供了一个模块词典的概念,一个模块词典就是一个数据结构,负责将脚本中的标识符分别映射到与它们对应的代码或是数据上,如果在c程序中我们要调用getMax函数,我们就需要用脚本词典去获得一个包含有函数GetMaxpython对象。如下:

                 

    PyObject *pName = PyString_FromString("test");

             PyObject * pModule = PyImport_Import(pName);

       

               if(!pModule)

               {

                   printf("could not open script /n");

                   return 0;           

               }

     

           PyObject *pDict = PyModule_GetDict(pModule);

     

    然后我们获得GetMax函数

           PyObject *pFunc = PyDict_GetItemString(pDict, "GetMax");

     

    在我们向该函数中传递两个参数,python使用是tuple结构来传递参数

     

           PyObject *pParams = PyTuple_New(2);

           PyObject *pCurrParam;

           pCurrParam = PyInt_FromLong(16);

           PyTuple_SetItem(pParams, 0, pCurrParam);

           pCurrParam = PyInt_FromLong(32);

           PyTuple_SetItem(pParams, 1, pCurrParam);

     

    我们向GetMax函数传递了1632,然后就要调用函数并输出返回值了,如下

     

           PyObject *pMax = PyObject_CallObject(pFunc, pParams);

           int max = PyInt_AsLong(pMax);

     

    这样max就为32

     

    7.  Python调用c语言函数

    同样我们可以用python调用c语言函数,这样就能做到真正的交互了。首先定义一个c语言函数。

            PyObject * RepeatString (PyObject *pSelf, PyObject *pParams)

    {

                   printf("/tRepeatString was called from:/n");

     

                   char *pstrString;

                   int iRepCount;

     

                   if(!PyArg_ParseTuple(pParams, "si", &pstrString, &iRepCount))

                   {

                         printf("uable to parse parameter tuple./n");

                         exit(0);

                   }

     

                   for (int i = 0; i < iRepCount; i++)

                   {

                          printf("/t/t%d:   %s /n", i, pstrString);

                   }

                   return PyInt_FromLong(iRepCount);

    }

     

    该函数接受两个参数,pSelf没有什么用处,而另一个pParams则是用来传递参数的。由于传递参数都是用tuple结构,我们就使用PyArg_ParseTuple这个函数,对于”si”,表示的是按照字符串与整数来读取参数。

    然后我们在主应用程序中定义一个api来存放该函数

           PyMethodDef HostAPIFuncs [] =

           {

                  {"RepeatString", RepeatString, METH_VARARGS, NULL},

                  {NULL, NULL, NULL, NULL}    

           };

     

    对于这个数组的最后一行NULL来说,表明该数组结束。

    接下来我们创建一个module,用来供脚本调用

           if (!PyImport_AddModule("HostAPI"))

           {

                  printf("Host API module could not be created");

           }

    然后将我们定义的函数表加入这个模块

           if (!Py_InitModule("HostAPI", HostAPIFuncs))

           {

                  printf("Host API module could not be initialized");

           }

     

    创建一个python脚本test.py,然后在第一行写上

           import HostAPI

     

    再定义一个函数用来调用HostAPI函数

           def PrintStuff():

           RepCount = HostAPI.RepeatString("String repetition", 4)

          

    最后我们再在主程序中调用PrintStuff函数,就可以了

    总体程序如下:

           //create a module

           if (!PyImport_AddModule("HostAPI"))

           {

                  printf("Host API module could not be created");

           }

                 

           //create a function table

           PyMethodDef HostAPIFuncs [] =

           {

                  {"RepeatString", RepeatString, METH_VARARGS, NULL},

                  {NULL, NULL, NULL, NULL}    

           };

     

           //initial the module with the function table

           if (!Py_InitModule("HostAPI", HostAPIFuncs))

           {

                  printf("Host API module could not be initialized");

           }

     

           //load a python script

           PyObject *pName = PyString_FromString("test");

        PyObject * pModule = PyImport_Import(pName);

     

           if(!pModule)

        {

            printf("could not open script /n");

            return 0;           

        }

     

           //get the module dict

           PyObject * pDict = PyModule_GetDict ( pModule );

          

           //get the function with the dict

           PyObject * pFunc = PyDict_GetItemString ( pDict, "PrintStuff" );

          

           //call the function

           PyObject_CallObject ( pFunc, NULL );

     

           Py_XDECREF ( pFunc );

           Py_XDECREF ( pDict );

           Py_XDECREF(pModule);

           Py_XDECREF(pName);

     

    这样就完成了pythonc的集成,不过这只是一些简单的应用,具体还是要参考python manual。(以上代码来自于《游戏脚本高级编程》)

  • 相关阅读:
    反应堆模式
    ABP领域层——仓储(Repositories)
    如何使用ASP.NET Web API OData在Oracle中使用Entity Framework 6.x Code-First方式开发 OData V4 Service
    dapper的Dapper-Extensions用法(一)
    VisualStudio 怎么使用Visual Leak Detector
    Visual Studio Code开发TypeScript
    Topshelf创建Windows服务
    ENode框架初始化
    知已者明(转)
    配置静态监听解决ORA-12514错误的案例(转)
  • 原文地址:https://www.cnblogs.com/xiaowangba/p/6313804.html
Copyright © 2011-2022 走看看