??xml version="1.0" encoding="utf-8" standalone="yes"?> 在大部分的MMOG中,游戏对象的类型都大同异Q主要有物品、生物、玩家等。比如在wow中,通过服务器发下来的GUID我们可以?jin)解刎ͼ游戏中?大类对象Q包括物?Item)、背?Container)、生?Unit)、玩?Player)、游戏对?GameObject)、动态对?DynamicObject)、尸?Corpse){?/p>
在mangos的实CQ对象用类l承的方式,由O(jin)bject基类定义游戏对象的公有接口及(qing)属性,包括GUID的生成及(qing)理、构造及(qing)更新UpdateData数据的虚接口、设|及(qing)获取对象属性集的方法等。然后分Z(jin)两类z对象Q一是ItemQ另一是WorldObject。Item即物品对象,W(xu)orldObject思义Qؓ(f)世界对象Q即可添加到游戏世界场景中的对象Q该对象cd定义?jin)纯虚接口,也就是不可被实例化,主要是在Object对象的基上又d?jin)坐标设|或获取的相x口?/p>
Itemcd又派兵出?jin)一cBag对象Q这是一U特D的物品对象Q其本nh物品的所有属性及(qing)Ҏ(gu)Q但又可作ؓ(f)新的容器cdQƈh自己Ҏ(gu)的属性和Ҏ(gu)Q所以实C采用?jin)派生。mangos在实现时对Bag的类型定义做?jin)点技巧,Item的类型ؓ(f)2QBag的类型ؓ(f)6Q这样在通过位的方式来表C类型时QBagcd也就同时属于Itemcd?jin)。虽然只是很的一个技巧,但在很多地方却带来了(jin)极大的便利?/p>
从WorldObjectz出的cd有好几U了(jin)QUnit、GameObject、DynamicObject和Corpse。Unit为所有生物类型的基类Q同W(xu)orldObject一P也不可被实例化。它定义?jin)生物类型的公有属性,如种族、职业、性别、生命、魔法等Q另外还提供?jin)相关的一些操作接口。游戏中实际的生物对象类型ؓ(f)CreatureQ从UnitzQ另外还有一cL生对象Player为玩家对象。Player与Creature在实C最大的区别是玩家的操作由客L(fng)发来的消息驱动,而Creature的控制是p己定义的AI对象来驱动,另外Player内部q包括了(jin)很多的逻辑pȝ实现?/p>
另外q有两类Ҏ(gu)的CreatureQPet和TotemQ其对象cd仍然q是生物c,只是实现上与?x)有些特D的东西需要处理,所以在mangos中将其作为独立的zc,只是实现上的一点处理。另外在GameObject中也实现有派生对象,最l的l承关系图比较简单,׃ȝ(ch)地去d?jin)?/p>
从我所?jin)解的早期游戏实现来看,大部分的游戏对象l构都是采用的类DU方式。可能与早期寚w向对象的理解有关Q当面向对象的概念刚出来Ӟ大家认ؓ(f)l承是面向对象的全部,所以处处皆对象Q处处皆l承?/p>
cd现的是一U封装,虽然从云风那里出来的弃C++而{投C的声韛_能会(x)影响一部分人,但是Q用什么语a本n是个h喜好?qing)团队整体情况决定的。我们所要的也是最l的实现l果Q至于中间的步骤Q完全看个h。还是用云风的话_(d)q只是一U信仰问题,我依焉用我所熟?zhn)的C++Q下面的描述也是如此?/p>
随着面向对象技术的深入Q以?qing)泛型等概念的相l提出,软gE序l构斚w的趋势也有了(jin)很大改变。C++大师们常说的话中有一句是q样说的Q尽是采用组合而不是ѝ游戏对象的实现也有cM的{变,向于以l合的方式来实现游戏对象cdQ也是实现一个通用的entitycdQ然后以脚本定义的方式组合出不同的实际游戏对象类型?/p>
描述的有些抽象,具体实现下一来仔细探讨下?br> 关于实体消息的内容之前讨Z件机制的时候做q一点说明,其实q也是按接口调用和按消息驱动的区别Q现在mangos的做法是完全的接口调用,所以引擎内部就没有M的实体消息。实体代码实现和实体理器是我们重点要讨论的内容?/p>
另有一文章也提到?jin)用类l箋的方式实现游戏对象的两大问题Q一是它要求pȝ中的所有对象都必须从一个v点衍生而成Q也是说所有对象类在编译的时候已l确定,q可能是一个不受欢q的限制Q如果开发者决定添加新的对象类Q则必须要对基类有所?jin)解Q方能支持新cR另一个问题在于所有的对象c都必须实现同样的一些底层函数?/p>
对于W二个问题,可以通过接口l承的方式来避免基类的方法太多。在mangos的实C采用了(jin)cM的方法,从Object虚基cL生的Unit和W(xu)orldObject仍然q是不可实例化的c,q两U对象定义了(jin)不同的属性和Ҏ(gu)Q分来实C同类型的对象。在游戏内部可以Ҏ(gu)对象的实际类型来Object指针向下转型为Unit或WorldObjectQ以调用需要的接口。方法虽然不够OOQ也q能解决问题。但是第一个问题是始终无法避免的?/p>
所以我们便有了(jin)通用实体q么一个概念,其主要方法是原来基cȝ接口q行分类Q分C个个不同的子cMQ然后以对象l合的方式来生成我们所需要的实际游戏对象cd。这个组合的q程可以通过脚本定义的方式,q样便可以在q行时生成ؓ(f)同的对象cdQ也p决了(jin)上面提到的第一个问题?/p>
通用实体的实现方法在目前的游戏引擎及(qing)开源代码中也可以看到媄(jing)子。一个是BigWorldQ从提供的资料来看,其引擎只提供?jin)一个entity游戏对象Q然后由游戏内容实现者通过xml和python脚本来自由定义不同类型的entitycdQ每U类型可有不同的property和不同的Ҏ(gu)。这样原来由基类定义的接口完全{Ud脚本定义Q具有非常强的灵zL?/p>
另外q有一个是CEL中的entity实现。按照CEL的描qͼentity可以是游戏中的Q意对象,包括玩家可交互的对象Q如钥匙、武器等Q也可以包括不能直接交互的对象,如游戏世界,甚至d链中的一部分{。entity本nq没有Q何特性,具体的功能实现需要靠附加property来完成。简单来_(d)property才定义了(jin)entity可以做什么,至于该怎么做,那又是依靠behavior来定义。所以,最l在CEL中一个游戏对象其实是由entityl合?jin)多个property?qing)多个behavior而生成的?/p>
但是CEL中的property与BigWorld中的property意义不大一P在CEL中可定义的property其实是引擎内部要先提供的Q比如其CZ中所丄pcobject.mesh、pcmove.linear、pctools.inventory{,而BigWorld中的property是完全的自由定制。从q个角度来讲Q其实可以把CEL中的property看作是游戏的逻辑pȝQ也是我们上面所描述的,接口分类后所定义的子cR?/p>
由引擎内部提供可选择的property与BigWorld所采用的完全自由定制property其实本质上是相同的。在用BigWorld实现的游戏中Q也不可能ؓ(f)每种游戏对象cd都完全从头定义propertyQ基于代码利用的原则Q也?x)先定义一些小c,然后在entitycd定义时以自定义property的方式来包含q些类。当?dng)我没有用过BigWorldQ上面的描述也只是基于游戏实现的大原则所做出来的?/p>
描述的依然有些抽象,我们可以用wow?qing)mangos代码来说明一下。mangos中ؓ(f)object定义?jin)一个属性集合,Ҏ(gu)对象cd的不同,q个属性集的大及(qing)保存数据也会(x)有差异,另外游戏对象内部含有处理不同游戏逻辑的系l,如RestSystem、FloodFilterSystem、VariousSystem{等Q在player.h中以接口l的方式q行定义?/p>
如果要将q种l构改ؓ(f)我们描述的通用entitypȝQ可以让object只提供property注册和删除的接口Q这里的property定义与CEL中的相同Q放在mangos中也是上面说的RestSystem、FloodFilterSystem、VariousSystemq些。然后也通过xml文g的方式定义我们所需要的游戏对象cdQ如player,creature,item{,不同的对象类型可以选择加蝲不同的propertyQ加载的原则是需要哪些功能就加蝲哪些property?/p>
对象的定义按上面的方法完成后Q对象的实现也需要做一些修攏V以前客L(fng)的消息是直接交由player来处理,AI也是直接调用creature的接口来完成一些功能,现在通用的entity内部已经没有M可用的方法,所有的实现都{C(jin)property中,所以需要由各个property实现自己来注册感兴趣的事件及(qing)消息Qentity实现一个消息的转发Q{l对此感兴趣的property来处理。其余的实现没有什么不同了(jin)?/p>
当然Q我们再做一Ҏ(gu)展,让property不光由引擎来提供Q用脚本本n也能定义propertyQƈ且可以通过xml来注册这些propertyQ这样便实现?jin)与BigWorld一L(fng)完全自由Ҏ(gu)。这其实也就是将很多用C++实现的功能{Ud?jin)python中,q种做法可作为参考,但不一定对所有h合适,臛_在我看来Q这L(fng)实现也基本只能由E序员来做,所以让E序员选择自己最擅长的语a可能?x)更易于开发和调试?/p>
有关游戏对象实现的描qͼ前面两篇文章中说的不甚清楚,主要是一直都要引用网上能够找到的资料来进行描qͼ以避免与公司引v不必要的ȝ(ch)。所以语a有些拼凑的感觉,丄例子也很不恰当,今天正好看到?jin)游戏编E精_五和六上的两篇文章Q内定w差不多,<<Zlg的对象管?gt;>?lt;<Zlg的游戏对象系l?gt;>Q说的也是我上两文章想要描q的内容Q所以再补一,引用其中的部分文字进行明的说明?/p>
传统的游戏对象管理系l采用承的方式来实玎ͼ例如Q所有的子类都从CObjectz。大多数情况下,直接z的也是抽象类Q其中带一些功能而另一些子cd不带q些功能Q比如可控制/不可控制Q可动画/不可动画{。mangos的实C基本是q种情况Q从Object直接z的Unit和W(xu)orldObject都是不可直接实例化的cR?/p>
传统Ҏ(gu)的问题在于无法应寚w求的变化Q如要求武器也有动画效果时就无法处理?jin)。如果硬要是q样做,那随着需求的啬,很多的方法会(x)被放到基cMQ最l的l果是承树(wi)变得来头重脚轻,q样的类?x)失它的内聚性,因ؓ(f)它们试图为所有对象完成所有的事?/p>
是说到最后,基类?x)有一个很长的接口列表Q而很多的游戏对象cdҎ(gu)不需要实现其中的一些甚臛_部分接口Q但是按照这U结构却又必d实现。以至于于实C个非常庞大的对象Q而且惌修改一点功能会(x)Dpȝ的大调整?/p>
我们希望的系l是可以现有的功能l合到新的对象中Qƈ且在新的功能添加到现有的对象中时不需要重构大量的代码和调整承树(wi)的结构?/p>
实现的方法就是从lg来创Z个对象。组件是一个包含所有相x据成员和Ҏ(gu)的类Q它完成某个特定的Q务。把几个lgl合在一起就可以创徏一个新的对象。如把Entitylg、Renderlg和Collectablelgl合在一L(fng)成了(jin)一个Spoon对象。Entitylg让我们可以把对象攑ֈ游戏世界中,Renderlg让我们可以ؓ(f)对象指定一个模型进行渲染,而Collectablelg让我们可以拾取这个对象?/p>
关于lg的实玎ͼ所有的lg都从一个基lg接口zQ可U其为IComponent。每个组件也有自q接口定义Qƈ且这个接口也需要从IComponentzQ类gq样QIComponent -- ICmpRender -- CCmpRender q里的每个组件也是我在上一中所说的由引擎提供的属性,或者说在BigWorld中自己实现然后定义的属性,或者用mangos中的定义Q就是一个个的SystemQ虽然mangosq没有将其完全做成组Ӟ但是通过其代码注释可以看刎ͼ接口也是按功能组q行?jin)分c,如果要拆分成lg也是比较方便的?/p>
lg之间的通信有两U方法,一是用lgID查询到组件接口指针,然后调用接口Ҏ(gu)Q二是用消息的方式Q向对象中所有组件发消息。在初始化的时候,每一个组件类型都?x)告诉对象管理器应该接收什么样的消息?/p>
查询接口的方法也是直接的方法调用,只不q接口不是全部在基类中,所以必d查询到指定的lg然后才能调用其接口。消息的使用前面已经说过多次Q其实现Ҏ(gu)也有q说明?/p>
最后是关于游戏对象功能的扩展和游戏对象的定义。需要扩展功能也是需要实C个新的组Ӟ或者修改现在组件。在大多数情况下Q扩展都不会(x)引vl构的很大调_(d)受媄(jing)响的最多只是用到该组件的部分代码?/p>
游戏对象定义可采用完全数据驱动的方式Q用xml或者脚本语a来定义对象类型,以及(qing)每个cd需要加载的lg。对象类型注册到对象理器后Q由理器提供创建指定类型的对象的方法。数据驱动的方式能够让策划自由定义游戏对象类型,q且随时可自由创建新的对象类型?/p>
一、服务器l模型的选型 二、MMORPG服务器系l架?/p>
MMORPG大型|游服务器是使用高性能|络I/O模型配合消息队列q接各服务线E的一个非常稳定的高性能|游pȝ。其中消息队列系Z׃n内存自行开发完成。在单服务器标准工作环境下进行测试,一台双 XEON 服务器可以非常轻村֜辑ֈ?,500用户每秒处理5,000hQ每U处理请求数可超q?25,000?/p>
三、MMORPG的实?/p>
首先Q在基础斚wQ与规划现实中的城市(jng)一P得先搭徏起一pd的房屋、道路及(qing)出口、管U和诸多NPC人物{构成的基本要素和活动空_(d)通过在服务器?Server side)取得预先设计好的l合地理、NPC人物、技能等一pd的初始化数字数据(具体文档片段误附gA.地图数据文gCZ和附件B.司机 NPC 数据文gCZ)Q然后依靠程序将数字数据和游戏逻辑有机地协调v来,最lŞ成一套完整的虚拟游戏基础I间?/p>
在确定了(jin)地图数据生成规则后,可以用编辑器L~辑游戏场景。依赖于q样良好的基设施Q才能在其他游戏逻辑的配合下实现完整的故事情节。同时服务器端负责将属于用户各自的游戏逻辑数据通过验证后发送到合法的用户客L(fng)机器里,完成客户端游戏逻辑的徏立和数据同步。担负服务器与客L(fng)通讯的是自定义格式的数据通讯包Q它?yu)像数字经般诏I着整个游戏的始l。数据封包与如下4部分消息有关Q它们分别ؓ(f)场景消息, 同步消息Q主角消息和界面消息?/p>
A.主角消息包括客户端所控制的角色的所有动作,包括走\Q聊天、交易、战斗等?br> B.场景消息包括昼夜兴替、气候变化,一定的旉在场景里出现某些东西{,q类消息h的特Ҏ(gu)所有消息的发v者都是服务器Q广播对象则是场景里的所有玩家?br> C.同步消息是针对发起对象是某个玩家Q经q服务器q播l所有看得见他的玩家Q该消息也包括所有的动作Q该U消息是服务器广播给客户端的Q主角消息则一般是客户端主动发l服务器端?br> D.界面消息是服务器发给客户端的聊天消息和各U属性及(qing)状态变化的信息?/p>
值得一谈的q有处于|络游戏中比较重要的服务器同客户端消息广播和同步问题。其中一U方法是采取在国际上被称?Mutual synchronizationQ相互同步)(j)Q是一U对未来|络的前景的良好预测出来的解x案来解决保每个玩家在各自客L(fng)上看到的东西大体是一L(fng)同步问题?/p>
首先客户端需要在d游戏的时候徏立很多张q播列表Q这些列表在客户端后台和服务器端要保持不定时同步。其中要建立多张列表Q是因ؓ(f)要广播的cd包括全局信息、本C息和q程信息{等Q这些列表都是在客户端登陆的时候根据服务器发过来的消息建立好的。在建立列表的同Ӟq需要获得每个列表中q播对象的传输时_(d)q且要维护一张完整的用户状态列表在后台Q也是进行不定时的和服务器进行同步,Ҏ(gu)本地的用L(fng)态表Q可以一部分决策由客L(fng)来决定,当客L(fng)发送这部分决策的时候,则直接将最l决{发送到各个q播列表里面的客L(fng)Qƈ对其旉q行校对Q以保证每个客户端在收到的消息的旉是和本地旉q行校对q的Q再采用预测补偿计算提前量的Ҏ(gu)Q计出提前量,Ҏ(gu)计算量确定实际行走速度Q将?x)同步变得非常的^滑?/p>
其中Q广播的重点在于如何计出q播的对象,首先在服务器端的q接l构里面增加一个广播对象的队列Q该队列在客L(fng)登陆服务器的时候由服务器传输给合法的客L(fng)Q然后由客户端自己来l护q个队列Q当有h走出客户端视野的时候,由客L(fng)d要求服务器给那个对象发送消q消息?/p>
当有q视野的情况Q则先需要客L(fng)在每ơ给服务器发送更C|的消息的时候,服务器都l该q接出一个视野范_(d)然后在需要广播的时候,循环整张地图上的玩家Q找到坐标在其视野范围内的玩家从而完成广播的全过E?/p>
其次是虚拟对象系l。其中主要会(x)涉及(qing)到NPC的概念,其是广泛应用的A Star法{在提供NPC的h工智能决{方面有着重要的作用。NPC使用一U是被动触发事g和是d触发事g的方式由计算机来实现对NPC做何U决{。A Star法是典型的启发式搜烦(ch)的应用,其普通原理是先设计一个Rule() 函数Q来莯一个点的代P然后每次搜烦(ch)的时候把下一步可能到辄所有点都经qRule() 函数评h(hun)一下,获取两到三个代h(hun)比较?yu)的点,l箋搜烦(ch)Q直臛_Ch的一个点。最明显的应用是NPC在实现自动选择d目标和逃跑时的实现。实现自动选择d目标Ӟ首先获得地图上距该NPC附近的敌人列表,设计相应Rule() 函数Q根据敌人的强弱、远q,判断出几个评估数据,然后选择代h(hun)最的敌hq行dd。逃跑则是在主动事仉面检查自qHPQ如果HP低于某个|而敌人正q战d的时候,则触发逃跑函数Q在逃跑函数里面也是对周围的所有的敌hl织成列表,然后设计Rule() 函数Q先分析选择出对你构成威胁最大的敌hQ该函数q需要判断敌人的q动速度Q战斗力强弱Q最后得Z个主要敌人,然后针对该主要敌行\径的Rule() 的函数的设计Q搜索的范围只可能是和主要敌人相反的方向Q然后再Ҏ(gu)该几个方向上的敌人的强弱来计代P做出最后的选择Q如果幸q的话,可以?0%的机率逃往没有 NPC L的邻q地图中厅R?/p>
最后,׃脚本是RPG游戏的灵,自然脚本~译器就扮演?jin)十分重要的C。在Z~译的服务器端程序中Q是无法在程序的q行q程中构Z些东西的Q所以必通过脚本~译器提供一些简单的语法和文法解析的功能Q进行一pd的逻辑判断和@环,以提高服务器端的灉|E度。可使用cM汇编语言的那U结构来实现脚本~译器,讄一些条件蟩转和循环来实现逻辑判断和@环。提供一些通用指o(h)Q如判断、@环、四则运、寻址{等Q针对不同的脚本采用不同的解析方法,对NPCqNPC固定的脚本,对ItemqItem固定的脚本,解析完以后就把结果生成底层该对象的结构便于用?/p>
l过以上的徏设步骤,一个完整的MMORPG|络游戏pȝp逐步建立h?jin)?/p>
在游戏编E精_四有三文章讲C(jin)实体以及(qing)实体理的实现方案,其中一文章说C(jin)实体理pȝ的四大要素:(x)定义实体怎样沟通的实体消息Q实C实体cM码和数据的实体代码,l护已经注册在案的实体类列表Q和用来创徏、管理、发送消息的实体理器?/p>
]]>
d分配服务器:(x)游戏区唯一入口点,Ҏ(gu)d服务器负载和排队情况Q分配登录玩家到指定d服务器中q行dQ?br>d服务器:(x)处理玩家验证w䆾合法性,?qing)游戏选游戏世界操作,控制服务器h敎ͼ
数据服务器:(x)处理玩家数据dQ保存和~存的地方;
世界服务器:(x)整个游戏旉的中?j)管理数据的服务器?
游戏服务器:(x)处理玩家主逻辑的服务器Q?
道具服务器:(x)处理所有直接道L(fng)关逻辑的服务器Q管理道L(fng)产生消亡Q交易,合成Q升U,{操作;
|关服务器:(x)提供l玩家与游戏服务器的中{服务器,玩家一旦登录游戏,始终处于一个网x务器Q?br>聊天服务器:(x)提供更丰富的聊天形式Q消息优化,转发?br>中心(j)验证服务器:(x)与登录服务器通信Q主要进行玩家n份验证,?qing)反馈用户信息?br>中心(j)计费服务器:(x)充|扣费Q交易操作的处理?/p>
本文来自CSDN博客Q{载请标明出处Q?a >http://blog.csdn.net/olncy/archive/2008/12/15/3520572.aspx
考虑到近q来计算机硬件技术的飞速发展,物理服务器的性h(hun)比得C(jin)很大的提高,l合目需要通过服务器组l数万玩家提供高质量服务的商业要求,l过研究Ҏ(gu)数种服务器模型后Q决定采取了(jin)上图所C的服务器组模型?/p>
from: http://bbs.luaer.cn/read-Lua-tid-233.html
环境Qlua for windows (lfW)
主页Q?a >http://luaforwindows.luaforge.net/
lua for windows其实是一整套Lua的开发环境,它包括:(x)
Lua InterpreterQLua解释器)(j)
Lua Reference ManualQLua参考手册)(j)
Quick Lua Tour QLua快速入门)(j)
Examples QLua范例Q?br>Libraries with documentation Q一些Lua库和文档Q?br>SciTE Q一个很的多用途编辑器Q已l对Lua做了(jin)Ҏ(gu)讄Q?/p>
其它详细的内容请到l(f)uaforge的主上查看?/p>
之所以推荐这套环境是因ؓ(f)它整合了(jin)在windows学习(fn)和开发Lua所需要的所有东?/p>
Q对于新手来说是非常体脓(chung)的,附带的SciTE只要l过单配|就能够很方便的~?/p>
写LuaE序Q编译,q行Q调试。它q是附带自动提示和代码自动补全功能的哦,
对于用惯VC + VA的开发h员来_(d)实在是太亲切?jin)?/p>
下面介绍一下整个lfWQ?br>下蝲lfwQ最新的版本?.1.3.13Q直接安装,注意最后一步会(x)询问SciTE~辑?/p>
是否使用“黑色”风格Q我比较喜欢黑色底色Q所以在q里打钩Q之后l?br>安装完成后,学习(fn)Lua所需要的一切环境就全部安装完毕Q十分简单?/p>
下面可以试是否安装成功
打开SciTEQ新Z个文Ӟ输入一行lua代码Q?/p>
print("hello,lua")
然后保存为hello.luaQ注意保存文件时要加文g名后~.luaQ否则可能不能正?/p>
的运行?br>按F5Q如果SciTE的输出窗口出?br>>lua -e "io.stdout:setvbuf 'no'" "hello.lua"
hello,lua
>Exit code: 0
字样则代表整个lua开发环境安装成功?/p>
如果对SciTE默认的配色方案或者字体不满意Q点凅ROptions】菜单中的【Open
Global Options File】,则可以看到SciTE环境的全局配置文g。里面可以修?/p>
的包括字体,颜色Q窗口布局{等Q修改相应的值即可。如果找不到自己惌?/p>
改的目Q可以再到【Options】的【Open black.properties】(如果使用的是
白色背景Q这里则是white.propertiesQ文件中查找Q这里存储的是更加细致的
属性配|。修改这两个文gQ基本上p够满_部分学习(fn)或是开发者的个h?/p>
好。还有一点,在Global Options File中,查找command.help.*.luaQ后面对?/p>
的是在编辑器中按下F1键弹出的chm格式的lua手册文g路径Q这里需要修改一?/p>
Q把文g路径Ҏ(gu)就可以?jin)?.1.3版本g没这个问题了(jin)Q?/p>
整个环境q附带一个QuickLuaTourQ是一个用Lua写的一个基于控制台的小教程Q?/p>
很易于理解?/p>
基本上整个环境就是这P之后可以开始学?fn)Lua?jin)?/p>
在上一文章中Q介l了(jin)一U基于组件方式的游戏UI架构设计Ҏ(gu)Q在q里Q笔者将介绍如何利用CEGUI和Lua来实现这U灵zȝ框架?/p>
控制语句 | 格式 | CZ |
If | if 条g then ... elseif 条g then ... else ... end |
if 1+1=2 then print("true")
elseif 1+2~=3 then print("true") else print("false") end |
While | while 条g do ... end |
while 1+1~=2 do print("true") end
|
Repeat | repeat ... until 条g |
repeat print("Hello") until 1+1~=2
|
For | for 变量=初? l点? 步进 do ... end |
for i = 1, 10, 2 do print(i) end
|
For | for 变量1, 变量2, ... 变量n in 表或枚D函数 do ... end |
for a,b in mylist do print(a, b) end
|
比较W号 | < | > | <= | >= | == | ~= |
含义 | 于 | 大于 | 于或等?/td> | 大于或等?/td> | 相等 | 不相{?/td> |
or and < > <= >= ~= == .. (字符串连? + - * / % not #(lua5.1 取长度运?/span>) - (一元运? ^ |
and | break | do | else | elseif | |
end | false | for | function | if | |
in | local | nil | not | or | |
repeat | return | then | true | until | while |
Nil | I|所有没有用过的变量,都是nil。nil既是|又是cd?/td> |
Boolean | 布尔|只有两个有效|(x)true和false |
Number | 数|在Lua里,数值相当于C语言的double |
String | 字符Ԍ如果你愿意的话,字符串是可以包含"\0"字符的(q和C语言L?\0"l尾是不一L(fng)Q?/td> |
Table | 关系表类型,q个cd功能比较强大Q请参考后面的内容?/td> |
Function | 函数cdQ不要怀疑,函数也是一U类型,也就是说Q所有的函数Q它本n是一个变量?/td> |
Userdata | 嗯,q个cd专门用来和Lua的宿L交道的。宿主通常是用C和C++来编写的Q在q种情况下,Userdata可以是宿ȝL数据cdQ常用的有Struct和指针?/td> |
Thread | U程cdQ在Lua中没有真正的U程。Lua中可以将一个函数分成几部䆾q行?/span>如果感兴的话,可以ȝ看Lua的文档?br>现在回过头来看看Q倒觉得不是线E类型。反而象是用来做遍历的,象是Iterator函数?br>如:(x) function range(n)
可惜的是要l运行,需要coroutine.resume函数Q有炚w肋。请指教?br>local i = 0 while(i < n) do coroutine.yield( i ) i = i + 1 end end |
转蝲Q?http://www.d2-life.com/LBS/blogview.asp?logID=41
使用Lua作脚本,主要是因为它?yu)y玲珑Q体U小Q运行快Q,而且它的语法又比较简单明?jin)。不q,使用LuaAPILua引擎集成到程序中Q确实有一些不方便——用落木随风|友的话来说Q就?p用汇~?。当?dng)现在你不用再q么辛苦?jin),因?f)你可以用LuaWrapper For C++。用这个工P在C++中集成Lua脚本是轻而易丄事。你原有的C++函数和类Q几乎不需要Q何改变,可以与Lua脚本׃n?br>
作者:(x) 沐枫 Q第二h生成员)(j)
版权所有{载请注明原出?br>主页Q第二h?http://www.d2-life.com
http://www.d2-life.com/LBS/blogview.asp?logID=41
Z么要用Lua作脚本?
使用Lua作脚本,主要是因为它?yu)y玲珑Q体U小Q运行快Q,而且它的语法又比较简单明?jin)。不q,使用LuaAPILua引擎集成到程序中Q确实有一些不方便——用落木随风|友的话来说Q就?p用汇~?。当?dng)现在你不用再q么辛苦?jin),因?f)你可以用LuaWrapper For C++。用这个工P在C++中集成Lua脚本是轻而易丄事。你原有的C++函数和类Q几乎不需要Q何改变,可以与Lua脚本׃n?br> 我们接下来,用实例来说明Q如何用LuaWrapper来集成Lua脚本C的程序中厅R?br>
1. 创徏Lua引擎
LuaWrap lua; 或?LuaWrap* lua = new LuaWrap;
创徏一个LuaWrap对象Q就是创Z个Lua脚本引擎。ƈ且根据Lua的特性,你可以创ZQ意多个Lua引擎Q甚臛_以分布在不同的线E当中?br>
2. 装蝲q执行脚本程?br> 你可以从~冲Z装蝲Lua脚本Q?br> lua.LoadString(
"print('Hello World')"
);
当然Q你也可以从文g中装入,q执行Lua脚本Q?br> Lua.LoadFile("./test.lua");
Lua的脚本,可以是源代码Q也可以l过~译后的中间代码。也怽对编译后的中间代码更感兴——如果你不希望让源代码赤裸裸的袒露在大家的眼前?br>
3. 获取和设|Lua变量
能够获取和设|脚本变量的内容Q是一个最基本的功能。你可以使用GetGlobal和SetGlobal函数来做到这一点:(x)
(1) 获取变量Q?br> int a = lua.GetGlobal<int>("a");
LuaTable table = lua.GetGlobal<LuaTable>("t");
q里Q?lt;> 里头的类型,是惌的变量的cd?br> (2) 讄变量Q?br> lua.SetGlobal("a", a);
lua.SetGlobal("t", table);
4. 调用Lua函数
使用Call函数Q就可以很简单的从你的程序中调用Lua函数Q?br> lua.Call<void>("print", "Hello World");
int sum = lua.Call<int>("add", 2, 3);
q里Q?lt;> 里头的类型是q回值的cd?br>
5. 如何让Lua也能调用C++的函?br> _N的地Ҏ(gu)?jin)。假如有下面q样的一个函敎ͼ(x)
int add(int a, int b)
{
return a + b;
}
如果惌它能够让Lua使用Q只需它注册到Lua引擎当中可以了(jin)Q?br> lua.RegisterFunc("add", int(int,int), add);
q样QLua中就可以用直接用了(jin)Q?br> QLua脚本Qsum = add(1, 3)
(*) RegisterFunc的功能,是让你把C++的函数注册到Lua中,供Lua脚本使用?br> W一个参敎ͼ是想要在Lua中用的函数名?br> W二个参敎ͼ是C++中函数的原型Q?C++允许函数重蝲的,你可以用函数原型,来选择需要注册到Lua引擎中的那个函数?br> W三个参敎ͼ是C++中函数的指针?jin)?br>
6. 如何能让C++的类在Lua中?br> 我们先看看下面这个C++c:(x)
class MyArray
{
std::vector<double> array;
public:
void setvalue(int index, double value);
double getvalue(int index);
int size();
const char* ToString();
};
你准备要让Lua能够自由讉Kq操作这个类。很单,你只需增加几个宏定义就可以?jin)?x)
class MyArray
{
std::vector<double> array;
public:
void setvalue(int index, double value);
double getvalue(int index);
int size();
const char* ToString();
// 一?class 作ؓ(f)一?Lua 对象是很Ҏ(gu)的,只需要增加以下宏定义?br> DEFINE_TYPENAME("My.array");
BEGIN_REGLUALIB("array")
LUALIB_ITEM_CREATE("new", MyArray ) // 创徏MyArray
LUALIB_ITEM_DESTROY("del", MyArray ) // 消除MyArray?br> END_REGLUALIB()
BEGIN_REGLUALIB_MEMBER()
LUALIB_ITEM_FUNC("size", int (MyArray*), &MyArray::size)
LUALIB_ITEM_FUNC("__getindex", double(MyArray*, int), &MyArray::getvalue)
LUALIB_ITEM_FUNC("__newindex", void (MyArray*, int, double), &MyArray::setvalue)
LUALIB_ITEM_FUNC("__tostring", const char* (MyArray*), &MyArray::ToString)
LUALIB_ITEM_DESTROY("__gc", MyArray ) // 垃圾攉时消除对象用?br> END_REGLUALIB_MEMBER()
};
只要有了(jin)q些宏定义,q个cd是可以在Lua中用的cM(jin)Q我们就可以在Lua中注册这个类?jin)?x)
lua.Register<MyArray>()
q样注册以后Q我们在Lua中就可以使用q个cM(jin)Q?br> a = array.new() -- 创徏对象Q相当于 a = new Myarray
a[1] = 10 -- 调用__newindexQ也是C++中的 a->setvalue(1, 10)
a[2] = 20 -- 调用__newindexQ也是C++中的 a->setvalue(2, 20)
print(
a, -- 调用 __tostringQ也是C++中的 a->ToString()
a:size(), -- 相当于C++中的 a->size()
a[1], -- 调用__getindexQ也是C++中的a->getvalue(1)
a[2]) --调用__getindexQ也是C++中的a->getvalue(2)
array.del(a) -- 清除对象Q相当于 delete a
a = nil -- 清空 aQ很象C++中的 a = NULL
当然Q你也可以不用delq个对象Q而是{待Lua帮你自动q行垃圾回收。在Luaq行垃圾回收Ӟ它会(x)自动调用q个对象?__gc Q相当于 delete?br>
那么Q在C++中要创徏MyArray对象Qƈ且传递给Lua全局变量怎么办?p前面讲过的一P使用SetGlobalQ?br> MyArray* a = new MyArray;
lua.SetGlobal("a", a);
要获取该对象Q同L(fng)Q应该用GetGlobalQ?br> MyArray* a = lua.GetGlobal<MyArray>("a");
对于传递给Lua的对象,pLua来管理该对象的生存周期好?jin)。如果你非要删除它的话,你可以用DelGlobalObjectQ?br> lua.DelGlobalObject<MyArray>("a");
不过q么做的话,你应当明白你在做什么,因ؓ(f)在Lua的脚本中Q可能已l在多处引用?jin)这个对象?jin)。删除了(jin)其中一个,导致其它引用对象失效,从而可能引致系l崩溃?br>
(1) DEFINE_TYPENAME("My.array");
定义cd的名U。在Lua中,q个cd名称是唯一用来识别C++cd的,你必Mؓ(f)不同的对象给予不同的名称?br>
(2) BEGIN_REGLUALIB("array") ... END_REGLUALIB()
你可以ؓ(f)一个对象定义一个程序库Q?array"是E序库的名字。在E序库中定义的函数是全局函数Q在Lua中,使用该函敎ͼ需要在函数前加上库的名字,如:(x)array.newQ)(j)。通常Q程序库?x)包含创建对象的?gu)。如Q?br> LUALIB_ITEM_CREATE("new", MyArray ) // 创徏MyArray
q样子,你才能在Lua中创建MyArrayQ?br> a = array.new()
你也可以选择增加一个删除对象操作:(x)
LUALIB_ITEM_DESTROY("del", MyArray ) // 删除MyArray
q样Q你可以直接删除一个对象了(jin)Q?br> array.del(a)
(3) BEGIN_REGLUALIB_MEMBER() ...END_REGLUALIB_MEMBER()
在此处,你可以定义对象的成员函数Q也可以重蝲对象的操作符——是的,pC++的operator重蝲。例如:(x)
LUALIB_ITEM_FUNC("__newindex", void (MyArray*, int, double), &MyArray::setvalue)
是重蝲 operator[] 操作W。Lua中可重蝲的操作符q有许多Q如Q?br>
__getindexQ操作符[]Q支持读取访问,?v = a[10]
__newindexQ操作符[]Q支持赋D问,?a[10] = 1.22
__tostringQ将变量转换成字串__addQ等同于operator +
__addQ操作符 Q?br> __subQ操作符 -
__mulQ操作符 ×
__divQ操作符 ÷
__powQ操作符 ^ (乘方)
__unmQ一元操作符 -
__concatQ操作符 .. (字符串连?
__eqQ操作符 == (a ~= b{h(hun)?not a == b)
__ltQ操作符 < (a > b {h(hun)?b < a)
__leQ操作符 <= (a >= b {h(hun)?b <= aQ要注意的是Q如果没有定?__le"Q则Lua会(x)试a<=b 转换?not (b < a) )
__gcQ在垃圾回收时调用此函数Q相当于C++的析构函数。强烈徏议定义此操作W,以免造成内存泄漏{情c(din)比如:(x)
LUALIB_ITEM_DESTROY("__gc", MyArray ) // 垃圾攉时消除对象用?br>
(? q里要说明一下,在lua中,讉K索引操作W是__indexQ不是__getindexQ在luaWrapper库中Qؓ(f)?jin)方便用,其映射为__getindexQ同Ӟ对__index的定义将?x)被忽略?br>
p么简单。假如你已经有现成的c,而你没有修改该类的权力,如何其加入到Lua中呢Q答案就是,l承它,把zcd入到Lua中?br>
l束?br> LuaWrapper 需要用到boost库的支持Qboost/type_traits.hpp, boost/function.hpp, boost/bind.hppQ它使用?jin)C++的模杉K份特化,因此QC++~译器如果不支持此特性,无法编译。目前支持此Ҏ(gu)的~译器已l有很多。在VisualStudo产品pd中,只有VC7.1能支持此Ҏ(gu),因此Q?zhn)如果正在使用VisualStudioQ请认你用的是VisualStudio2003?br> 如果你觉?LuaWrapper For C++ 能够帮助你,我会(x)感觉很荣q。我很愿意将q个E序库分享给大家。顺便一提的是,如果你在使用q程中发现BUGQ或是有好的Q希望?zhn)能与我联pR你在用过E中Q请不要删除文g中的|名信息Q如果你修改?jin)程序库Q请(zhn)在修改的文件中加入(zhn)的修改说明。当?dng)我?x)非常Ƣ迎(zhn)能修改后的程序回馈给我。我?x)l优化ƈ完善它?br>
Lua 提供?jin)高U抽象,却又没失Mg的关?/p>
![]() |
U别: 初 Martin Streicher (martin.streicher@linux-mag.com), 首席~辑, Linux Magazine 2006 q?6 ?12 ?/p> 虽然~译性编E语a和脚本语a各自h自己独特的优点,但是如果我们使用q两U类型的语言来编写大型的应用E序?x)是什么样子呢QLua 是一U嵌入式脚本语言Q它非常,速度很快Q功能却非常强大。在创徏其他配置文g或资源格式(以及(qing)与之对应的解析器Q之前,请尝试一?Lua?/blockquote> |