LUA脚本组件系统
----让LUA成为C++的子集
三脚本组件系统相关理论介绍
3.1基于组件的对象系统
在经典面向对象方法论描述中,我们知道对象由属性和方法组成.基本对象类可以通过派生子类来扩展其功能.这样做的问题之一是对类型不同的对象必须定义不同的类或者定义一个包括不同类型对象属性和方法的大类来描述这不同的对象.结果是要么生成无数的类要么生成含有属性和方法庞大和冗余的类.另一个问题是每种游戏对象(即使这种类型的对象只有一个)都必须有一个预先定义好的类才能用使用该类生成对象.
基于组件的对象系统试图解决以上描述的两个问题.它具有以下特点:
1. 游戏对象不再由属性和方法组成而是被分解为一系列的功能单一的组件
2. 每个组件由属性和方法组成,这些属性和方法功能内聚只完成某一种特定的任务
3. 即使在游戏运行时,也可以通过添加或删除组件,使对象的行为和功能改变
4. 任何一个游戏对象可以克隆出和自己一样的新对象
5. 游戏对象可以保存到文件或者数据库,也可以从文件或者数据库加载
6. 游戏对象有一个唯一的标识,通过该标识可以被其它对象访问
7. 游戏对象可以包含其它子对象
基于组件的对象系统的类图如下:
(图一)
例如下图描述了由不同组件构成的NPC对象
(图二)
从这个图可以看出,该NPC由描述位置的TransformComponent,描述动作行为的AIComponent及描述生命的HealthComponent等组件构成
3.2脚本作为对象的组件
组件系统看起来很完美.好像游戏设计人员只须按要求组合相应的组件就可以创造新的的对象,从而完成不同的需求创造不同的玩法.事实上是不是这样的呢.假设有这样一个需求
有一个和图2一样的NPC对象,但现在要求该NPC有两种状态,无敌和可攻击,在子弹击中NPC时,只有在可攻击的状态下才造成伤害.假设主程序已经给你划分好接口,这些接口需要在lua脚本中被其它系统调用
1. SetInvincible(i)
无返回值,有一个参数i,为true表示设置为无敌,为false表示为可以攻击
2. IsInvincible()
返回该npc是否无敌,true表示无敌,false表示可以攻击
3. TakeDamage(d)
无返回值,参数d是一个数值变量代表子弹的伤害值,该函数会在子弹碰撞到npc时调用
根据第本文一部分的介绍,我们可以知道NPC对象的部分属性和方法可以放到lua文件中,因此我们可以写这样的一个脚本文件npc.lua
local invincible= false; functionSetInvincible(i) invincible = i; end functionIsInvincible() return invincible; end functionTakeDamage(d) if(not invincible) then this.HealthComponent:Decrease(d); --假设HealthComponent有一个Decrease实现伤害计算 end end
如果将npc.lua和npc这个对象关联起来了,那么我们就可以在lua脚本中可以这样调用了:
npc. SetInvincible(false);
npc.TakeDamage(47)
首先我们在函数TakeDamage中直接调用了HealthComponent的函数Decrease来完成伤害计算.其次我们为对象增加了一个属性invinceble来记录对象的无敌状态.
脚本系统的特性用这样一个假想的例子很难描述出来.那么脚本到底应具有什么样的功能呢?其功能主要有两点:
1. 协助对象与对象之间通信及对象内部通信,
2. 扩展对象的数据属性和方法
根据上述两点特性,我们可以把脚本抽象为一个组件,这种组件拥有一个脚本文件,当附加到一个对象时,该对象就拥有了脚本定义的属性和方法.