Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1017157
  • 博文数量: 243
  • 博客积分: 3053
  • 博客等级: 中校
  • 技术积分: 2975
  • 用 户 组: 普通用户
  • 注册时间: 2009-05-02 21:11
文章分类

全部博文(243)

文章存档

2013年(2)

2012年(20)

2011年(5)

2010年(114)

2009年(102)

我的朋友

分类:

2010-09-14 12:32:05

用CompositionTarget_Rendering实现固定时间间隔定时器

 
Silverlight提供了大致五种定时方式,这篇文章比较了各种定时方式的特点和应用环境。限于篇幅,本文就不赘述了。本文主要讨论实现游戏动画的定时器应用,当然还是针对正在开发的MMORPG游戏。 一般来说,除非是很特殊很复杂的应用,storyboard,dispatcher timer和CompositionTarget_Rendering三种方式就足够应付了。
  
简单说来,storyboard动画的实质就是控制UIElement的属性随时间的变化来实现动画效果。因为silverlight控制所有内部变化细节,动画效果比较平滑。相比之下,dispatcher timer来实现相同的动画,就需要多一些代码来控制了。不过有些动画无法用UIElement的属性变化来体现,也就不能直接用storyboard来实现,这时候就需要考虑dispatcher timer了。dispatcher timer其实跟普通定时器(例如Thread.Timer)没有太大差别,唯一特殊的是dispatcher timer和UI运行在同一个线程,所以比较适合实现UI动画。总的来说,几种定时方式并无孰优孰劣之分,只有使用场合的不同。
 
本文重点讨论CompositionTarget_Rendering定时方式来实现动画。为什么青睐于CompositionTarget_Rendering呢?可能读者已经知道CompositionTarget_Rendering的事件在UI即将提交的时候触发,与silverlight应用程序的帧频是一致的。换句话说,无论动画理论上变化多快,帧频多高,最终反映到计算机显示器上,帧频是不可能高于silverlight应用程序的最大帧频的。也就是说,很多帧只是在内存中闪了一下,并没有机会显示在屏幕上。可以想象这是多么大的浪费,尽管没有验证过,相信性能上会受影响。因为CompositionTarget_Rendering的事件在UI即将提交的时候触发,此时来决定需要显示的帧,避免了资源浪费。尤其在silverlight应用程序的最大帧频设置变化的情况,CompositionTarget_Rendering可以自适应的调整动画的帧频,保证最大限度的节省资源消耗。
 
CompositionTarget_Rendering严格讲不是一个定时器,因为我们不能控制触发的时间间隔。因为CompositionTarget_Rendering事件的触发由silverlight应用程序的帧频决定,而silverlight应用程序的帧频由最大帧频设置和硬件环境等因素决定,所以CompositionTarget_Rendering事件的触发的时间间隔是不固定的,大致上等于(1000/最大帧频设置)毫秒。对于动画控制,变化的时间间隔是不能接受的。所以我们需要模拟一个固定时间间隔的CompositionTarget_Rendering定时器。具体看下面的代码。
 
    public abstract class MainLoop
    {
        
protected DateTime lastTick;
        
public delegate void UpdateHandler(object sender, int elapsed);
        
public event UpdateHandler Timeout;

        
public void Tick()
        {
            DateTime now 
= DateTime.Now;
            var elapsed 
= (now - lastTick).Milliseconds;
            lastTick 
= now;
            
if (Timeout != null) Timeout(this, elapsed);
        }

        
public virtual void Start()
        {
            lastTick 
= DateTime.Now;
        }

        
public virtual void Stop()
        {
        }

    }

 

 
MainLoop类是抽象基类,定义公共的方法和事件接口。CompositionTargetMainLoop类继承并实现MainLoop类。当然也可以只用一个类来实现。用基类和具体类来实现的好处是可以用不同的方法(例如dispatcher timer)来实现该基类,但是保持相同的接口,便于不同定时方式实现之间的互换。
 
该定时器本身并不提供固定时间间隔的定时,实际上定时的事件总是和UI的帧频保持一致的,由前面的讨论可知,该时间间隔受最大帧频设置,硬件配置,运行环境的因素影响而变化,是不确定的。解决的办法是在每次定时事件中提供距离上次定时事件的时间间隔,然后由使用该定时器的类来计算模拟固定时间间隔。代码如下。
 
        void Instance_Timeout(object sender, int elapsed)
        {
            _lastElapsed 
+= elapsed;
            
if (_lastElapsed >= _timerlInterval)
            {
                
while (_lastElapsed >= _timerlInterval)
                    _lastElapsed 
-= _timerlInterval;
                ...
            }
        }
阅读(1847) | 评论(0) | 转发(0) |
0

上一篇:Http模块

下一篇: 简单容器(转)

给主人留下些什么吧!~~