原文:一头雾水的"Follow The Pointer"

一头雾水的"Follow The Pointer"
                                                                                                     周银辉

Microsoft Expression Blend中有一个示例程序"Follow The Pointer", 看程序演示会觉得很酷,看代码(点击下载)会觉得一头雾水, 不过现在我便借此介绍一下WPF中的CompositionTarget 以及该示例中设计到了一些物理知识.

一, CompositionTarget
虽然我们拥有Storyboard(故事板)以及Microsoft Expression Blend为WPF动画制作提供强有力的支持,但你会发现这是不够的,也许你希望能通过代码来控制动画中的每一帧,以便显示更加复杂和视觉效果更好的动画, 那么你就得了解CompositionTarget 类.

CompositionTarget 类用于呈现你的应用程序显示表面, 每次绘制时其都会触发其Rendering事件, 其绘制次数取决于你计算机的FPS.
我们可以自定义Rendering事件的处理器来进行一些自定义的绘制或其他工作(注意其会根据计算机的FPS来不停地调用改事件处理器,比如每秒60次,所以不应该在这里进行复杂费时的操作) 比如:

CompositionTarget.Rendering += delegate
{
    this.UpdateColor();
};

这里有一个简单的例子说明CompositionTarget的用法,你可以点击这里下载

二, "Follow The Pointer"中的物理知识
编写视觉效果稍稍好一点的动画时不使用数学或物理知识几乎是不可能的. "Follow The Pointer"示例中用到了力,速度,加速度以及流动摩擦(其变形形式).
动画的简单的流程: 当用户移动鼠标时,程序会计算可移动控件(以下称"小方块",就是跟随鼠标的那个控件)的位置到鼠标位置所形成的向量, 并将该向量作为施加到小方块上的作用力.该作用力会使小方块朝鼠标所在位置移动.假设小方块处于空气(或水等)环境中,小方块的移动会产生流摩擦力,该摩擦力与速度成正比,其会使小方块减速并最终停止下来.
具体如何表现这些物理知识请参考下面的两段代码
这里是原示例代码:

private void CompositionTarget_Rendering(object sender, EventArgs e)
        {
            // Current position of mouse pointer relative to the movable control.
            // The Mouse class is defined in the System.Windows.Input namespace.
            Point mousePos = Mouse.GetPosition(this.MovableControl); 

            TimeSpan currentTime = this.stopwatch.Elapsed;
            double elapsedTime = (currentTime - this.prevTime).TotalSeconds;
            this.prevTime = currentTime;

            // The vector to the mouse pointer represents the force currently acting on the movable control.
            Vector force = new Vector(mousePos.X, mousePos.Y);

            // The smaller the value of damping, the more iterations it takes to approach the mouse pointer, thus allowing velocity to grow larger.
            force = (force * this.SpringSlider.Value - this.velocity * this.DampingSlider.Value) * elapsedTime;

            // The current force causes an acceleration (a change in velocity).
            this.velocity += force;

            // If the eye won't notice any further motion then don't animate on this iteration.
            if (velocity.Length < epsilon)
                return;

            // Distance equals speed times time.
            this.translation.X += this.velocity.X * elapsedTime; 
            this.translation.Y += this.velocity.Y * elapsedTime;
        }

这里是改写与简化后的示例代码:

void CompositionTarget_Rendering(object sender, EventArgs e)
        {

            //上次绘制到此时的时间间隔
            TimeSpan currentTime = this.stopwatch.Elapsed;
            double elapsedTime = (currentTime - this.prevTime).TotalSeconds;           
            this.prevTime = currentTime;

            //鼠标相对于小方块的位置
            Point mouseLoc = Mouse.GetPosition(this.rectangle1);
            //由于改相当位置是相对于小方块左上角的,将其纠正到相当于小方块中心
            mouseLoc.Offset(-this.rectangle1.ActualWidth / 2, -this.rectangle1.ActualHeight / 2);


            //使用鼠标相对于小方块的位置作为外力
            Vector force = new Vector(mouseLoc.X, mouseLoc.Y);

            //流动摩擦力系数假设为该值
            double coefficient = 5;

            //假设小方块质量为1,则加速度为a = force/1;
            //那么在elapsedTime内其速度的变化量为a*elapsedTime
            //由于流动摩擦力与速度成正比,那么流动摩擦力为coefficient * this.velocity
            //所以速度的变化为(force * 200 - coefficient * this.velocity) * elapsedTime
            //这里为了演示中小方块的速度更快一点,我们将外力扩大了200倍
            Vector velocityDelta = (force * 200 - coefficient * this.velocity) * elapsedTime;

            //当前速度
            this.velocity += velocityDelta;

            //小方块的新位置
            this.translation.X += this.velocity.X * elapsedTime;
            this.translation.Y += this.velocity.Y * elapsedTime;
            
        }
       

