Silverlight开发MMORPG游戏研讨(4):用一个定时器实现多个不同帧频的动画

上一篇文章介绍了用CompositionTarget_Rendering实现固定时间间隔定时器。本篇将继续这个话题,介绍该定时器的一个实际应用:用一个定时器实现多个帧频不同的动画,笔者正在开发的MMORPG游戏中使用了该技术。前文讨论了该定时器的优点之一,即动画帧只在即将提交UI前处理,可以根据silverlight程序的帧频的变化而自适应调整。本文讨论另外一个优点:不同帧频的动画可以共享同一个定时器。而用其他定时器实现这个需求要麻烦很多。
 
假设要实现两组动画:动画A和动画B。动画A的帧间隔是100毫秒,动画B的帧间隔是120毫秒。如果用dispatcher timer或storyboard实现,需要怎么做呢?我们不得不先取得两个时间间隔的最大公约数20毫秒,作为定时器的时间间隔,然后每隔5次或6次处理动画A或动画B。但是这个方法的前提条件是可以取得一个合理的最大公约数。如果需要实现更多的动画,而且时间间隔各不相同,或者最大公约数为1毫秒,这个方法的代价就太大了。因为间隔1毫秒的定时器意味着定时器事件过于频繁,造成系统负担。如果某个动画的时间间隔为250毫秒,意味着249次定时器事件都是浪费的。显然这个方法的效果不太理想。
 
用上文介绍定时器,该问题迎刃而解。定时器的时间间隔总是随着程序运行的帧频自动变化,从而保证在不影响动画效果的情况下单位时间内定时器事件次数最少。每个动画的时间间隔则由各自的类来控制。动画类的代码如下。
 
     public   class  Sprite:Canvas
    {
        
int  _timerlInterval  =   100 //  ms
         int  _lastElapsed  =   0 ;
        
double  _left;
        
double  _top;

        
public  Sprite( int  speed,  double  left,  double  top)
        {
            _timerlInterval 
=  speed;
            _left 
=  left;
            _top 
=  top;
            
this .Loaded  +=   new  RoutedEventHandler(Sprite_Loaded);
        }

        
void  Sprite_Loaded( object  sender, RoutedEventArgs e)
        {
            
this .Children.Add(body);
            Canvas.SetLeft(
this , _left);
            Canvas.SetTop(
this , _top);
            CompositionTargetMainLoop.Instance.Timeout 
+=   new  MainLoop.UpdateHandler(Instance_Timeout);
        }

        Image body 
=   new  Image()
        {
            Stretch
=  Stretch.None
        };

        
int  currentFrame = 4 , endFrame = 9 ;
        
void  Instance_Timeout( object  sender,  int  elapsed)
        {
            _lastElapsed 
+=  elapsed;
            
if  (_lastElapsed  >=  _timerlInterval)
            {
                
while  (_lastElapsed  >=  _timerlInterval)
                    _lastElapsed 
-=  _timerlInterval;

                
//  display frames
                currentFrame ++ ;
                
if  (currentFrame  >  endFrame) { currentFrame  =   4 ; }
                
string  imgPath  =   string .Format( " images/0-{0}.png " , currentFrame);
                body.Source 
=   new  BitmapImage( new  Uri(imgPath, UriKind.Relative))
                {
                    CreateOptions 
=  BitmapCreateOptions.None
                }; 
            }
        }
    }

 

 
主程序部分代码如下。
 
         void  MainPage_Loaded( object  sender, RoutedEventArgs e)
        {
            
//  add sprites
             this .LayoutRoot.Children.Add( new  Sprite( 100 , 100 , 10 ));
            
this .LayoutRoot.Children.Add( new  Sprite( 200 , 300 , 10 ));

            
//  start timer (main game loop)
            CompositionTargetMainLoop.Instance.Start();
        }

 

 
可以看出,通过一个主定时器,理论上可以添加任意多帧间隔不同的动画。当然添加的动画越多,每次定时事件处理的事务就越多,对UI线程的影响就越大。所以原则上不要在定时事件中处理复杂逻辑运算。另外一点需要注意的是每个动画的帧间隔在统计意义上是固定的,但是每次帧间隔并不完全相同,不过在动画效果上与固定帧间隔是完全相同的。这是由CompositionTarget_Rendering的原理决定的。演示如下:
 
 
 
演示项目源码在 这里下载

转载于:https://www.cnblogs.com/erichan/archive/2010/05/13/1734168.html

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值