Torque2D MIT 学习笔记(8) TAML的高级使用

TAML 编译

当你要将一个对象写入到TAML时,并不意味着之写入单一的对象,写入操作同样将作用于他的子对象.

在写入的时候会遵循若干个步骤:

  1. 查找所有静态和动态的属性Field进行写入,保存.
  2. 查找所有的子对象进行写入,保存.
  3. 查找所有自定义状态进行写入,保存.

静态和动态属性的编译

这个过程实际上是由两部分组成,首先是遍历所有的静态属性域,并检测他们是否应该被写入文件.要注意的是这个检测操作只在没有前置调用WriteDefaults的情况下执行.

在引擎的属性域系统中预先指定了每个属性的相关接口,有设置,获取,写入方法,如下:

addProtectedField("Angle", TypeF32, NULL, &setAngle, &getAngle, &writeAngle, "");

比如WriteAngle方法,如果谁想知道这个Angle域是否能被写入都可以进行调用来询问,用代码说明:

// 添加image属性域
addProtectedField("image", TypeImageAssetPtr, Offset(mImageAsset, ImageFont), &setImage, &getImage, &writeImage, "");

// writeImage的实现
static bool writeImage( void* obj, StringTableEntry pFieldName )  
{ 
    // 检测资源是不是为空(空为默认,证明没有改变过)
    return static_cast<ImageFont*>(obj)->mImageAsset.notNull(); 
}

TAML快速遍历所有的静态属性域并检测他们,形成一张需要写入的静态属性域列表.

接下来,TAML快速遍历所有的动态属性域,并直接将他们加入写入列表.因为动态属性是在脚本中创建的,没有相关的检测接口,所以无法决定是否需要写入.

子对象编译

TAML先对写入对象进行检测是不是继承于TamlChildren,如果是则会查询包含多少子对象.

参照代码可见:

// 直接继承于TamlChild的类有三个(也有二次继承的,这里省略)
class ParticleAsset : public AssetBase, public TamlChildren
class SimSet: public SimObject, public TamlChildren
class Scene : public BehaviorComponent,
public TamlChildren,
public PhysicsProxy,
public b2ContactListener,
public b2DestructionListener, public virtual Tickable
// 编译代码中 void Taml::compileChildren( TamlWriteNode* pTamlWriteNode ) { ..... // 编译对象 SimObject* pSimObject = pTamlWriteNode->mpSimObject; // 类型转换为TamlChildren. TamlChildren* pChildren = dynamic_cast<TamlChildren*>( pSimObject ); // 这里要判断是不是转换成功以及有没有子对象 if ( pChildren == NULL || pChildren->getTamlChildCount() == 0 ) return; }

如果存在子对象,TAML将遍历所有的子对象,并递归的进行它们属性域,自定义状态,子对象的写入.

如上所示,SimSet继承于TamlChildren,可以包含很多的SimObject,同样适用于包含多个SceneObject的Scene,如下代码:

%list = new SimSet();

// Add some objects.
%list.add( new ScriptObject() );
%list.add( new ScriptObject() );
%list.add( new ScriptObject() );

// Write out the list.
TamlWrite( %list, "list.taml" );

 写入的内容:

<SimSet>
     <ScriptObject/>
     <ScriptObject/>
     <ScriptObject/>
  </SimSet>

XML 格式

与XML格式相比,想要阅读或者编辑二进制格式的文件是很困难的,而XML格式在开发和编辑过程中容易使用.

下面是一个比较具体的脚本例子:

// 创建一个SimSet对象实例
%bookList = new SimSet()
{
    Title="My Book List"; // 增加动态域Titile
};

// 创建几个Script对象,并设置相关的动态域
%book1 = new ScriptObject()
{
    Title="Torque 3D Game Development Cookbook";
    Author="Dave Wyand";
};

%book2 = new ScriptObject()
{
    Title="Graphics Programming Black Book (Special Edition)";
    Author="Michael Abrash";
};

%book3 = new ScriptObject()
{
    Title="Programming with Graphics";
    Author="Garry Marshall";
};

// 加入simSet
%bookList.add( %book1 );
%bookList.add( %book2 );
%bookList.add( %book3 );

// 写入TAML文件
TamlWrite( %bookList, "booklist.taml" );

文件结果如下:

<SimSet
	Title="My Book List">
	<ScriptObject
		Title="Torque 3D Game Development Cookbook"
		Author="Dave Wyand"/>
	<ScriptObject
		Title="Graphics Programming Black Book (Special Edition)"
		Author="Michael Abrash"/>				
	<ScriptObject
		Title="Programming with Graphics"
		Author="Garry Marshall"/>				
  </SimSet>

XML的布局方式非常的简洁.

每一个XMl节点代表着一种能够被引擎认可并创建的类型.

每一个XMl属性都是一个属性域.这个属性域可以是静态或者动态属性域名.

TAML支持同一个对象在同一个TAML文件中多处存在,比如: 

%list = new SimSet();

%obj = new ScriptObject();
%list.add( %obj );
%list.add( %obj );
%list.add( %obj );

TamlWrite( %list, "list.taml" );

 产生的结果是:

<SimSet>
	<ScriptObject TamlId="1"/>
	<ScriptObject TamlRefId="1"/>
	<ScriptObject TamlRefId="1"/>
</SimSet>

命名对象

TAML支持Torque对象的命名,不过要特别注意的是相同名字重复而产生的丢失问题.

所以使用全局唯一的对象名是必要的,尤其是GUI文件.使用方法如下:

TamlWrite( new ScriptObject(Fred), "test.taml" );
// 输出
<ScriptObject Name="Fred"/>

TAML事件回调

  TAML提供了一个TamlCallbacks的监听器来执行对象的读写通告,SimObject继承了这个监听器,因此每一个对象都可以处理TAML的事件回调.具体回调如下:

  • onTamlPreWrite() - 对象写入前调用.
  • onTamlPostWrite() - 对象写入后调用.
  • onTamlPreRead() - 对象状态读取前调用.
  • onTamlPostRead() - 对象状态读取后调用.
  • onTamlAddParent() - onTamlPostRead()调用后并添加到父对象后调用.
  • onTamlCustomWrite() - 对象自定义属性写入期间调用.
  • onTamlCustomRead() - 对象自定义属性读取期间调用.
原文地址:https://www.cnblogs.com/KevinYuen/p/2940493.html