CryEngine3中的AnimationGraph编程

C++的实现类

AnimationGraph代码方面由两部分组成:

         静态部分(class  = CAnimationGraph=

         动态部分(class  = CAnimationGraphState=

静态部分代表了图的结构并且每个部件的属性。每一个加载的加载的AnimationGraph文件都有一个实例。所有这些都隶属于一个AnimationGraph的管理器(=CAnimationGraphManager=)。

动态部分代表了关卡中一个角色实体实例当前的状态。AnimationGraph这部分属于一个动画角色(=CAnimatedCharacter=)。

如果一个角色使用了两个AnimationGraph,他们是两个被动态两部分AnimationGraph。他们被封装到一个包装类里,作为单一的CAnimationGraphState类行为相同。这个CAnimatedCharacter类拥有自己的包装类,并且包装类拥有这两个AnimationGraph部分。

设置输入值

         AnimationGraph输入的值 可以通过引擎的任何模块修改,也可以通过Lua脚本。

使用C++代码

         需要一个角色的IAnimationGraphState指针对象(AnimationGraph动态部分的接口)它有这样一些方法会被调用。

         bool SetInput( InputID, float, TAnimationGraphQueryID * pQueryID = 0 );

bool SetInput( InputID, int, TAnimationGraphQueryID * pQueryID = 0 );

bool SetInput( InputID, const char *, TAnimationGraphQueryID * pQueryID = 0 );

第一个参数是InputID号。第二个值的设置将会被转换为匹配的输入类型。第三个参数是可选择的,用于获取一个查询编号,更具操作需求在附加反馈信息时使用。(例如当动画匹配输入值开始时)。

如果操作成功返回值为true

以下也是一样的,只是它在没有存在值通过下不会默认输入值。因此这可能在你只想改变上半身动作而不影响全身动画时是非常有用的。

bool SetInputOptional( InputID, const char *, TAnimationGraphQueryID * pQueryID = 0 );

输入可以用过他们的名字而不是ID来制定,使用此方法:

template <class T> inline bool SetInput( const char * name, T value, TAnimationGraphQueryID * pQueryID = 0 );

使用一个字符串来查询ID,因此首选方法参数输入是存储变量的ID,以备以后应用。输入名称可以转换成 输入ID的使用方法:

InputID GetInputId( const char * input ) = 0;

使用LUA脚本

         不建议在脚本里更改AnimationGraph的输入值,但还是可能做的.为此,Lua脚本功能将被应用与:

         Entitiy.actor:SetAnimationInput(name,value)

         Entity是脚本列表中的实体,名字是Input的输入名,Value是它要设置的值。

实施一个新的节点类型

         对于AnimationGraph工厂的每一个节点类型都需要在AnimationGraph管理器里注册。这可以通过CAnimationGraphManger::RegisterFactories函数来做。

         该系统需要存储一个任意节点类型,通过属性组合来初始化实例。为了能够区分独特属性的组合和对已经创建的实例进行排序,关键是通过节点工厂方法virtual bool !IsLessThan( IAnimationStateNodeFactory * pFactory )来实现。这个方法应该返回所有节点直接存储的数据成员和派生值的属性值比较的结果,使用预处理宏可以简化执行。例如像CAGFacial这个C++类采取的例子:

                    virtual bool IsLessThan( IAnimationStateNodeFactory * pFactory )

{

                 AG_LT_BEGIN_FACTORY(CAGFacial);

                                      AG_LT_ELEM(m_expressionNameIdle);

                                      AG_LT_ELEM(m_expressionNameAlerted);

                                      AG_LT_ELEM(m_expressionNameCombat);

                 AG_LT_END();

}

         新的节点通过调用工厂的Create()方法来创建。一个相应节点类新的实例需要被创建并返回给调用者。在某种情况且当节点通过一种方法被执行时它不需要存储任何动态数据(所以它是一个可以共享的节点),然后工厂实例也可以是同一时间的节点实例。在这种情况下该功能可以简单的实现为:

        IAnimationStateNode * CAGSomeFactoryAndNodeClass::Create()
{
                  return this;
}

         一些节点依赖于他们的类型或者有些时候依赖于他们的属性值,需要每帧更新(仅当该节点属于当前状态)。如果真的是这样,那么它初始化玩后节点鼻血设置eASNF_Update的标志。后来的每帧当节点被激活它的virtual void Update( !SAnimationStateData& data )函数将会被调用。

         节点提供覆盖的一些虚方法

         virtual void EnterState( SAnimationStateData& data, bool dueToRollback );

virtual EHasEnteredState HasEnteredState( SAnimationStateData& data );

virtual void EnteredState( SAnimationStateData& data ) {}

virtual bool CanLeaveState( SAnimationStateData& data );

virtual void LeaveState( SAnimationStateData& data );

virtual void LeftState( SAnimationStateData& data, bool wasEntered ) {}

       如果从当前状态转换到另一个状态需要当前状态可以通过调用CanLeaveState函数来查询它时候开始过渡到下一个状态。每个节点都有转换的否决权。一旦所有节点都返回treue才开始转换。

         在一个转换到另一个状态的的开始,LeaveState方法是当前状态的每一个节点第一个被调用方法。然后会为下一个状态的每个节点调用EnterState方法。这些节点会被清除用这些方法进行初始化他们的数据。因为这些方法是在动画真正开始之前被调用。大多数节点不会在这里做任何事除了AnimationLayerX节点将他们的动画压入动画队列之中。

         下一步,该系统不断的通过调用HasEnteredState函数查询下一个状态的每一个节点。该函数会被以下列状态返回;

         eHES_Instant —— 如果这个节点不影响进入

         eHES_Wating —— 如果该节点影响进入并且进入工作仍在进行中

         eHES_Entered —— 如果该节点通知系统进入工作已经完成

         例如实例的AnimationLayerX节点正在监视动画队列则返回eHES_Waiting知道他们的动画开始播放的时候才返回eHES_Entered。这用于对于其他节点的动画同步。一旦一个几点返回了eHES_EnteredAnimationGraph状态间的转换就结束了(注意这个时候动画间的转换刚刚开始并没有结束)。当前状态的节点会被通知调用它们的LeftState方法并且下一个状态的节点开始调用EnteredState方法。

         大部分节点在调用HasEnteredState时返回eHES_Instant,因为他们提供的功能只是与动画播放相关。如果下个状态的所有节点都返回eHES_Instant则意味着这个图正在进入一个空状态,在这种转换完成和下一个状态正在成为当前状态的情况下,由于它是一个空状态并且不会播放任何动画,所有LeftStateEnteredState方法不会被调用。但对先前状态下的节点的LeftState方法会被在其他非空状态进入后被调用。

 

 

作者:无花无酒
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.

 

posted on 2009-12-15 15:41  无花无酒  阅读(901)  评论(0编辑  收藏  举报