第七章,流程与动画

      假设现在我们要在视域中播放一组gif动画,时长20秒播放3遍,应该怎么办?唔,毫无疑问,你应该有个定时器,固定时间间隔检测一下是否跳转到一下帧。好的,现在我们要播放一百组这样的gif动画,在屏幕的不同地方,他们的起始时间和播放次数都不尽相同,有些快有些慢。。。相信你一定囧到了。

     另举一例,假设我们要使一个物体加速前进,初始速度v,加速度a,直到命中目比地(x,y)为止。这两个例子的共同点是:我们想要达到的效果是确定的,但却不能在当前时刻立即完成,需要有一个模块(函数)来定时更新状态。我们把这种确定目标,随时间逐步更新的事件称为“动画申请”,通常用APPLY来指代和命名。毫无疑问,这个更新实体状态的函数必须是应用层定制的,以达到特定的目标。而定时触发的工作将由内核来完成。

     下面我们用库函数APPLY_ShowObject的实现来示例如何完成一个动画申请函数。这个函数按照指定的半透明度变化率渐显或渐隐实体,形式如下:

 

 

BOOL FP_ShowObject(PObject* ob, BYTE* data, GameCore* m_core, DWORD time)
{
                APPLYINFO_SHOWAPHPA* info=(APPLYINFO_SHOWAPHPA*)data;
                 if (info->alphaspeed<0
                  &&ob->GetAlpha()<=info->alphadest)
                 {
                                  ob->SetAlpha(info->alphadest);
                                  ob->Updata();
                                  return TRUE;
                 }
                 else if(info->alphaspeed>0
                  &&ob->GetAlpha()>=info->alphadest)
                 {
                                  ob->SetAlpha(info->alphadest);
                                  ob->Updata();
                                    return TRUE;
                 }
 
                 double new_alpha=ob->GetAlpha()+info->alphaspeed;
                 if (new_alpha<0)
                         new_alpha=0;
                 else if (new_alpha>1)
                          new_alpha=1.0;

                 ob->SetAlpha(new_alpha);
                 ob->Updata();
                 return FALSE;
}

 

 

 

EVENTHANDLE     CClassSenior::APPLY_ShowObject(  PObject*  ob,          //实体,不能为空
                                                                          double   alphaspeed,  //每次变化的透明度,变化间隔取决于系统间隔
                                                                          double   alphadest,    //当无法到达角度时,将一直旋转
                                                                         DWORD    nTimeSpace, //触发间隔)
                                                                        SNG_MSG* CallBackMsg //回调消息)

{

                 if (alphadest>ob->GetAlpha()&&alphaspeed<0)
                 {
                              return 0;
                 }
                 else if (alphadest<ob->GetAlpha()&&alphaspeed>0)
                 {
                              return 0;
                 }
                 else if (alphaspeed==0)
                 {
                              return 0;
                 }

                 APPLYINFO_SHOWAPHPA temp={alphaspeed,alphadest};
                 APPLY* apply=GetObjectModule()->CreateApply();
                 apply->ObjectPtr=ob;
                 if (CallBackMsg)
                                  memcpy(&apply->CallBackMsg,CallBackMsg,sizeof(SNG_MSG));
                 apply->fp_applyfuction=FP_ShowObject;
                 if (nTimeSpace<GetMinApplySpace()) 
                                  nTimeSpace=GetMinApplySpace();
                 apply->dwSpaceCount=nTimeSpace;
                 memcpy(apply->param,&temp,sizeof(APPLYINFO_SHOWAPHPA));
                 GetCore()->PostQuest(OBJECT_MODULE,SNG_QUEST_CRAETE_APPLY,apply,NULL);
                 return apply->EventHandle;

}

 

   全局函数FP_ShowObject既为状态更新函数,内核会按照APPLY结构中指定的时间间隔调用该函数。APPLY结构如下:

 

#define APPLY_COMMON_DATA_LENGTH   64
 typedef BOOL (*FP_APPLYFUCTION)(PObject*,   //实体指针
                                                     BYTE*,      //数据
                                               GameCore*,  //传入GameCore
                                                  DWORD);     //传入当前时间,游戏开始后的毫秒计数

 typedef struct _tagAPPLY{
             EVENTHANDLE   EventHandle;    //事件ID
              _tagGroup*   MyGroup;        //组
             PObject*   ObjectPtr;      //实体指针
                BOOL    bnLocked;       //是否锁定
                BOOL    bnStoped;       //是否已被提前结束
               DWORD   StartTick;  //消息开始处理的时间
               DWORD    dwLastRunTick;  //上一次触发的时间
               DWORD    dwSpaceCount;   //间隔处理时间
               BYTE    param[APPLY_COMMON_DATA_LENGTH];//常用信息位
               FP_APPLYFUCTION     fp_applyfuction;//函数指针
               SNG_MSG    CallBackMsg; //事件结束时的回调消息
               _tagAPPLY*   NextApply;
 }APPLY,*LPAPPLY;

 

     当用户定制动画申请函数时,APPLY结构中的调用间隔,事件结束后的回调消息CallBackMsg以及函数指针是必须填写的,如需用到一些额外的参数,请将参数值以结构的形式拷贝到APPLY结构Param数组中。注意,在刷新函数FP_APPLYFUCTION中,如果返回TRUE,则该动画申请将被中止,如设置了回调消息,该消息将被异步投递。反之,则动画申请继续等待下一次被调用。

 

     现在我们可以很简单的播放动画了,大功告成。

 

     BITObject* bit;

     bit->LoadPic("某动画");

     APPLY_PlayBitObject(bit);//这是播放动画函数的库函数,具体参见ShinyNovaGui.h

 

 

      下面考虑一个新的问题,假设我们要播放A动画和B动画,然后在A动画和B动画都完成后播放C动画。又或者先播放A动画后播放B动画然后播放C动画。有消息机制这个当然不难解决,我们可以为每个动画申请设计一个回调消息,只有当回调消息足够多时再继续我们的下一步流程。在代码规模较小时,这不失为一个好办法。但如果游戏中有大量这样串行或者并行的流程,那么你将为管理和处理如此之多的消息而头疼不已。为此,ShinyNova提供了一组简单的函数来实现对固定流程的约束工作:

     BeginGroup();

         APPLY_1();

             BeginGroup();

                    APPLY_2();

             NextGropu();

                    APPLY_3();

             EndGroup();

     NextGroup();

         APPLY_4();

     EndGroup();

 

     每个Group内的动画申请将被并行执行,不同的Group将被串行执行。现在,你可以让你的游戏人物一边抽烟一边跳一曲华尔兹,然后优雅的向女士行礼了。

    

   

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值