首页 文章 精选 留言 我的

精选列表

搜索[游戏],共9817篇文章
优秀的个人博客,低调大师

如何用C++做游戏(3)

上一讲我把Lua基本的栈规则讲了一下,然后完善了一下我的CLuaFn类。让它可以支持任意参数数量和函数名称的传值。当然,这些功能是为了今天这篇文章而铺路的。 我是一名(C++)程序员,所以在很多时候,不想过多的使用Lua的特性,因为个人感觉,Lua的语法要比(C++)的更加灵活。而我更希望,在函数调用的某些习惯上,遵循一些(C++)的规则。 好了,废话少说,我们先来看一个类(头文件)。假设我们要把这个对象,传输给Lua进行调用。 #ifndef _TEST_H #define _TEST_H class CTest { public: CTest(void); ~CTest(void); char* GetData(); void SetData(const char* pData); private: char m_szData[200]; }; #endif 这个类里面有两个函数,一个是GetData(),一个是SetData(),之所以这么写,我要让Lua不仅能使用我的类,还可以给这个类使用参数。 那么,cpp文件,我们姑且这样写。(当然,你可以进行修改,按照你喜欢的方式写一个方法) char* CTest::GetData() { printf(“[CTest::GetData]%s./n”, m_szData); return m_szData; } void CTest::SetData(const char* pData) { sprintf(m_szData, “%s”, pData); } 这是一个标准的类,我需要这个类在Lua里面可以创造出来,并赋予数值,甚至我可以把CTest作为一个Lua函数参数,传给Lua函数让它去给我 处理。让我们来看看怎么做。如果使用标准的Lua语法,有点多,所以我就借用一下上次提到的tolua来做到这一切,我一句句的解释。姑且我们把这些代码 放在LuaFn.cpp里面。 static int tolua_new_CTest(lua_State* pState) { CTest* pTest = new CTest(); tolua_pushusertype(pState, pTest, “CTest”); return 1; } static int tolua_delete_CTest(lua_State* pState) { CTest* pTest = (CTest* )tolua_tousertype(pState, 1, 0); if(NULL != pTest) { delete pTest; } return 1; } static int tolua_SetData_CTest(lua_State* pState) { CTest* pTest = (CTest* )tolua_tousertype(pState, 1, 0); const char* pData = tolua_tostring(pState, 2, 0); if(pData != NULL && pTest != NULL) { pTest->SetData(pData); } return 1; } static int tolua_GetData_CTest(lua_State* pState) { CTest* pTest = (CTest* )tolua_tousertype(pState, 1, 0); if(pTest != NULL) { char* pData = pTest->GetData(); tolua_pushstring(pState, pData); } return 1; } 看看这几个静态函数在干什么。 我要在Lua里面使用CTest,必须让Lua里这个CTest对象能够顺利的创造和销毁。tolua_new_CTest()和tolua_delete_CTest()就是干这个的。 tolua_pushusertype(pState, pTest, “CTest”); 这句话的意思是,将一个已经在Lua注册的”CTest”对象指针,压入数据栈,用指针形式弹出来。 。 ,CTest* pTest = (CTest* )tolua_tousertype(pState, 1, 0);是将数据栈下的对象以(CTest* ) tolua_SetData_CTest() 函数和tolua_GetData_CTest分别对应CTest的SetData方法和GetData()方法。 因为我们的SetData方法里面存在 变量,那么同样,我们需要使用const char* pData = tolua_tostring(pState, 2, 0);将参数弹出来,然后输入到pTest->SetData(pData);对象中去,当然,你可以有更多若干个参数。随你的喜好。这里只做一个 举例。 好了,你一定会问,这么多的静态函数,用在哪里?呵呵,当然是给Lua注册,当你把这些数据注册到Lua里面,你就可以轻松的在Lua中使用它们。 让我们看看,注册是怎么做到的。 还是在CLuaFn类里面,我们增加一个函数。比如叫做bool InitClass(); bool CLuaFn::InitClass() { if(NULL == m_pState) { printf(“[CLuaFn::InitClass]m_pState is NULL./n”); return false; } tolua_open(m_pState); tolua_module(m_pState, NULL, 0); tolua_beginmodule(m_pState, NULL); tolua_usertype(m_pState, “CTest”); tolua_cclass(m_pState, “CTest”, “CTest”, “”, tolua_delete_CTest); tolua_beginmodule(m_pState, “CTest”); tolua_function(m_pState, “new”, tolua_new_CTest); tolua_function(m_pState, “SetData”, tolua_SetData_CTest); tolua_function(m_pState, “GetData”, tolua_GetData_CTest); tolua_endmodule(m_pState); tolua_endmodule(m_pState); return true; } 上面的代码,就是我把上面的几个静态函数,绑定到Lua的基础对象中去。 tolua_beginmodule(m_pState, “CTest”);是只注册一个模块,比如,我们管CTest叫做”CTest”,保持和C的名称一样。这样在Lua的对象库中就会多了一个 CTest的对象描述,等同于string,number等等基本类型,同理,你也可以用同样的方法,注册你的MFC类。是不是有点明白了?这里要注 意,tolua_beginmodule()和tolua_endmodule()对象必须成对出现,如果出现不成对的,你注册的C类型将会失败。 tolua_function(m_pState, “SetData”, tolua_SetData_CTest); 指的是将Lua里面CTest对象的”SetData”绑定到你的tolua_SetData_CTest()函数中去。 好的,让我们来点激动人心的东西。还记得我们的Simple.lua的文件么。我们来改一下它。 function func_Add(x, y) local test = CTest:new(); test:SetData(“I’m freeeyes!”); test:GetData(); return x..y; end 我在这个函数里面,New了一个CTest对象,并进行赋值操作,最后把结果打印在屏幕上。 你或许会问,最后一句不是x+y么,怎么变成了 x..y,呵呵,在Lua中,..表示联合的意思,就好比在C++里面, string strName += “freeeyes”。原来觉得x+y有点土,索性返回一个两个字符串的联合吧。 好了,我们已经把我们的这个CTest类注册到了Lua里面,让我们来调用一下吧。修改一下Main函数。变成以下的样子。 int _tmain(int argc, _TCHAR* argv[]) { CLuaFn LuaFn; LuaFn.InitClass(); LuaFn.LoadLuaFile(“Sample.lua”); CParamGroup ParamIn; CParamGroup ParamOut; char szData1[20] = {‘/0′}; sprintf(szData1, “[freeeyes]“); _ParamData* pParam1 = new _ParamData(szData1, “string”, (int)strlen(szData1)); ParamIn.Push(pParam1); char szData2[20] = {‘/0′}; sprintf(szData2, “[shiqiang]“); _ParamData* pParam2 = new _ParamData(szData2, “string”, (int)strlen(szData2)); ParamIn.Push(pParam2); char szData3[40] = {‘/0′}; _ParamData* pParam3 = new _ParamData(szData3, “string”, 40); ParamOut.Push(pParam3); LuaFn.CallFileFn(“func_Add”, ParamIn, ParamOut); char* pData = (char* )ParamOut.GetParam(0)->GetParam(); printf(“[Main]Sum = %s./n”, pData); getchar(); return 0; } 如果你完全按照我的,你就可以编译你的工程了,运行一下,看看是啥结果? [CTest::GetData]I’m freeeyes!. [Main]Sum = [freeeyes][shiqiang]. 看看,是不是和我输出的一样? 呵呵,有意思吧,你已经可以在Lua里面用C++的函数了,那么咱们再增加一点难度,比如,我有一个CTest对象,要作为一个参数,传输给func_Add()执行,怎么办? 很简单,如果你对上面的代码仔细阅读,你会发现下面的代码一样简洁。为了支持刚才要说的需求,我们需要把Sample.lua再做一点修改。 function func_Add(x, y, f) f:SetData(“I’m freeeyes!”); f:GetData(); return x..y; end f假设就是我们要传入的CTest对象。我们要在Lua里面使用它。(我们的CLuaFn都不用改,把main函数稍微改一下即可,来看看怎么写。) // LuaSample.cpp : 定义控制台应用程序的入口点。 // #include “stdafx.h” #include “LuaFn.h” int _tmain(int argc, _TCHAR* argv[]) { CLuaFn LuaFn; LuaFn.InitClass(); LuaFn.LoadLuaFile(“Sample.lua”); CParamGroup ParamIn; CParamGroup ParamOut; char szData1[20] = {‘/0′}; sprintf(szData1, “[freeeyes]“); _ParamData* pParam1 = new _ParamData(szData1, “string”, (int)strlen(szData1)); ParamIn.Push(pParam1); char szData2[20] = {‘/0′}; sprintf(szData2, “[shiqiang]“); _ParamData* pParam2 = new _ParamData(szData2, “string”, (int)strlen(szData2)); ParamIn.Push(pParam2); //只追加了这里 CTest* pTest = new CTest(); _ParamData* pParam3 = new _ParamData(pTest, “CTest”, sizeof(CTest)); ParamIn.Push(pParam3); //追加结束 char szData4[40] = {‘/0′}; _ParamData* pParam4 = new _ParamData(szData4, “string”, 40); ParamOut.Push(pParam4); LuaFn.CallFileFn(“func_Add”, ParamIn, ParamOut); char* pData = (char* )ParamOut.GetParam(0)->GetParam(); printf(“[Main]Sum = %s./n”, pData); getchar(); return 0; } 好了,就这么点代码,改好了,我们再Build一下,然后点击运行。看看输出结果,是不是和以前的一样? 恩,是不是有点兴奋了?你成功的让Lua开始调用你的C++对象了!并且按照你要的方式执行!还记得我曾在第一篇文章里面许诺过,我会让你画出一个MFC窗体么?呵呵,如果你到现在依然觉得很清晰的话,说明你的距离已经不远了。 既然已经到了这里,我们索性再加点难度,如果我要把CTest作为一个对象返回回来怎么做?很简单,且看。 int _tmain(int argc, _TCHAR* argv[]) { CLuaFn LuaFn; LuaFn.InitClass(); LuaFn.LoadLuaFile(“Sample.lua”); CParamGroup ParamIn; CParamGroup ParamOut; char szData1[20] = {‘/0′}; sprintf(szData1, “[freeeyes]“); _ParamData* pParam1 = new _ParamData(szData1, “string”, (int)strlen(szData1)); ParamIn.Push(pParam1); char szData2[20] = {‘/0′}; sprintf(szData2, “[shiqiang]“); _ParamData* pParam2 = new _ParamData(szData2, “string”, (int)strlen(szData2)); ParamIn.Push(pParam2); CTest* pTest = new CTest(); _ParamData* pParam3 = new _ParamData(pTest, “CTest”, sizeof(CTest)); ParamIn.Push(pParam3); CTest* pTestRsult = NULL; _ParamData* pParam4 = new _ParamData(pTestRsult, “CTest”, sizeof(pTestRsult)); ParamOut.Push(pParam4); LuaFn.CallFileFn(“func_Add”, ParamIn, ParamOut); //接受Lua返回参数为CTest类型,并调用其中的方法。 pTestRsult = (CTest* )ParamOut.GetParam(0)->GetParam(); pTestRsult->GetData(); getchar(); return 0; } 好,编译,执行。呵呵,看到了吧。 看到这里,如果你能看的明白,说明你已经对Lua如何调用C接口,以及C如何调用Lua有了一定的理解。当然,我写的这个类也不是很完善,不过做一半的Lua开发,应该是够用了。以以上的方式,你可以使用Lua驾驭你的C++代码。 好了,咱们既然已经说到这里了,再深一步,如果我的类是继承的,怎么办? 比如,我的CTest继承了一个CBase,我的CBase又继承了一个。。。 在Lua里面,一样简单,我拿MFC的例子来举例吧,想必大家更喜欢看。 比如 CCmdTarget继承自CObject。 那么我在注册的时候可以这么写。 tolua_cclass(tolua_S, “CCmdTarget”, ”CCmdTarget”, ”CObject”, NULL); 这个表示CCmdTarget继承自CObject对象。 当然,MFC里面还会有很多类型,比如常数,Lua一样能处理。 举个例子说。 tolua_constant(tolua_S, “ES_AUTOHSCROLL”, ES_AUTOHSCROLL); 这样注册,你就可以在 Lua里面使用ES_AUTOHSCROLL这个常数,它会自动绑定ES_AUTOHSCROLL这个(C++)常数对象。 小伙伴们,还请持续关注更新,更多干货和资料请直接联系我,也可以加群710520381,邀请码:柳猫,欢迎大家共同讨论