下载Demo以及源代码

一头雾水的"Follow The Pointer"的更多相关文章

  1. What is the difference between a Clustered and Non Clustered Index?

    A clustered index determines the order in which the rows of a table are stored on disk. If a table h ...

  2. Discovering the Computer Science Behind Postgres Indexes

    This is the last in a series of Postgres posts that Pat Shaughnessy wrote based on his presentation ...

  3. Enhancing the Scalability of Memcached

    原文地址: https://software.intel.com/en-us/articles/enhancing-the-scalability-of-memcached-0 1 Introduct ...

  4. 用arm-linux-gcc v4.3.4交叉编译Qt4.8.3

    1.解压缩 #tar zxvf  qt-everywhere-opensource-src-4.8.3.tar.gz 2. configure #mkdir buildarm-static #cd b ...

  5. Golang源码探索(三) GC的实现原理

    Golang从1.5开始引入了三色GC, 经过多次改进, 当前的1.9版本的GC停顿时间已经可以做到极短. 停顿时间的减少意味着"最大响应时间"的缩短, 这也让go更适合编写网络服 ...

  6. Understanding the Objective-C Runtime

    Wednesday, January 20, 2010 Understanding the Objective-C Runtime The Objective-C Runtime is one of ...

  7. Golang源码探索(三) GC的实现原理(转)

    Golang从1.5开始引入了三色GC, 经过多次改进, 当前的1.9版本的GC停顿时间已经可以做到极短.停顿时间的减少意味着"最大响应时间"的缩短, 这也让go更适合编写网络服务 ...

  8. golang----GC的实现原理

    Golang从1.5开始引入了三色GC, 经过多次改进, 当前的1.9版本的GC停顿时间已经可以做到极短.停顿时间的减少意味着"最大响应时间"的缩短, 这也让go更适合编写网络服务 ...

  9. Python C/C++ 拓展使用接口库(build-in) ctypes 使用手册

    Python C/C++ 拓展使用接口库(build-in) ctypes 使用手册 ctypes 是一个Python 标准库中的一个库.为了实现调用 DLL,或者共享库等C数据类型而设计.它可以把这 ...

随机推荐

  1. Spark jdbc postgresql数据库连接和写入操作源码解读

    概述:Spark postgresql jdbc 数据库连接和写入操作源码解读,详细记录了SparkSQL对数据库的操作,通过java程序,在本地开发和运行.整体为,Spark建立数据库连接,读取数据 ...

  2. linux之sort和uniq

    uniq uniq命令: uniq不加参数,只对相邻的相同行内容去重. 例子如下: [root@localhost ~]# pwd /root [root@localhost ~]# cat oldb ...

  3. 关于Natively Compiled Stored Procedures的优化

    Interpreted Transact-SQL stored procedures are compiled at first execution, in contrast to natively ...

  4. oracle权限管理学习

      Oracle 权限 权限允许用户访问属于其它用户的对象或执行程序,ORACLE系统提供三种权限:Object 对象级.System 系统级.Role 角色级.这些权限可以授予给用户.特殊用户pub ...

  5. Sql 查询结果 根据某个字段值 变更另外一个字段值 case when

    SELECT CASE THEN '*******' ELSE Plate END AS Plate, CarType FROM Cars;

  6. Solr全文检索

    1.Solr的安装 .环境要求 jdk1.+tomcat8+solr5.5.0 .将以上的软件包上传到服务器 . 安装tomcat8(解压文件) tar -zxvf apache-tomcat-.ta ...

  7. tkinter学习系列之(五)Checkbutton控件

    目录 目录 前言 (一)基本属性 (二)案例 1.简单的复选框 2.组合复选框 目录 前言 复选框:可以同时多选的一组框,其只有两种状态,选中与未选中. (一)基本属性 (1)说明: tkinter里 ...

  8. nginx limit_rate突然限速失败

    ##问题 nginx限制用户对指定目录的访问: <!-- lang: shell --> location ~ ^/(path001)/ { limit_rate 0k; limit_co ...

  9. 【Java学习系列】第4课--Java Web相关

    本文地址 分享提纲: 1.概述 2. Jsp基础 2.1 1.概述 1.1)[来源和先导] 本文主要的java web的教程来源JSP是 菜鸟教程JSP 和 天码营Java Web.     主要的先 ...

  10. PyQt5--TextDrag

    # -*- coding:utf-8 -*- ''' Created on Sep 21, 2018 @author: SaShuangYiBing Comment: ''' import sys f ...