﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-组件工厂-随笔分类-RPG游戏逻辑设计</title><link>http://www.cppblog.com/flashboy/category/6691.html</link><description>------3D游戏研发</description><language>zh-cn</language><lastBuildDate>Mon, 14 Sep 2009 15:14:01 GMT</lastBuildDate><pubDate>Mon, 14 Sep 2009 15:14:01 GMT</pubDate><ttl>60</ttl><item><title>游戏Entity设计不完全整理(转)</title><link>http://www.cppblog.com/flashboy/archive/2009/08/18/93684.html</link><dc:creator>RedLight</dc:creator><author>RedLight</author><pubDate>Tue, 18 Aug 2009 03:11:00 GMT</pubDate><guid>http://www.cppblog.com/flashboy/archive/2009/08/18/93684.html</guid><wfw:comment>http://www.cppblog.com/flashboy/comments/93684.html</wfw:comment><comments>http://www.cppblog.com/flashboy/archive/2009/08/18/93684.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/flashboy/comments/commentRss/93684.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/flashboy/services/trackbacks/93684.html</trackback:ping><description><![CDATA[<div>
<p><span><span><span>在游戏引擎中，</span><span>Entity</span><span>通常被翻译成实体，也常用诸如</span><span>GameObject</span><span>、</span><span>Actor</span><span>、</span><span>SimulationObject</span><span>、</span><span>Unit</span><span>、</span><span>Character</span><span>等名字。相比于对图像声音引擎的热情，</span><span>Entity</span><span>层多年来一直备受冷遇，但最近几年随着大型游戏的发展，</span><span>Entity</span><span>层设计的重要性已经达到和图像声音的同等水平，而且已经出现了多种通用型</span><span>Entity</span><span>架构。当然，这里伴随着争议和分歧。</span></p>
<h3><span>直接模式（</span><span>The C Approach</span><span>）</span></h3>
<p><span>这是最早、最简单、也是任何人都能直接想到的模式。这种方式下一个</span><span>Entity</span><span>就是一个简单的</span><span>struct:</span></p>
<p><span>struct Mob<br>{<br>int level, hp, mp, attack, &#8230;;<br>};</span></p>
<p><span>这种情况下往往需要对不同类型的</span><span>Entity</span><span>定义不同的</span><span>struct</span><span>，比如</span><span>Player</span><span>、</span><span>Mob</span><span>、</span><span>Item</span><span>、</span><span>Doodad</span><span>等。</span><span>Entity</span><span>的数据库可以直接使用现成的数据库系统或者从数据文件读取，比如</span><span>csv</span><span>文件。一般会选择</span><span>Excel</span><span>编辑数据库，然后导出</span><span>csv</span><span>。</span><span>Excel</span><span>的强大表格和统计计算功能是调节游戏数据平衡的得力工具。以致这种最古老而简单的</span><span>Entity</span><span>模式以强大的生命力一直活到现在。</span></p>
<p><span>那么为什么</span><span>Developers</span><span>会要去探索其他方式呢？最大的问题是这种方式下各种</span><span>Entity</span><span>完全不同质。比如</span><span>Player</span><span>、</span><span>Mob</span><span>、</span><span>Doodad</span><span>都有位置，都要做碰撞检测，但他们却是不同的类型，不能使用同一份代码；</span><span>Player</span><span>和</span><span>Mob</span><span>都有</span><span>hp</span><span>和</span><span>mp</span><span>，也有基本相同的处理逻辑&#8230;&#8230;当然，这个可以用</span><span>hack</span><span>的方法解决：只要各个</span><span>struct</span><span>前若干个成员类型和顺序完全相同，就可以将指针</span><span>cast</span><span>成统一的一个</span><span>Entity</span><span>类型来处理。不过，任何人都能想到更好的办法，用类！</span></p>
<h3><span>继承模式（</span><span>Inheritage</span><span>）</span></h3>
<p><span>这也是</span><span>Entity</span><span>、</span><span>GameObject</span><span>等这些名字的由来，他们就是基类。于是我们可以得到一颗继承关系树，例如：</span></p>
<p><span>Entity</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>Character</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>Player</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>Mob</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>Missile</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>Laser</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>GuidedMissile</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>Item</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&#8230;</span></p>
<p><span>Entity</span><span>对象的逻辑大多也是直接包含在类里的。但也有人采用了数据对象和逻辑对象的分离，其好处是对相同的数据可以替换不同的逻辑。不过，个人比较怀疑这种分离是否值得，因为类的派生本身就是可以拥有不同的逻辑。</span></p>
<p><span>另外，</span><span>Entity</span><span>间的交互除了用标准的直接访问方式外，经常使用消息模式。消息模式和</span><span>Windows</span><span>的消息模式类似，</span><span>Entity</span><span>间通过消息交互。虽说窗口编程画了多年时间才摆脱了当年肥大的</span><span>switch</span><span>的消息处理模式，在</span><span>Entity</span><span>层使用消息模式还是有意义的，因为消息很容易广播且可以直接在网络上发送。执着于</span><span>OO</span><span>的人会将消息写成</span><span>Command</span><span>对象，但原理仍然是一样的。</span></p>
<p><span>同时，联网游戏出现，指针不能在不同的机器上标识对象，我们必须用稳定的</span><span>ID</span><span>来标识对象，于是我们有了</span><span>EntityManager</span><span>来分配</span><span>ID</span><span>和管理对象集合，或者叫</span><span>GameObjectManager</span><span>、</span><span>ObjectManager</span><span>等。这在一段时期内几乎成了完美的方案。</span></p>
<p><span>随着游戏内容的丰富性的迅速膨胀，传统的由程序员来实现游戏逻辑功能的模式也越来越力不从心。脚本语言的集成将大部分创意性工作从程序员的担子上拿了下来，交还给游戏设计人员。为了给脚本提供足够的控制权，</span><span>Entity</span><span>结构上必须有充分的灵活性。</span></p>
<h3><span>数据驱动（</span><span>Data-Driven</span><span>）</span></h3>
<p><span>现在有句很流行的话，&#8220;唯一不变的是变化。（</span><span>The only constant is change.</span><span>）&#8221;数据驱动使得变化对引擎的影响最小化。数据驱动不能算是一种独立的</span><span>Entity</span><span>模式，不如说它是一种设计思想，其目的就是将内容制作和游戏引擎的制作分离开来。与上面所说的填充</span><span>Entity</span><span>属性数据库的不同之处在于，它还要能通过数据来设计游戏逻辑。</span></p>
<p><span>游戏设计人员需要的一项最基本功能就是自定义人物属性，所以与其在类里写死属性成员，不如使用属性表（</span><span>Attributes/Properties</span><span>）。通常使用一个哈希表（</span><span>Hashtable</span><span>），或者</span><span>std::map</span><span>，或者</span><span>Dictionary</span><span>，或者就是个数组，随个人喜好，其实就是要一个</span><span>key-value</span><span>的映射表。然后为脚本和编辑器提供对属性表的操作。</span></p>
<p><span>动态的逻辑主要就靠脚本了，必须为脚本提供足够的事件和方法。个人推荐用</span><span>Lua</span><span>脚本，因为它是在游戏领域内用得最多的通用脚本语言，其引擎很小、速度很快、易于集成，尽管语法过于松散。不要迷信宣传去用庞大、极慢、难于集成的</span><span>Python</span><span>。为脚本提供事件，其实也就是调用脚本里的函数，这里如果使用了前面所述的消息模式，那么就只要调用一个脚本方法，传递不同的消息参数就行了。当然也有人觉得这样很丑陋而更愿意为不同的事件注册不同的函数。</span></p>
<p><span>当有了数据驱动后，</span><span>Entity</span><span>的继承树就基本失去意义了，因为一个</span><span>Entity</span><span>是什么已经不是程序里决定的了，而是通过数据和脚本设计出来的。但数据和脚本又不是全部，一个</span><span>Entity</span><span>的核心内容和需要高效处理的部分，如碰撞检测，还是要程序来完成。于是我们需要重新设计</span><span>Entity</span><span>类，困难的局面也就由此开始。</span></p>
<p><span>一个直观的想法是一个统一且唯一的</span><span>Entity</span><span>类，它包含了所有的基本功能，如显示、碰撞检测、运动、背包等，然后由数据决定哪些组件被启用。比如一个玩家角色可能会启用绝大部分组件，而一颗树只启用显示和碰撞检测组件。但也伴随着缺点：一、这个类太大了；二、对于树木等一些简单的</span><span>Entity</span><span>也要浪费其他组件的私有数据所占的内存。那么一个简单的折中是部分使用继承、部分使用数据定制。例如</span><span>Entity</span><span>只提供最基本的组件，再派生出</span><span>CharactorEntity</span><span>提供足够人物角色使用的组件。</span></p>
<h3><span>组件模式（</span><span>Component-Based Entity</span><span>）</span></h3>
<p><span>提到组件，那么很自然的就过渡到组件模式，就是把显示、运动、攻击、背包、队伍、声音等基本功能都做成独立的组件，由数据来决定向</span><span>Entity</span><span>里添加哪些组件。由此可以得到另外一个扩展，就是既然可以有引擎内置的组件，那就也可以有脚本制作的组件，实现脚本模块的复用。这种模式在</span><span>GDC2002</span><span>正式提出，到现在主流的引擎都有这种设计。</span></p>
<p><span>这种模式在理论上很完美，但实践上还是有不少疑问。最常见的问题就是组件间的依赖关系。理想情况下，各个组件是完全独立的，但实践中必然有所依赖。比如运动速度、攻击强度等和角色的基本属性有关，运动组件需要角色的包围盒来测试是否碰撞，</span><span>AI</span><span>组件需要分析角色当前状态和发出运动、攻击命令，角色动作状态变化时改变显示组件属性，攻击组件需要访问队伍信息组件以禁止攻击队友等等。处理这种依赖关系主要要解决两个问题：</span></p>
<p>&lt;!--[if !supportLists]--&gt;<span><span>一、<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span>&lt;!--[endif]--&gt;<span>谁依赖谁。比如是敏捷属性改变而去修改移动速度，还是运动组件读取敏捷属性来计算移动速度。如果要游戏设计人员自由定义基本属性的话，就要选择前者，因为基本属性组件会是脚本组件。</span></p>
<p>&lt;!--[if !supportLists]--&gt;<span><span>二、<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span>&lt;!--[endif]--&gt;<span>如何取得另一组件的指针</span><span>/</span><span>引用。常见的方法是给每个组件类型一个唯一</span><span>ID</span><span>，然后用该</span><span>ID</span><span>在</span><span>Entity</span><span>上查询注册了的组件，如果找到返回其指针</span><span>/</span><span>引用，否则返回</span><span>null</span><span>。当然，每次访问都做这个查询会很浪费</span><span>CPU</span><span>，如果</span><span>Entity</span><span>的组件不会在运行时动态添加删除的话（除非在编辑器里，否则很少有人会这么做），可以在</span><span>Entity</span><span>初始化后让每个组件缓存它所要用的其他组件指针。那么当所依赖的组件不存在怎么办，一般情况下都是无声地忽略。</span></p>
<p><span>当</span><span>Entity</span><span>由很多组件组成后，交互的消息需要发给每一个组件。这里又一次体现出消息机制的优势，你不需要在</span><span>Entity</span><span>里为每一个事件函数写一个</span><span>loop</span><span>来调用组件的相应事件函数。但这里也出现了一个问题，消息到达各个组件的顺序。很多时候这个顺序不会有什么影响，但个别时候不同的顺序会导致完全不同的逻辑发展方向。</span></p>
<p><span>此外，</span><span>Entity</span><span>的序列化存储也变得比较复杂，经典的</span><span>Excel</span><span>导出</span><span>csv</span><span>的模式难以奏效，因为这里需要结构化的存储，所以需要结构化的数据文件如</span><span>XML</span><span>来存储，或者完全用脚本来包含所有数据和构造</span><span>Entity</span><span>。</span></p>
<p><span>据个人经验，使用数据驱动的继承模式时很是向往组件模式，感觉上它一个非常自然的扩展方向，但顾忌其引入的额外的复杂性，尤其是需要游戏设计人员具有一定的编程能力，所以一直不敢全盘接过使用。但退一步，在引擎里仍然使用组件思想，但</span><span>Entity</span><span>的组件构成在编译时固定，可以达到某种妥协，这和采用继承与数据驱动的折中类似。</span></p>
<h3><span>混入模式（</span><span>Mix-in</span><span>）</span></h3>
<p><span>这是又一种常见的折中模式，即使用</span><span>C++</span><span>的多重继承，将各个组件类混入一个</span><span>Entity</span><span>类。如：</span></p>
<p><span>class Mob: public GameObject, public Renderable, public Movable, public Attackable<br>{<br>&#8230;<br>}</span></p>
<p><span>这种方法因其简单而且非常符合多重继承设计思想而被很多引擎采用。当然缺点也是只能在支持多重继承的语言里使用，而且当组件很丰富时，</span><span>dynamic_cast</span><span>就变成一个代价高昂的操作。</span><span> <br></span></p>
<h3><span>功能性与复杂性（</span><span>Functionality vs Complexity</span><span>）</span></h3>
<p><span>编程领域最古老的原则之一就是要&#8220;简单快速&#8221;。但随着问题的复杂化，程序也随之变得越来越复杂。好的方法应该能有效的降低或隐藏复杂性。但是，没有不带副作用的药（</span><span>No silver bullet.</span><span>），在取得更强大的功能的同时总会带来额外的复杂性。我们需要做出权衡，在必要时牺牲一些功能，也就是要估算性价比。</span><br></p>
<p><span>一般游戏内容制作人员不会或不太会编程，编程人员也不善于游戏的内容创造和数值平衡，过于复杂的系统会导致需要两面兼顾的人才，会大大增加做出一款游戏的难度。</span></p>
</span></span></div>
<img src ="http://www.cppblog.com/flashboy/aggbug/93684.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/flashboy/" target="_blank">RedLight</a> 2009-08-18 11:11 <a href="http://www.cppblog.com/flashboy/archive/2009/08/18/93684.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>游戏对象的实现</title><link>http://www.cppblog.com/flashboy/archive/2009/07/29/91635.html</link><dc:creator>RedLight</dc:creator><author>RedLight</author><pubDate>Wed, 29 Jul 2009 14:04:00 GMT</pubDate><guid>http://www.cppblog.com/flashboy/archive/2009/07/29/91635.html</guid><wfw:comment>http://www.cppblog.com/flashboy/comments/91635.html</wfw:comment><comments>http://www.cppblog.com/flashboy/archive/2009/07/29/91635.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/flashboy/comments/commentRss/91635.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/flashboy/services/trackbacks/91635.html</trackback:ping><description><![CDATA[<div class=intro>狭义的游戏对象是指游戏世界中所能看到及可交互的对象，如玩家、怪物、物品等，我们这里也主要讨论这类对象在服务器上的组织及实现。</div>
<div class=content>　　
<p>　　在大部分的MMOG中，游戏对象的类型都大同小异，主要有物品、生物、玩家等。比如在wow中，通过服务器发下来的GUID我们可以了解到，游戏中有9大类对象，包括物品(Item)、背包(Container)、生物(Unit)、玩家(Player)、游戏对象(GameObject)、动态对象(DynamicObject)、尸体(Corpse)等。</p>
<p>　　在mangos的实现中，对象使用类继承的方式，由Object基类定义游戏对象的公有接口及属性，包括GUID的生成及管理、构造及更新UpdateData数据的虚接口、设置及获取对象属性集的方法等。然后分出了两类派生对象，一是Item，另一是WorldObject。Item即物品对象，WorldObject顾名思义，为世界对象，即可添加到游戏世界场景中的对象，该对象类型定义了纯虚接口，也就是不可被实例化，主要是在Object对象的基础上又添加了坐标设置或获取的相关接口。</p>
<p>　　Item类型又派兵出了一类Bag对象，这是一种特殊的物品对象，其本身具有物品的所有属性及方法，但又可作为新的容器类型，并具有自己特有的属性和方法，所以实现上采用了派生。mangos在实现时对Bag的类型定义做了点小技巧，Item的类型为2，Bag的类型为6，这样在通过位的方式来表示类型时，Bag类型也就同时属于Item类型了。虽然只是很小的一个技巧，但在很多地方却带来了极大的便利。</p>
<p>　　从WorldObject派生出的类型就有好几种了，Unit、GameObject、DynamicObject和Corpse。Unit为所有生物类型的基类，同WorldObject一样，也不可被实例化。它定义了生物类型的公有属性，如种族、职业、性别、生命、魔法等，另外还提供了相关的一些操作接口。游戏中实际的生物对象类型为Creature，从Unit派生，另外还有一类派生对象Player为玩家对象。Player与Creature在实现上最大的区别是玩家的操作由客户端发来的消息驱动，而Creature的控制是由自己定义的AI对象来驱动，另外Player内部还包括了很多的逻辑系统实现。</p>
<p>　　另外还有两类特殊的Creature，Pet和Totem，其对象类型仍然还是生物类，只是实现上与会有些特殊的东西需要处理，所以在mangos中将其作为独立的派生类，只是实现上的一点处理。另外在GameObject中也实现有派生对象，最终的继承关系图比较简单，就不麻烦地去画图了。</p>
<p>　　从我所了解的早期游戏实现来看，大部分的游戏对象结构都是采用的类似这种方式。可能与早期对面向对象的理解有关，当面向对象的概念刚出来时，大家认为继承就是面向对象的全部，所以处处皆对象，处处皆继承。</p>
<p>　　类实现的是一种封装，虽然从云风那里出来的弃C++而转投C的声音可能会影响一部分人，但是，使用什么语言本身就是个人喜好及团队整体情况决定的。我们所要的也是最终的实现结果，至于中间的步骤，完全看个人。还是用云风的话说，这只是一种信仰问题，我依然采用我所熟悉的C++，下面的描述也是如此。</p>
<p>　　随着面向对象技术的深入，以及泛型等概念的相继提出，软件程序结构方面的趋势也有了很大改变。C++大师们常说的话中有一句是这样说的，尽是采用组合而不是继承。游戏对象的实现也有类似的转变，趋向于以组合的方式来实现游戏对象类型，也就是实现一个通用的entity类型，然后以脚本定义的方式组合出不同的实际游戏对象类型。</p>
<p>　　描述的有些抽象，具体实现下一篇来仔细探讨下。<br><br><br>在游戏编程精粹四有三篇文章讲到了实体以及实体管理的实现方案，其中一篇文章说到了实体管理系统的四大要素：定义实体怎样沟通的实体消息，实现一实体类代码和数据的实体代码，维护已经注册在案的实体类列表，和用来创建、管理、发送消息的实体管理器。</p>
<p>　　关于实体消息的内容之前讨论事件机制的时候做过一点说明，其实这也就是按接口调用和按消息驱动的区别，现在mangos的做法是完全的接口调用，所以引擎内部就没有任何的实体消息。实体代码实现和实体管理器是我们重点要讨论的内容。</p>
<p>　　另有一篇文章也提到了使用类继续的方式实现游戏对象的两大问题，一是它要求系统中的所有对象都必须从一个起点衍生而成，也就是说所有对象类在编译的时候已经确定，这可能是一个不受欢迎的限制，如果开发者决定添加新的对象类，则必须要对基类有所了解，方能支持新类。另一个问题在于所有的对象类都必须实现同样的一些底层函数。</p>
<p>　　对于第二个问题，可以通过接口继承的方式来避免基类的方法太多。在mangos的实现中就采用了类似的方法，从Object虚基类派生的Unit和WorldObject仍然还是不可实例化的类，这两种对象定义了不同的属性和方法，分来实现不同类型的对象。在游戏内部可以根据对象的实际类型来Object指针向下转型为Unit或WorldObject，以调用需要的接口。方法虽然不够OO，也还能解决问题。但是第一个问题是始终无法避免的。</p>
<p>　　所以我们便有了通用实体这么一个概念，其主要方法是将原来基类的接口进行分类，分到一个个不同的子类中，然后以对象组合的方式来生成我们所需要的实际游戏对象类型。这个组合的过程可以通过脚本定义的方式，这样便可以在运行时生成为同的对象类型，也就解决了上面提到的第一个问题。</p>
<p>　　通用实体的实现方法在目前的游戏引擎及开源代码中也可以看到影子。一个是BigWorld，从提供的资料来看，其引擎只提供了一个entity游戏对象，然后由游戏内容实现者通过xml和python脚本来自由定义不同类型的entity类型，每种类型可有不同的property和不同的方法。这样原来由基类定义的接口完全转移到脚本定义，具有非常强的灵活性。</p>
<p>　　另外还有一个是CEL中的entity实现。按照CEL的描述，entity可以是游戏中的任意对象，包括玩家可交互的对象，如钥匙、武器等，也可以包括不能直接交互的对象，如游戏世界，甚至任务链中的一部分等。entity本身并没有任何特性，具体的功能实现需要靠附加property来完成。简单来说，property才定义了entity可以做什么，至于该怎么做，那又是依靠behavior来定义。所以，最终在CEL中一个游戏对象其实是由entity组合了多个property及多个behavior而生成的。</p>
<p>　　但是CEL中的property与BigWorld中的property意义不大一样，在CEL中可定义的property其实是引擎内部要先提供的，比如其示例中所举的pcobject.mesh、pcmove.linear、pctools.inventory等，而BigWorld中的property是完全的自由定制。从这个角度来讲，其实可以把CEL中的property看作是游戏的逻辑系统，也就是我们上面所描述的，接口分类后所定义的子类。</p>
<p>　　由引擎内部提供可选择的property与BigWorld所采用的完全自由定制property其实本质上是相同的。在用BigWorld实现的游戏中，也不可能为每种游戏对象类型都完全从头定义property，基于代码利用的原则，也会先定义一些小类，然后在entity类型定义时以自定义property的方式来包含这些小类。当然，我没有使用过BigWorld，上面的描述也只是基于游戏实现的大原则所做出来的。</p>
<p>　　描述的依然有些抽象，我们可以用wow及mangos代码来说明一下。mangos中为object定义了一个属性集合，根据对象类型的不同，这个属性集的大小及保存数据也会有差异，另外游戏对象内部含有处理不同游戏逻辑的系统，如RestSystem、FloodFilterSystem、VariousSystem等等，在player.h中以接口组的方式进行定义。</p>
<p>　　如果要将这种结构改为我们描述的通用entity系统，可以让object只提供property注册和删除的接口，这里的property定义与CEL中的相同，放在mangos中也就是上面说的RestSystem、FloodFilterSystem、VariousSystem这些。然后也通过xml文件的方式定义我们所需要的游戏对象类型，如player,creature,item等，不同的对象类型可以选择加载不同的property，加载的原则是需要哪些功能就加载哪些property。</p>
<p>　　对象的定义按上面的方法完成后，对象的实现也需要做一些修改。以前客户端的消息是直接交由player来处理，AI也是直接调用creature的接口来完成一些功能，现在通用的entity内部已经没有任何可用的方法，所有的实现都转到了property中，所以需要由各个property实现自己来注册感兴趣的事件及消息，entity实现一个消息的转发，转给对此感兴趣的property来处理。其余的实现就没有什么不同了。</p>
<p>　　当然，我们再做一点扩展，让property不光由引擎来提供，用脚本本身也能定义property，并且可以通过xml来注册这些property，这样便实现了与BigWorld一样的完全自由特性。这其实也就是将很多用C++实现的功能转移到了python中，这种做法可作为参考，但不一定对所有人合适，至少在我看来，这样的实现也基本只能由程序员来做，所以让程序员选择自己最擅长的语言可能会更易于开发和调试。</p>
<p>有关游戏对象实现的描述，前面两篇文章中说的不甚清楚，主要是一直都要引用网上能够找到的资料来进行描述，以避免与公司引起不必要的麻烦。所以语言有些拼凑的感觉，举的例子也很不恰当，今天正好看到了游戏编程精粹五和六上的两篇文章，内容都差不多，&lt;&lt;基于组件的对象管理&gt;&gt;和&lt;&lt;基于组件的游戏对象系统&gt;&gt;，说的也是我上两篇文章想要描述的内容，所以再补一篇，引用其中的部分文字进行明确的说明。</p>
<p>&nbsp;</p>
<p>　　传统的游戏对象管理系统采用继承的方式来实现，例如，所有的子类都从CObject派生。大多数情况下，直接派生的也是抽象类，其中带一些功能而另一些子类则不带这些功能，比如可控制/不可控制，可动画/不可动画等。mangos的实现中基本就是这种情况，从Object直接派生的Unit和WorldObject都是不可直接实例化的类。</p>
<p>　　传统方法的问题在于无法应对需求的变化，如要求武器也有动画效果时就无法处理了。如果硬要是这样做，那随着需求的啬，很多的方法会被放到基类中，最终的结果是继承树变得越来越头重脚轻，这样的类会丧失它的内聚性，因为它们试图为所有对象完成所有的事。</p>
<p>　　就是说到最后，基类会有一个很长的接口列表，而很多的游戏对象类型根本不需要实现其中的一些甚至大部分接口，但是按照这种结构却又必须去实现。以至于于实现一个非常庞大的对象，而且想要修改一点功能会导致系统的大调整。</p>
<p>　　我们希望的系统是可以将现有的功能组合到新的对象中，并且在将新的功能添加到现有的对象中时不需要重构大量的代码和调整继承树的结构。</p>
<p>　　实现的方法就是从组件来创建一个对象。组件是一个包含所有相关数据成员和方法的类，它完成某个特定的任务。把几个组件组合在一起就可以创建一个新的对象。如把Entity组件、Render组件和Collectable组件组合在一起生成了一个Spoon对象。Entity组件让我们可以把对象放到游戏世界中，Render组件让我们可以为对象指定一个模型进行渲染，而Collectable组件让我们可以拾取这个对象。</p>
<p>　　关于组件的实现，所有的组件都从一个基础组件接口派生，可称其为IComponent。每个组件也有自己的接口定义，并且这个接口也需要从IComponent派生，类似于这样：IComponent -- ICmpRender -- CCmpRender</p>
<p>　　这里的每个组件也就是我在上一篇中所说的由引擎提供的属性，或者说在BigWorld中自己实现然后定义的属性，或者使用mangos中的定义，就是一个个的System，虽然mangos并没有将其完全做成组件，但是通过其代码注释可以看到，接口也是按功能组进行了分类，如果要拆分成组件也是比较方便的。</p>
<p>　　组件之间的通信有两种方法，一是用组件ID查询到组件接口指针，然后调用接口方法；二是使用消息的方式，向对象中所有组件发消息。在初始化的时候，每一个组件类型都会告诉对象管理器应该接收什么样的消息。</p>
<p>　　查询接口的方法也就是直接的方法调用，只不过接口不是全部在基类中，所以必须先查询到指定的组件然后才能调用其接口。消息的使用前面已经说过多次，其实现方案也有过说明。</p>
<p>　　最后是关于游戏对象功能的扩展和游戏对象的定义。需要扩展功能也就是需要实现一个新的组件，或者修改现在组件。在大多数情况下，扩展都不会引起结构的很大调整，受影响的最多只是使用到该组件的部分代码。</p>
<p>　　游戏对象定义可采用完全数据驱动的方式，使用xml或者脚本语言来定义对象类型，以及每个类型需要加载的组件。对象类型注册到对象管理器后，由管理器提供创建指定类型的对象的方法。数据驱动的方式能够让策划自由定义游戏对象类型，并且随时可自由创建新的对象类型。</p>
<p><br></p>
</div>
<img src ="http://www.cppblog.com/flashboy/aggbug/91635.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/flashboy/" target="_blank">RedLight</a> 2009-07-29 22:04 <a href="http://www.cppblog.com/flashboy/archive/2009/07/29/91635.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>WoW API中的Lua</title><link>http://www.cppblog.com/flashboy/archive/2009/01/12/71770.html</link><dc:creator>RedLight</dc:creator><author>RedLight</author><pubDate>Sun, 11 Jan 2009 16:28:00 GMT</pubDate><guid>http://www.cppblog.com/flashboy/archive/2009/01/12/71770.html</guid><wfw:comment>http://www.cppblog.com/flashboy/comments/71770.html</wfw:comment><comments>http://www.cppblog.com/flashboy/archive/2009/01/12/71770.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/flashboy/comments/commentRss/71770.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/flashboy/services/trackbacks/71770.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;<a href='http://www.cppblog.com/flashboy/archive/2009/01/12/71770.html'>阅读全文</a><img src ="http://www.cppblog.com/flashboy/aggbug/71770.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/flashboy/" target="_blank">RedLight</a> 2009-01-12 00:28 <a href="http://www.cppblog.com/flashboy/archive/2009/01/12/71770.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>LUA和C之间的函数调用</title><link>http://www.cppblog.com/flashboy/archive/2009/01/04/71167.html</link><dc:creator>RedLight</dc:creator><author>RedLight</author><pubDate>Sun, 04 Jan 2009 13:43:00 GMT</pubDate><guid>http://www.cppblog.com/flashboy/archive/2009/01/04/71167.html</guid><wfw:comment>http://www.cppblog.com/flashboy/comments/71167.html</wfw:comment><comments>http://www.cppblog.com/flashboy/archive/2009/01/04/71167.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/flashboy/comments/commentRss/71167.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/flashboy/services/trackbacks/71167.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;<a href='http://www.cppblog.com/flashboy/archive/2009/01/04/71167.html'>阅读全文</a><img src ="http://www.cppblog.com/flashboy/aggbug/71167.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/flashboy/" target="_blank">RedLight</a> 2009-01-04 21:43 <a href="http://www.cppblog.com/flashboy/archive/2009/01/04/71167.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Lua脚本语法说明（修订） </title><link>http://www.cppblog.com/flashboy/archive/2008/09/12/61701.html</link><dc:creator>RedLight</dc:creator><author>RedLight</author><pubDate>Fri, 12 Sep 2008 10:03:00 GMT</pubDate><guid>http://www.cppblog.com/flashboy/archive/2008/09/12/61701.html</guid><wfw:comment>http://www.cppblog.com/flashboy/comments/61701.html</wfw:comment><comments>http://www.cppblog.com/flashboy/archive/2008/09/12/61701.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/flashboy/comments/commentRss/61701.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/flashboy/services/trackbacks/61701.html</trackback:ping><description><![CDATA[Lua脚本语法说明（增加lua5.1部份特性）<br><br>　　Lua 的语法比较简单，学习起来也比较省力，但功能却并不弱。<br>　　所以，我只简单的归纳一下Lua的一些语法规则，使用起来方便好查就可以了。估计看完了，就懂得怎么写Lua程序了。<br><br>　　在Lua中，一切都是变量，除了关键字。<br><br>I.&nbsp; 首先是注释<br>　　写一个程序，总是少不了注释的。<br>　　在Lua中，你可以使用单行注释和多行注释。<br>　　单行注释中，连续两个减号"--"表示注释的开始，一直延续到行末为止。相当于C++语言中的"//"。<br>　　多行注释中，由"--[["表示注释开始，并且一直延续到"]]"为止。这种注释相当于C语言中的"/*...*/"。在注释当中，"[["和"]]"是可以嵌套的（<span style="COLOR: red">在lua5.1中，中括号中间是可以加若干个"="号的，如 [==[ ... ]==]</span>），见下面的字符串表示说明。<br><br>II.&nbsp; Lua编程<br>　　经典的"Hello world"的程序总是被用来开始介绍一种语言。在Lua中，写一个这样的程序很简单：<br>　　print("Hello world")<br>　　在Lua中，语句之间可以用分号"；"隔开，也可以用空白隔开。一般来说，如果多个语句写在同一行的话，建议总是用分号隔开。<br>　　Lua 有好几种程序控制语句，如：<br>
<table style="WIDTH: 760px; BORDER-COLLAPSE: collapse; HEIGHT: 124px" cellSpacing=0 cellPadding=3 border=1>
    <tbody>
        <tr>
            <td style="COLOR: red">控制语句</td>
            <td style="COLOR: red">格式</td>
            <td style="COLOR: red">示例</td>
        </tr>
        <tr>
            <td style="WIDTH: 80px">If</td>
            <td style="WIDTH: 313px; HEIGHT: 44px">if 条件 then ... elseif 条件 then ... else ... end</td>
            <td>
            <div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">+</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">2</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">then</span><span style="COLOR: #000000">&nbsp;print(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">true</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">)<br></span><span style="COLOR: #0000ff">elseif</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">+</span><span style="COLOR: #000000">2</span><span style="COLOR: #000000">~</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">3</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">then</span><span style="COLOR: #000000">&nbsp;print(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">true</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">)<br></span><span style="COLOR: #0000ff">else</span><span style="COLOR: #000000">&nbsp;print(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">false</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">)&nbsp;</span><span style="COLOR: #0000ff">end</span></div>
            <br></td>
        </tr>
        <tr>
            <td>While</td>
            <td>while 条件 do ... end</td>
            <td>
            <div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="COLOR: #0000ff">while</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">+</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">~</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">2</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">do</span><span style="COLOR: #000000">&nbsp;print(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">true</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">)&nbsp;</span><span style="COLOR: #0000ff">end</span></div>
            <br></td>
        </tr>
        <tr>
            <td>Repeat</td>
            <td>repeat ... until 条件</td>
            <td>
            <div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="COLOR: #000000"><span style="COLOR: #2000ff">repeat</span>&nbsp;</span><span style="COLOR: #0000ff">print</span><span style="COLOR: #000000">(</span><span style="FONT-WEIGHT: bold; COLOR: #000000">"</span><span style="FONT-WEIGHT: bold; COLOR: #000000">Hello</span><span style="FONT-WEIGHT: bold; COLOR: #000000">"</span><span style="COLOR: #000000">)&nbsp;</span><span style="COLOR: #0000ff">until</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #800000">1</span><span style="COLOR: #000000">+</span><span style="COLOR: #800000">1</span><span style="COLOR: #000000">~=</span><span style="COLOR: #800000">2</span></div>
            <br></td>
        </tr>
        <tr>
            <td>For</td>
            <td>for 变量=初值, 终点值, 步进 do&nbsp;... end</td>
            <td>
            <div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="COLOR: #0000ff">for</span><span style="COLOR: #000000">&nbsp;i&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">,&nbsp;</span><span style="COLOR: #000000">10</span><span style="COLOR: #000000">,&nbsp;</span><span style="COLOR: #000000">2</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">do</span><span style="COLOR: #000000">&nbsp;print(i)&nbsp;</span><span style="COLOR: #0000ff">end</span></div>
            <br></td>
        </tr>
        <tr>
            <td>For</td>
            <td>for 变量1, 变量2, ... 变量n in 表或枚举函数 do ... end</td>
            <td>
            <div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="COLOR: #0000ff">for</span><span style="COLOR: #000000">&nbsp;a,b&nbsp;</span><span style="COLOR: #0000ff">in</span><span style="COLOR: #000000">&nbsp;mylist&nbsp;</span><span style="COLOR: #0000ff">do</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">print</span><span style="COLOR: #000000">(a,&nbsp;b)&nbsp;</span><span style="COLOR: #0000ff">end</span></div>
            <br></td>
        </tr>
    </tbody>
</table>
<br>　　注意一下，for的循环变量总是只作用于for的局部变量；当省略步进值时，for循环会使用1作为步进值。<br>　　使用break可以用来中止一个循环。<br>　　相对C语言来说，Lua有几个地方是明显不同的，所以面要特别注意一下：<br><br>　　．<strong>语句块</strong><br>　　　　语句块在C中是用"{"和"}"括起来的，在Lua中，它是用do 和 end 括起来的。比如：<br>　　　　do print("Hello") end<br>　　　　可以在 <strong>函数</strong> 中和 <strong>语句块</strong> 中定局部变量。<br><br>　　．<strong>赋值语句</strong><br>　　　　赋值语句在Lua被强化了。它可以同时给多个变量赋值。<br>　　　　例如：<br>　　　　a,b,c,d=1,2,3,4<br>　　　　甚至是：<br>　　　　a,b=b,a&nbsp; -- 多么方便的交换变量功能啊。<br>　　　　在默认情况下，变量总是认为是全局的。假如需要定义局部变量，则在第一次赋值的时候，需要用local说明。比如：<br>　　　　local a,b,c = 1,2,3&nbsp; -- a,b,c都是局部变量<br><br>　　．<strong>数值运算</strong><br>　　　　和C语言一样，支持 +, -, *, /。但Lua还多了一个"^"。这表示指数乘方运算。比如2^3 结果为8, 2^4结果为16。<br>　　　　连接两个字符串，可以用".."运处符。如：<br>　　　　"This a " .. "string." -- 等于 "this a string"<br><br>　　．<strong>比较运算<br></strong>
<table style="WIDTH: 543px; BORDER-COLLAPSE: collapse; HEIGHT: 70px" cellSpacing=0 cellPadding=3 border=1>
    <tbody>
        <tr>
            <td style="COLOR: red">比较符号</td>
            <td>&lt;</td>
            <td>&gt;</td>
            <td>&lt;=</td>
            <td>&gt;=</td>
            <td>==</td>
            <td>~=</td>
        </tr>
        <tr>
            <td style="COLOR: red">含义</td>
            <td>小于</td>
            <td>大于</td>
            <td>小于或等于</td>
            <td>大于或等于</td>
            <td>相等</td>
            <td>不相等</td>
        </tr>
    </tbody>
</table>
<br>　　　　所有这些操作符总是返回true或false。<br>　　　　对于Table，Function和Userdata类型的数据，只有 == 和 ~=可以用。相等表示两个变量引用的是同一个数据。比如：<br>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">　　　　a</span><span style="COLOR: #808080">=</span><span style="COLOR: #000000">{</span><span style="FONT-WEIGHT: bold; COLOR: #800000">1</span><span style="COLOR: #000000">,</span><span style="FONT-WEIGHT: bold; COLOR: #800000">2</span><span style="COLOR: #000000">}<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top>　　　　b</span><span style="COLOR: #808080">=</span><span style="COLOR: #000000">a<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top>　　　　</span><span style="COLOR: #0000ff">print</span><span style="COLOR: #000000">(a</span><span style="COLOR: #808080">==</span><span style="COLOR: #000000">b,&nbsp;a</span><span style="COLOR: #808080">~=</span><span style="COLOR: #000000">b)&nbsp;&nbsp;</span><span style="COLOR: #008080">--</span><span style="COLOR: #008080">输出&nbsp;true,&nbsp;false</span><span style="COLOR: #008080"><br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">　　　　a</span><span style="COLOR: #808080">=</span><span style="COLOR: #000000">{</span><span style="FONT-WEIGHT: bold; COLOR: #800000">1</span><span style="COLOR: #000000">,</span><span style="FONT-WEIGHT: bold; COLOR: #800000">2</span><span style="COLOR: #000000">}<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top>　　　　b</span><span style="COLOR: #808080">=</span><span style="COLOR: #000000">{</span><span style="FONT-WEIGHT: bold; COLOR: #800000">1</span><span style="COLOR: #000000">,</span><span style="FONT-WEIGHT: bold; COLOR: #800000">2</span><span style="COLOR: #000000">}<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top>　　　　</span><span style="COLOR: #0000ff">print</span><span style="COLOR: #000000">(a</span><span style="COLOR: #808080">==</span><span style="COLOR: #000000">b,&nbsp;a</span><span style="COLOR: #808080">~=</span><span style="COLOR: #000000">b)&nbsp;&nbsp;</span><span style="COLOR: #008080">--</span><span style="COLOR: #008080">输出&nbsp;false,&nbsp;true</span><span style="COLOR: #008080"><br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></span></div>
<br><br>　　．逻辑运算<br>　　　　and, or, not<br>　　　　其中，and 和 or 与C语言区别特别大。<br>　　　　在这里，请先记住，在Lua中，只有false和nil才计算为false，其它任何数据都计算为true，0也是true！<br>　　　　and 和 or的运算结果不是true和false，而是和它的两个操作数相关。<br>　　　　a and b：如果a为false，则返回a；否则返回b<br>　　　　a or b：如果 a 为true，则返回a；否则返回b<br><br>　　　　举几个例子：<br>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">　　　　&nbsp;</span><span style="COLOR: #0000ff">print</span><span style="COLOR: #000000">(</span><span style="FONT-WEIGHT: bold; COLOR: #800000">4</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #808080">and</span><span style="COLOR: #000000">&nbsp;</span><span style="FONT-WEIGHT: bold; COLOR: #800000">5</span><span style="COLOR: #000000">)&nbsp;</span><span style="COLOR: #008080">--</span><span style="COLOR: #008080">输出&nbsp;5</span><span style="COLOR: #008080"><br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">　　　　&nbsp;</span><span style="COLOR: #0000ff">print</span><span style="COLOR: #000000">(nil&nbsp;</span><span style="COLOR: #808080">and</span><span style="COLOR: #000000">&nbsp;</span><span style="FONT-WEIGHT: bold; COLOR: #800000">13</span><span style="COLOR: #000000">)&nbsp;</span><span style="COLOR: #008080">--</span><span style="COLOR: #008080">输出&nbsp;nil</span><span style="COLOR: #008080"><br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">　　　　&nbsp;</span><span style="COLOR: #0000ff">print</span><span style="COLOR: #000000">(false&nbsp;</span><span style="COLOR: #808080">and</span><span style="COLOR: #000000">&nbsp;</span><span style="FONT-WEIGHT: bold; COLOR: #800000">13</span><span style="COLOR: #000000">)&nbsp;</span><span style="COLOR: #008080">--</span><span style="COLOR: #008080">输出&nbsp;false</span><span style="COLOR: #008080"><br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">　　　　&nbsp;</span><span style="COLOR: #0000ff">print</span><span style="COLOR: #000000">(</span><span style="FONT-WEIGHT: bold; COLOR: #800000">4</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #808080">or</span><span style="COLOR: #000000">&nbsp;</span><span style="FONT-WEIGHT: bold; COLOR: #800000">5</span><span style="COLOR: #000000">)&nbsp;</span><span style="COLOR: #008080">--</span><span style="COLOR: #008080">输出&nbsp;4</span><span style="COLOR: #008080"><br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">　　　　&nbsp;</span><span style="COLOR: #0000ff">print</span><span style="COLOR: #000000">(false&nbsp;</span><span style="COLOR: #808080">or</span><span style="COLOR: #000000">&nbsp;</span><span style="FONT-WEIGHT: bold; COLOR: #800000">5</span><span style="COLOR: #000000">)&nbsp;</span><span style="COLOR: #008080">--</span><span style="COLOR: #008080">输出&nbsp;5</span><span style="COLOR: #008080"><br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></span></div>
<br>　　　　在Lua中这是很有用的特性，也是比较令人混洧的特性。<br>　　　　我们可以模拟C语言中的语句：x = a? b : c，在Lua中，可以写成：x = a and b or c。<br>　　　　最有用的语句是： x = x or v，它相当于：if not x then x = v end 。<br><br>　　．运算符优先级，从低到高顺序如下：<br>
<table style="WIDTH: 320px; BORDER-COLLAPSE: collapse" cellSpacing=0 cellPadding=3 border=1>
    <tbody>
        <tr>
            <td>&nbsp;&nbsp;&nbsp;&nbsp; or<br>&nbsp;&nbsp;&nbsp;&nbsp; and<br>&nbsp;&nbsp;&nbsp;&nbsp; &lt;&nbsp;&nbsp;&nbsp;&nbsp; &gt;&nbsp;&nbsp;&nbsp;&nbsp; &lt;=&nbsp;&nbsp;&nbsp; &gt;=&nbsp;&nbsp;&nbsp; ~=&nbsp;&nbsp;&nbsp; ==<br>&nbsp;&nbsp;&nbsp;&nbsp; .. (字符串连接)<br>&nbsp;&nbsp;&nbsp;&nbsp; +&nbsp;&nbsp;&nbsp;&nbsp; -<br>&nbsp;&nbsp;&nbsp;&nbsp; *&nbsp;&nbsp;&nbsp;&nbsp; /&nbsp;&nbsp;&nbsp;&nbsp; %<br>&nbsp;&nbsp;&nbsp;&nbsp; not&nbsp;&nbsp; #(<span style="COLOR: red">lua5.1 取长度运算</span>)&nbsp;&nbsp;&nbsp;&nbsp; - (一元运算)<br>&nbsp;&nbsp;&nbsp;&nbsp; ^</td>
        </tr>
    </tbody>
</table>
和C语言一样，括号可以改变优先级。<br><br>III.&nbsp; 关键字<br>　　关键字是不能做为变量的。Lua的关键字不多，就以下几个：<br>&nbsp;&nbsp;&nbsp;&nbsp;
<table style="WIDTH: 426px; BORDER-COLLAPSE: collapse; HEIGHT: 105px" cellSpacing=0 cellPadding=3 border=1>
    <tbody>
        <tr>
            <td>and</td>
            <td>break</td>
            <td>do</td>
            <td>else</td>
            <td>elseif</td>
            <td></td>
        </tr>
        <tr>
            <td>end</td>
            <td>false</td>
            <td>for</td>
            <td>function</td>
            <td>if</td>
            <td></td>
        </tr>
        <tr>
            <td>in</td>
            <td>local</td>
            <td>nil</td>
            <td>not</td>
            <td>or</td>
            <td></td>
        </tr>
        <tr>
            <td>repeat</td>
            <td>return</td>
            <td>then</td>
            <td>true</td>
            <td>until</td>
            <td>while</td>
        </tr>
    </tbody>
</table>
<br>IV.&nbsp; 变量类型<br>　　怎么确定一个变量是什么类型的呢？大家可以用type()函数来检查。Lua支持的类型有以下几种：<br>
<table style="WIDTH: 758px; BORDER-COLLAPSE: collapse; HEIGHT: 143px" cellSpacing=0 cellPadding=3 border=1>
    <tbody>
        <tr>
            <td style="WIDTH: 74px">Nil</td>
            <td>空值，所有没有使用过的变量，都是nil。nil既是值，又是类型。</td>
        </tr>
        <tr>
            <td>Boolean</td>
            <td>布尔值，只有两个有效值：true和false</td>
        </tr>
        <tr>
            <td>Number</td>
            <td>数值，在Lua里，数值相当于C语言的double</td>
        </tr>
        <tr>
            <td>String</td>
            <td>字符串，如果你愿意的话，字符串是可以包含"\0"字符的（这和C语言总是以"\0"结尾是不一样的）</td>
        </tr>
        <tr>
            <td>Table</td>
            <td>关系表类型，这个类型功能比较强大，请参考后面的内容。</td>
        </tr>
        <tr>
            <td>Function</td>
            <td>函数类型，不要怀疑，函数也是一种类型，也就是说，所有的函数，它本身就是一个变量。</td>
        </tr>
        <tr>
            <td>Userdata</td>
            <td>嗯，这个类型专门用来和Lua的宿主打交道的。宿主通常是用C和C++来编写的，在这种情况下，Userdata可以是宿主的任意数据类型，常用的有Struct和指针。</td>
        </tr>
        <tr>
            <td>Thread</td>
            <td><span style="TEXT-DECORATION: line-through">线程类型，在Lua中没有真正的线程。Lua中可以将一个函数分成几部份运行。</span>如果感兴趣的话，可以去看看Lua的文档。<br>现在回过头来看看，倒觉得不是线程类型。反而象是用来做遍历的，象是Iterator函数。<br>如：<br>
            <div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="COLOR: #0000ff">function</span><span style="COLOR: #000000">&nbsp;range(n)<br>&nbsp; <span style="COLOR: #2000ff">local</span> i&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000"><br>&nbsp;&nbsp;</span><span style="COLOR: #0000ff">while</span><span style="COLOR: #000000">(i&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">&nbsp;n)&nbsp;</span><span style="COLOR: #0000ff">do</span><span style="COLOR: #000000"></span> <br>&nbsp;&nbsp;&nbsp; coroutine.yield( i )<br><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;i&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;i&nbsp;</span><span style="COLOR: #000000">+</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000"><br>&nbsp;&nbsp;</span><span style="COLOR: #0000ff">end</span><span style="COLOR: #000000"><br></span><span style="COLOR: #0000ff">end</span></div>
            可惜的是要继续运行，需要coroutine.resume函数，有点鸡肋。请指教。<br></td>
        </tr>
    </tbody>
</table>
<br>V.&nbsp; 变量的定义<br>　　所有的语言，都要用到变量。在Lua中，不管在什么地方使用变量，都不需要声明，并且所有的这些变量总是全局变量，除非我们在前面加上"local"。这一点要特别注意，因为我们可能想在函数里使用局部变量，却忘了用local来说明。<br>　　至于变量名字，它是大小写相关的。也就是说，A和a是两个不同的变量。<br>　　定义一个变量的方法就是赋值。"＝"操作就是用来赋值的<br>　　我们一起来定义几种常用类型的变量吧。<br>　　A.&nbsp; Nil<br>　　　　正如前面所说的，没有使用过的变量的值，都是Nil。有时候我们也需要将一个变量清除，这时候，我们可以直接给变量赋以nil值。如：<br>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">　　　　var1</span><span style="COLOR: #808080">=</span><span style="COLOR: #000000">nil&nbsp;&nbsp;</span><span style="COLOR: #008080">--</span><span style="COLOR: #008080">&nbsp;请注意&nbsp;nil&nbsp;一定要小写</span></div>
<br>　　B.&nbsp; Boolean<br>　　　　布尔值通常是用在进行条件判断的时候。布尔值有两种：true 和 false。在Lua中，只有false和nil才被计算为false，而所有任何其它类型的值，都是true。比如0，空串等等，都是true。不要被 C语言的习惯所误导，0在Lua中的的确确是true。你也可以直接给一个变量赋以Boolean类型的值，如：<br>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">　　　　theBoolean&nbsp;</span><span style="COLOR: #808080">=</span><span style="COLOR: #000000">&nbsp;true</span></div>
<br>　　C.&nbsp; Number<br>　　　　在Lua中，是没有整数类型的，也不需要。一般情况下，只要数值不是很大（比如不超过100,000,000,000,000），是不会产生舍入误差的。在WindowsXP能跑的当今主流PC上，实数的运算并不比整数慢。<br>　　　　实数的表示方法，同C语言类似，如：<br>　　　　4 0.4 4.57e-3 0.3e12 5e+20<br><br>　　D.&nbsp; String<br>　　　　字符串，总是一种非常常用的高级类型。在Lua中，我们可以非常方便的定义很长很长的字符串。<br>　　　　字符串在Lua中有几种方法来表示，最通用的方法，是用双引号或单引号来括起一个字符串的，如：<br>　　　　"That's go!"<br>　　　　或<br>　　　　'Hello world!'<br><br>　　　　和C语言相同的，它支持一些转义字符，列表如下：<br>　　　　\a&nbsp; bell<br>　　　　\b&nbsp; back space<br>　　　　\f&nbsp; form feed<br>　　　　\n&nbsp; newline<br>　　　　\r&nbsp; carriage return<br>　　　　\t&nbsp; horizontal tab<br>　　　　\v&nbsp; vertical tab<br>　　　　\\&nbsp; backslash<br>　　　　\"&nbsp; double quote<br>　　　　\"&nbsp; single quote<br>　　　　\[&nbsp; left square bracket<br>　　　　\]&nbsp; right square bracket<br><br>　　　　由于这种字符串只能写在一行中，因此，不可避免的要用到转义字符。加入了转义字符的串，看起来实在是不敢恭维，比如：<br>　　　　"one line\nnext line\n\"in quotes\", "in quotes""<br>　　　　一大堆的"\"符号让人看起来很倒胃口。如果你与我有同感，那么，我们在Lua中，可以用另一种表示方法：用"[["和"]]"将多行的字符串括起来。（<span style="COLOR: red">lua5.1: 中括号中间可以加入若干个"="号，如 [==[ ... ]==]，详见下面示例</span>）<br>　　　　示例：下面的语句所表示的是完全相同的字符串：<br>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">a&nbsp;</span><span style="COLOR: #808080">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #ff0000">'</span><span style="COLOR: #ff0000">alo\n123"</span><span style="COLOR: #ff0000">'</span><span style="COLOR: #000000"><br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top>a&nbsp;</span><span style="COLOR: #808080">=</span><span style="COLOR: #000000">&nbsp;<span style="COLOR: red">"alo\n123\""</span><br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top>a&nbsp;</span><span style="COLOR: #808080">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #ff0000">'</span><span style="COLOR: #ff0000">\97lo\10\04923"</span><span style="COLOR: #ff0000">'</span><span style="COLOR: #000000"><br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top>a&nbsp;</span><span style="COLOR: #808080">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #ff0000">[</span><span style="COLOR: #ff0000">[alo<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top>123"</span><span style="COLOR: #ff0000">]</span><span style="COLOR: #000000">]<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top>a&nbsp;</span><span style="COLOR: #808080">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #ff0000">[</span><span style="COLOR: #ff0000">==[<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top>alo<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top>123"</span><span style="COLOR: #ff0000">]</span><span style="COLOR: #808080">==</span><span style="COLOR: #000000">]</span></div>
<br>　　　　值得注意的是，在这种字符串中，如果含有单独使用的"[["或"]]"就仍然得用"\["或"\]"来避免歧义。当然，这种情况是极少会发生的。<br><br>　　E.&nbsp; Table<br>　　　　关系表类型，这是一个很强大的类型。我们可以把这个类型看作是一个数组。只是C语言的数组，只能用正整数来作索引；在Lua中，你可以用任意类型来作数组的索引，除了nil。同样，在C语言中，数组的内容只允许一种类型；在Lua中，你也可以用任意类型的值来作数组的内容，除了nil。<br>　　　　Table的定义很简单，它的主要特征是用"{"和"}"来括起一系列数据元素的。比如：<br>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">　　　　T1&nbsp;</span><span style="COLOR: #808080">=</span><span style="COLOR: #000000">&nbsp;{}&nbsp;&nbsp;</span><span style="COLOR: #008080">--</span><span style="COLOR: #008080">&nbsp;定义一个空表</span><span style="COLOR: #008080"><br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">　　　　T1</span><span style="COLOR: #ff0000">[</span><span style="COLOR: #ff0000">1</span><span style="COLOR: #ff0000">]</span><span style="COLOR: #808080">=</span><span style="FONT-WEIGHT: bold; COLOR: #800000">10</span><span style="COLOR: #000000">&nbsp;&nbsp;</span><span style="COLOR: #008080">--</span><span style="COLOR: #008080">&nbsp;然后我们就可以象C语言一样来使用它了。</span><span style="COLOR: #008080"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></span></div>
<br>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">　　　　T1</span><span style="COLOR: #ff0000">[</span><span style="COLOR: #ff0000">"John"</span><span style="COLOR: #ff0000">]</span><span style="COLOR: #808080">=</span><span style="COLOR: #000000">{Age</span><span style="COLOR: #808080">=</span><span style="FONT-WEIGHT: bold; COLOR: #800000">27</span><span style="COLOR: #000000">,&nbsp;Gender</span><span style="COLOR: #808080">=</span><span style="COLOR: #000000">"Male"}<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top>　　　　这一句相当于：<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top>　　　　T1</span><span style="COLOR: #ff0000">[</span><span style="COLOR: #ff0000">"John"</span><span style="COLOR: #ff0000">]</span><span style="COLOR: #808080">=</span><span style="COLOR: #000000">{}&nbsp;&nbsp;</span><span style="COLOR: #008080">--</span><span style="COLOR: #008080">&nbsp;必须先定义成一个表，还记得未定义的变量是nil类型吗</span><span style="COLOR: #008080"><br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">　　　　T1</span><span style="COLOR: #ff0000">[</span><span style="COLOR: #ff0000">"John"</span><span style="COLOR: #ff0000">][</span><span style="COLOR: #ff0000">"Age"</span><span style="COLOR: #ff0000">]</span><span style="COLOR: #808080">=</span><span style="FONT-WEIGHT: bold; COLOR: #800000">27</span><span style="COLOR: #000000"><br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top>　　　　T1</span><span style="COLOR: #ff0000">[</span><span style="COLOR: #ff0000">"John"</span><span style="COLOR: #ff0000">][</span><span style="COLOR: #ff0000">"Gender"</span><span style="COLOR: #ff0000">]</span><span style="COLOR: #808080">=</span><span style="COLOR: #000000">"Male"<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top>　　　　当表的索引是字符串的时候，我们可以简写成：<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top>　　　　T1.John</span><span style="COLOR: #808080">=</span><span style="COLOR: #000000">{}<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top>　　　　T1.John.Age</span><span style="COLOR: #808080">=</span><span style="FONT-WEIGHT: bold; COLOR: #800000">27</span><span style="COLOR: #000000"><br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top>　　　　T1.John.Gender</span><span style="COLOR: #808080">=</span><span style="COLOR: #000000">"Male"<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top>　　　　或<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top>　　　　T1.John{Age</span><span style="COLOR: #808080">=</span><span style="FONT-WEIGHT: bold; COLOR: #800000">27</span><span style="COLOR: #000000">,&nbsp;Gender</span><span style="COLOR: #808080">=</span><span style="COLOR: #000000">"Male"}</span></div>
这是一个很强的特性。<br><br>　　　　在定义表的时候，我们可以把所有的数据内容一起写在"{"和"}"之间，这样子是非常方便，而且很好看。比如，前面的T1的定义，我们可以这么写：<br>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">　　　　T1</span><span style="COLOR: #808080">=</span><span style="COLOR: #000000"><br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top>　　　　{<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top>　　　　　　</span><span style="FONT-WEIGHT: bold; COLOR: #800000">10</span><span style="COLOR: #000000">,&nbsp;&nbsp;</span><span style="COLOR: #008080">--</span><span style="COLOR: #008080">&nbsp;相当于&nbsp;[1]&nbsp;=&nbsp;10</span><span style="COLOR: #008080"><br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">　　　　　　</span><span style="COLOR: #ff0000">[</span><span style="COLOR: #ff0000">100</span><span style="COLOR: #ff0000">]</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #808080">=</span><span style="COLOR: #000000">&nbsp;</span><span style="FONT-WEIGHT: bold; COLOR: #800000">40</span><span style="COLOR: #000000">,<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top>　　　　　　John</span><span style="COLOR: #808080">=</span><span style="COLOR: #000000">&nbsp;&nbsp;</span><span style="COLOR: #008080">--</span><span style="COLOR: #008080">&nbsp;如果你原意，你还可以写成：["John"]&nbsp;=</span><span style="COLOR: #008080"><br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">　　　　　　{<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top>　　　　　　　　Age</span><span style="COLOR: #808080">=</span><span style="FONT-WEIGHT: bold; COLOR: #800000">27</span><span style="COLOR: #000000">,&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008080">--</span><span style="COLOR: #008080">&nbsp;如果你原意，你还可以写成：["Age"]&nbsp;=27</span><span style="COLOR: #008080"><br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">　　　　　　　　Gender</span><span style="COLOR: #808080">=</span><span style="COLOR: #000000">Male&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008080">--</span><span style="COLOR: #008080">&nbsp;如果你原意，你还可以写成：["Gender"]&nbsp;=Male</span><span style="COLOR: #008080"><br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">　　　　　　},<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top>　　　　　　</span><span style="FONT-WEIGHT: bold; COLOR: #800000">20</span><span style="COLOR: #000000">&nbsp;&nbsp;</span><span style="COLOR: #008080">--</span><span style="COLOR: #008080">&nbsp;相当于&nbsp;[2]&nbsp;=&nbsp;20</span><span style="COLOR: #008080"><br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">　　　　}<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></span></div>
<br>　　　　看起来很漂亮，不是吗？我们在写的时候，需要注意三点：<br>　　　　第一，所有元素之间，总是用逗号"，"隔开；<br>　　　　第二，所有索引值都需要用"["和"]"括起来；如果是字符串，还可以去掉引号和中括号；<br>　　　　第三，如果不写索引，则索引就会被认为是数字，并按顺序自动从1往后编；<br><br>　　　　表类型的构造是如此的方便，以致于常常被人用来代替配置文件。是的，不用怀疑，它比ini文件要漂亮，并且强大的多。<br><br>　　F.&nbsp; Function<br>　　　　函数，在Lua中，函数的定义也很简单。典型的定义如下：<br>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">　　　　</span><span style="COLOR: #0000ff">function</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">add</span><span style="COLOR: #000000">(a,b)&nbsp;&nbsp;</span><span style="COLOR: #008080">--</span><span style="COLOR: #008080">&nbsp;add&nbsp;是函数名字，a和b是参数名字</span><span style="COLOR: #008080"><br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">　　　　&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;a</span><span style="COLOR: #808080">+</span><span style="COLOR: #000000">b&nbsp;&nbsp;</span><span style="COLOR: #008080">--</span><span style="COLOR: #008080">&nbsp;return&nbsp;用来返回函数的运行结果</span><span style="COLOR: #008080"><br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">　　　　</span><span style="COLOR: #0000ff">end</span><span style="COLOR: #000000"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></span></div>
<br>　　　　请注意，return语言一定要写在end之前。假如我们非要在中间放上一句return，那么就应该要写成：do return end。<br>　　　　还记得前面说过，函数也是变量类型吗？上面的函数定义，其实相当于：<br>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">　　　　</span><span style="COLOR: #0000ff">add</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #808080">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">function</span><span style="COLOR: #000000">&nbsp;(a,b)&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;a</span><span style="COLOR: #808080">+</span><span style="COLOR: #000000">b&nbsp;</span><span style="COLOR: #0000ff">end</span></div>
当重新给add赋值时，它就不再表示这个函数了。我们甚至可以赋给add任意数据，包括nil （这样，赋值为nil，将会把该变量清除）。Function是不是很象C语言的函数指针呢？<br><br>　　　　和C语言一样，Lua的函数可以接受可变参数个数，它同样是用"..."来定义的，比如：<br>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">　　　　</span><span style="COLOR: #0000ff">function</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #ff00ff">sum</span><span style="COLOR: #000000">&nbsp;(a,b,<img src="http://www.cnblogs.com/Images/dot.gif">)</span></div>
如果想取得...所代表的参数，可以在函数中访问arg局部变量（表类型）得到 (<span style="COLOR: red">lua5.1: 取消arg，并直接用"..."来代表可变参数了，本质还是arg</span>)。<br>　　　　如 sum(1,2,3,4)<br>　　　　则，在函数中，a = 1, b = 2, arg = {3, 4}&nbsp; (<span style="COLOR: red">lua5.1:&nbsp; a = 1, b = 2, ... = {3, 4}</span>)<br>　　　　更可贵的是，它可以同时返回多个结果，比如：<br>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">　　　　</span><span style="COLOR: #0000ff">function</span><span style="COLOR: #000000">&nbsp;s()<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top>　　　　　　</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="FONT-WEIGHT: bold; COLOR: #800000">1</span><span style="COLOR: #000000">,</span><span style="FONT-WEIGHT: bold; COLOR: #800000">2</span><span style="COLOR: #000000">,</span><span style="FONT-WEIGHT: bold; COLOR: #800000">3</span><span style="COLOR: #000000">,</span><span style="FONT-WEIGHT: bold; COLOR: #800000">4</span><span style="COLOR: #000000"><br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top>　　　　</span><span style="COLOR: #0000ff">end</span><span style="COLOR: #000000"><br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top>　　　　a,b,c,d&nbsp;</span><span style="COLOR: #808080">=</span><span style="COLOR: #000000">&nbsp;s()&nbsp;&nbsp;</span><span style="COLOR: #008080">--</span><span style="COLOR: #008080">&nbsp;此时，a&nbsp;=&nbsp;1,&nbsp;b&nbsp;=&nbsp;2,&nbsp;c&nbsp;=&nbsp;3,&nbsp;d&nbsp;=&nbsp;4</span><span style="COLOR: #008080"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></span></div>
<br>　　　　前面说过，表类型可以拥有任意类型的值，包括函数！因此，有一个很强大的特性是，拥有函数的表，哦，我想更恰当的应该说是对象吧。Lua可以使用面向对象编程了。不信？举例如下：<br>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">　　　　t&nbsp;</span><span style="COLOR: #808080">=</span><span style="COLOR: #000000"><br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top>　　　　{<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top>　　　　&nbsp;Age&nbsp;</span><span style="COLOR: #808080">=</span><span style="COLOR: #000000">&nbsp;</span><span style="FONT-WEIGHT: bold; COLOR: #800000">27</span><span style="COLOR: #000000"><br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top>　　　　&nbsp;</span><span style="COLOR: #0000ff">add</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #808080">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">function</span><span style="COLOR: #000000">(self,&nbsp;n)&nbsp;self.Age&nbsp;</span><span style="COLOR: #808080">=</span><span style="COLOR: #000000">&nbsp;self.Age</span><span style="COLOR: #808080">+</span><span style="COLOR: #000000">n&nbsp;</span><span style="COLOR: #0000ff">end</span><span style="COLOR: #000000"><br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top>　　　　}<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top>　　　　</span><span style="COLOR: #0000ff">print</span><span style="COLOR: #000000">(t.Age)&nbsp;&nbsp;</span><span style="COLOR: #008080">--</span><span style="COLOR: #008080">&nbsp;27</span><span style="COLOR: #008080"><br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">　　　　t.</span><span style="COLOR: #0000ff">add</span><span style="COLOR: #000000">(t,&nbsp;</span><span style="FONT-WEIGHT: bold; COLOR: #800000">10</span><span style="COLOR: #000000">)<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top>　　　　</span><span style="COLOR: #0000ff">print</span><span style="COLOR: #000000">(t.Age)&nbsp;&nbsp;</span><span style="COLOR: #008080">--</span><span style="COLOR: #008080">&nbsp;37</span></div>
<br>　　　　不过，t.add(t,10) 这一句实在是有点土对吧？没关系，在Lua中，我们可以简写成：<br>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">　　　　t:</span><span style="COLOR: #0000ff">add</span><span style="COLOR: #000000">(</span><span style="FONT-WEIGHT: bold; COLOR: #800000">10</span><span style="COLOR: #000000">)&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008080">--</span><span style="COLOR: #008080">&nbsp;相当于&nbsp;t.add(t,10)</span></div>
<br>　　G.&nbsp; Userdata 和 Thread<br>　　　　这两个类型的话题，超出了本文的内容，就不打算细说了。<br><br>VI.&nbsp; 结束语<br>　　就这么结束了吗？当然不是，接下来，我们需要用Lua解释器，来帮助理解和实践了。相信这样会更快的对Lua上手了。<br>　　就象C语言一样，Lua提供了相当多的标准函数来增强语言的功能。使用这些标准函数，可以很方便的操作各种数据类型，并处理输入输出。有关这方面的信息，我们可以参考《Programming in Lua 》一书，也可以在网络上直接观看电子版，网址为：<a href="http://www.lua.org/pil/index.html"><font color=#444444>http://www.lua.org/pil/index.html</font></a><br>　　<br>备注：本文的部份内容摘、译自lua随机文档。<br>相关链接：<br>1. Lua 官方网站： <a href="http://www.lua.org/"><font color=#444444>http://www.lua.org</font></a> <br>2. Lua Wiki网站，你可以在这里找到很多相关的资料，如文档、教程、扩展，以及C/C++的包装等： <a href="http://lua-users.org/wiki/"><font color=#444444>http://lua-users.org/wiki/</font></a><br>3. Lua 打包下载（包括各种平台和编译器的工程文件如vs2003,vs2005）：http://luabinaries.luaforge.net/download.html<br>
<img src ="http://www.cppblog.com/flashboy/aggbug/61701.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/flashboy/" target="_blank">RedLight</a> 2008-09-12 18:03 <a href="http://www.cppblog.com/flashboy/archive/2008/09/12/61701.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>