优秀的个人博客,低调大师

33亿游戏背后的利益哲学

没有永远的朋友,也没有永远的敌人,只有永远的利益。Oracle(甲骨文)以33亿并购BI(商业智能系统)厂商Hyperion(海波龙)再次将这一哲学进行了演绎。虽然Oracle自身在BI领域排名也在第7位,但是Oracle对自己的BI产品却不是非常的重视,所以Oracle的数据库产品夹带了BI系统老大BO(Business Objects)的产品。通过这种强强的联合,牢牢的把握住了用户。在这种强强联合中,Oracle给了BO唯一在所有PeopleSoft和JDEdwards应用中嵌入的BO平台的特权,而BO更是针对Oracle做深度的BI产品开发。但这种强强的合作伙伴却没有架住日益增长的BI市场对Oracle的诱惑,也没有抵御住Oracle对微软SQL Server附带BI产品的担心。 复杂的BI市场关系 BI市场现在已经成为一个非常庞大的市场。在这个市场上,BO、Cognos、SAS、Hyperion等厂商都有自己独特的技术优势和市场,当然微软和Oracle也占有一席之地。不过微软进入这个市场的办法很简单,那就是在SQL Server 2005里整合BI插件,虽然不直接卖BI系统,通过整合却占领了部分BI的市场。这个招数对数据库老大Oracle也构成了一定的威胁,原有的通过与BO合作来把握用户的策略由于双方的利益不同而出现了裂痕。Oracle自己构建BI也就是迟早的事情。为此,Oracle早前收购了Sigma Dynamics公司,以增强Oracle商业智能BI套件以及Oracle Fusion中间件的功能。面对Oracle对与BO合作关系的逃离,BO自然没法自己发展数据库对抗,唯一的方式就是加强自己在BI领域的绝对优势和客户占有率,BO能做的最好方式就是收购或者合并。Oracle要做BI需要收购专业BI厂商,BO扩大客户占有率也需要收购或者并购专业BI厂商。这就使得BI的前五位厂商有了一个机遇。 资本才最有说服力 对于BI市场的前五位来说,Hyperion是比较特殊的一个。他在企业绩效管理开发上具有技术优势,但是他的战略合作伙伴是SAP(当然也有IBM),这点跟Oracle倒是竞争对手。基于竞争的角度,对企业绩效管理的看好以及对整合BI进入自己产品系列的决心,Oracle对Hyperion是势在必得。虽然此前BO与Hyperion已经在并购上经历了漫长的磋商,但是资本的诱惑,33亿美元的真金白银还是说服了Hyperion,BO只得败下阵来。Oracle满意的将Hyperion收入囊中,Hyperion也高兴的以超出自身市价21%的价码满意而归,而BO也只能感叹资本的不足。BO在收购后发表的声明颇有意味。 “Business Objects公司一直位居国际商务智能市场的领导地位。如今排名第七位的公司Oracle并购了市场排名第四位的企业Hyperion丝毫不会改变Business Objects的领导地位。对于Oracle来讲,BI不过是数据库或应用软件的附属产品,而客户真正需要的是能够处理关键任务的BI,以帮助他们掌握对任何厂商提供的数据库以及各种应用的深刻洞察,因为他们工作在一个兼收并蓄的异构环境之中。Business Objects公司是唯一能够提供企业级BI解决方案的公司,与此同时这些产品方案具有开放性(就数据库、中间件、应用等产品而言)、广泛性(含盖了几乎全部对BI的需求,从数据质量管理到绩效管理) 以及整合性(统一在单一的平台—BusinessObjects XI之上)等特点。” 这个意味表明了BO与Oracle的合作关系将可能走向尽头,甚至BO会投靠到Oracle敌人的阵营。如果真的是这样,相信SAP与IBM乐于成为BO新的合作伙伴,虽然SAP与IBM都有自己比较成形的BI系统。 BI似乎遥远的市场 BI不仅对于老百姓,且对于IT人士也是一个非常陌生的名词。而33亿美元相当于250多亿人民币,这如果发生在中国那也是惊天的大事,至少是分众收购好耶的15倍,但在国外却不是太大的事情。中国市场在全球IT市场份额由此可见一斑。我们的信息化水平现在在很低的水平,应用水平就更低了。甚至我们熟知的IT网站用到了自动化业务管理系统的都少之又少。希望国内的厂商正视自己的差距,注重自身的技术含量,没有自己的独有技术,资本一进入就只有被淘汰。 本文转自驳客:站在真理的对面博客51CTO博客,原文链接http://blog.51cto.com/fangsheng111/19363如需转载请自行联系原作者 驳客

资源下载

更多资源
腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册