Silverlight:Mouse Avoiding 躲避鼠标效果

昨晚在一国外博客上(从域名后缀pl上猜想应该是波兰)看到这种效果(Mouse Avoid 躲避鼠标),是基于Flash/AS3开发的,这个示例把弹性运动摩擦力均加速运动等多种物理学原理综合运用在一起,产生了不错的交互效果。


在线演示

as3.0代码如下:

package {
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.geom.Point;

	public class MouseAvoider extends Sprite {

		private const SPRING:Number=0.1;//弹性系数
		private const FRICTION:Number=0.9;//摩擦系数
		private const FEAR_DISTANCE:Number=150;//安全距离(小于该距离则发生躲避行为)
		private const MAX_AVOID_FORCE:uint=10;//最大躲避速度

		private var _destinationPoint:Point;//目标静止点(鼠标远离该物体时,物体最终会静止的坐标点)
		private var _speed:Point=new Point(0,0);//速度矢量(_speed.x即相当于vx,_speed.y即相当于vy)

		public function MouseAvoider():void {
			drawStuff();
		}

		private function drawStuff():void {
			//默认先画一个半径为10的圆
			graphics.beginFill(Math.random() * 0xFFFFFF);
			//graphics.beginFill(0xFFFFFF);
			graphics.drawCircle(0, 0, 5);
			graphics.endFill();
		}

		//只写属性(设置目标点)
		public function set destinationPoint(value:Point):void {
			_destinationPoint=value;
			addEventListener(Event.ENTER_FRAME, enterFrameHandler);
		}

		protected function enterFrameHandler(e:Event):void {
			moveToDestination();//先移动到目标点
			avoidMouse();//躲避鼠标
			applyFriction();//应用摩擦力
			updatePosition();//更新位置
		}

		//以弹性运动方式移动到目标点
		private function moveToDestination():void {
			_speed.x += (_destinationPoint.x - x) * SPRING;
			_speed.y += (_destinationPoint.y - y) * SPRING;
		}

		//躲避鼠标
		private function avoidMouse():void {
			var currentPosition:Point=new Point(x,y);//确定当前位置
			var mousePosition:Point=new Point(stage.mouseX,stage.mouseY);//确实鼠标位置
			var distance:uint=Point.distance(currentPosition,mousePosition);//计算鼠标与当前位置的距离

			//如果低于安全距离
			if (distance<FEAR_DISTANCE) {
				var force:Number = (1 - distance / FEAR_DISTANCE) * MAX_AVOID_FORCE;//计算(每单位时间的)躲避距离--即躲避速率
				var gamma:Number=Math.atan2(currentPosition.y- mousePosition.y,currentPosition.x- mousePosition.x);//计算鼠标所在位置与当前位置所成的夹角

				var avoidVector:Point=Point.polar(force,gamma);//将极坐标转换为普通(笛卡尔)坐标--其实相当于vx = force*Math.cos(gamma),vy = force*Math.sin(gamma)

				//加速 躲避逃开
				_speed.x+=avoidVector.x;
				_speed.y+=avoidVector.y;
			}
		}

		//应用摩擦力
		private function applyFriction():void {

			_speed.x*=FRICTION;
			_speed.y*=FRICTION;
		}

		//最终更新自身的位置
		private function updatePosition():void {

			x+=_speed.x;
			y+=_speed.y;
		}

	}
}

测试代码:

package {
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.Sprite;
	import flash.filters.BlurFilter;
	import flash.geom.ColorTransform;
	import flash.geom.Point;
	import flash.events.Event;
	import flash.geom.Rectangle;

	/**
	* ...
	* @author Andrzej Korolczuk
	*/
	[SWF(height="300",width="400")]
	public class MouseAvoiderTest extends Sprite {

		private var background:Bitmap;
		private var backgroundBitmapData:BitmapData;
		private var container:Sprite = new Sprite();
		private var bounds:Rectangle;
		private var blur:BlurFilter=new BlurFilter(5,5);
		private var colorTransform:ColorTransform=new ColorTransform(0.9,0.9,0.9);

		public function MouseAvoiderTest() {
			addEventListener(Event.ADDED_TO_STAGE, init);
		}

		private function init(e:Event):void {
			bounds=new Rectangle(0,0,stage.stageWidth,stage.stageHeight);
			addChild(container);
			backgroundBitmapData=new BitmapData(stage.stageWidth,stage.stageHeight,true,0xff000000);
			background=new Bitmap(backgroundBitmapData);
			addChild(background);
			var i:uint=7;
			while (i--) {
				addAvoider();
			}
			addEventListener(Event.ENTER_FRAME, enterFrameHandler);
		}

		//创建MouseAvoider实例
		private function addAvoider():void {
			var avoider:MouseAvoider = new MouseAvoider();
			container.addChild(avoider);
			//随机设置目标点
			avoider.destinationPoint = new Point(100+(stage.stageWidth-200) * Math.random(), 100+(stage.stageHeight-200)  * Math.random());
		}

		private function enterFrameHandler(e:Event):void {
			backgroundBitmapData.draw(container);//根据container的内容生成位图数据
			backgroundBitmapData.applyFilter(backgroundBitmapData, bounds, new Point(0, 0), blur);//应用模糊滤镜
			backgroundBitmapData.colorTransform(bounds, colorTransform);//应用颜色滤镜(r,g,b颜色值均变成原来的90%)
			for (var i:uint = 0; i < container.numChildren; i++) {
				var avoider:MouseAvoider=container.getChildAt(i) as MouseAvoider;
				//r,g,b三色分量的偏移量设置为随机数(这样看上去就会不停的闪烁)
				avoider.transform.colorTransform=new ColorTransform(1,1,1,1,Math.random()*30,Math.random()*30,Math.random()*30);
			}
		}

	}

}

看完AS3的代码后,我就在想如何移植到Silverlight上来,下午抽空研究了一下,基本上用Silverlight还原出来了,但由于Silverlight在Bitmap编程方面的功能有点弱,另外没有Flash中的ColorTransForm颜色变换(也有可能是我没找到silverlight中对应的方法),效果上还是有点差距
先定义一个控件MouseAvoider.xaml:

<UserControl x:Class="MouseAvoider.MouseAvoider"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="10" d:DesignWidth="10">

    <Canvas>
        <Ellipse Width="10" Height="10" Fill="White" StrokeThickness="0" x:Name="ball">
            <Ellipse.RenderTransform>
                <ScaleTransform x:Name="scale"></ScaleTransform>
            </Ellipse.RenderTransform>
        </Ellipse>
    </Canvas>
</UserControl>

后端cs代码:

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace MouseAvoider
{
    public partial class MouseAvoider : UserControl
    {
        private double _spring = 0.1;
        private double _friction = 0.92;
        private int _fear_distance = 150;
        private int _max_avoid_force = 10;
        private Point _destinationPoint;
        private Point _speed = new Point(0, 0);

        public MouseAvoider()
        {
            InitializeComponent();

            this.Loaded += new RoutedEventHandler(MouseAvoider_Loaded);
        }

        void MouseAvoider_Loaded(object sender, RoutedEventArgs e)
        {
            //如果要实现彩色,将下面代码启用即可
            //Random rnd = new Random();
            //System.Threading.Thread.Sleep(5);
            //this.ball.Fill = new SolidColorBrush(Color.FromArgb(255,(byte)rnd.Next(0,256),(byte)rnd.Next(0,256),(byte)rnd.Next(0,256)));
        }

        public Point DestinationPoint
        {
            set
            {
                _destinationPoint = value;
                CompositionTarget.Rendering += new EventHandler(CompositionTarget_Rendering);
            }
        }

        private double X
        {
            get
            {
                return (double)this.GetValue(Canvas.LeftProperty);
            }
            set
            {
                this.SetValue(Canvas.LeftProperty, value);
            }
        }

        private double Y
        {
            get
            {
                return (double)this.GetValue(Canvas.TopProperty);
            }
            set
            {
                this.SetValue(Canvas.TopProperty, value);
            }
        }

        void CompositionTarget_Rendering(object sender, EventArgs e)
        {
            //以弹性运动方式移动到目标点
            _speed.X += (_destinationPoint.X - X) * _spring;
            _speed.Y += (_destinationPoint.Y - Y) * _spring;

            //躲避鼠标
            Point currentPosition = new Point(X,Y);
            Point mousePosition = (App.Current.RootVisual as MainPage).MousePosition;
            var dx = currentPosition.X - mousePosition.X;
            var dy = currentPosition.Y - mousePosition.Y;
            double distance = Math.Sqrt(dx * dx + dy * dy);
            if (distance < _fear_distance)
            {
                double force = (1 - distance / _fear_distance) * _max_avoid_force;
                double gamma = Math.Atan2(dy, dx);
                Point avoidVector = new Point(force * Math.Cos(gamma),force*Math.Sin(gamma));
                _speed.X += avoidVector.X;
                _speed.Y += avoidVector.Y;
            }

            //应用摩擦力
            _speed.X *= _friction;
            _speed.Y *= _friction;

            //更新位置
            X += _speed.X;
            Y += _speed.Y;
        }
    }
}

MainPage.xaml当作容器

<UserControl x:Class="MouseAvoider.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400">

    <Canvas x:Name="stage" Width="400" Height="300" Background="Black">

    </Canvas>
</UserControl>

后端代码:

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Effects;

namespace MouseAvoider
{
    public partial class MainPage : UserControl
    {

        Point _mousePosition = new Point(0, 0);

        public MainPage()
        {
            InitializeComponent();

            this.Loaded += new RoutedEventHandler(MainPage_Loaded);
        }

        void MainPage_Loaded(object sender, RoutedEventArgs e)
        {
            stage.MouseMove += new MouseEventHandler(stage_MouseMove);
            Random rnd = new Random();
            BlurEffect blur = new BlurEffect();
            for (int i = 0; i < 7; i++)
            {
                MouseAvoider _avoider = new MouseAvoider();
                _avoider.DestinationPoint = new Point(stage.Width / 2 - (rnd.NextDouble() * 2 - 1) * 80, stage.Height / 2 - (rnd.NextDouble() * 2 - 1) * 80);
                stage.Children.Add(_avoider);

                _avoider.Effect = blur;
            }

            CompositionTarget.Rendering += new EventHandler(CompositionTarget_Rendering);

        }

        void CompositionTarget_Rendering(object sender, EventArgs e)
        {
            Random rnd = new Random();
            for (int i = 0; i < stage.Children.Count; i++)
            {
                MouseAvoider _item = stage.Children[i] as MouseAvoider;
                _item.scale.ScaleX = _item.scale.ScaleY = 1.0 + (rnd.NextDouble() * 2 - 1) * 0.1;
            }
        }

        void stage_MouseMove(object sender, MouseEventArgs e)
        {
            _mousePosition = e.GetPosition(this.stage);
        }

        /// <summary>
        /// 获取当前鼠标所在位置
        /// </summary>
        public Point MousePosition
        {
            get { return _mousePosition; }
        }
    }
}


在线演示

注:没有找到Silverlight中对应的ColorTransForm方法,所以用白色替换了。同时相对Flash版的原效果而言,没有运动时的拖尾效果。哪位仁兄帮忙改进下,谢谢。

源文件下载: http://files.cnblogs.com/yjmyzz/MouseAvoider.rar

时间: 2024-09-30 11:06:33

Silverlight:Mouse Avoiding 躲避鼠标效果的相关文章

js实现精美的图片跟随鼠标效果实例

  本文实例讲述了js实现精美的图片跟随鼠标效果实现方法.分享给大家供大家参考.具体实现方法如下: ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69

js实现精美的图片跟随鼠标效果实例_javascript技巧

本文实例讲述了js实现精美的图片跟随鼠标效果实现方法.分享给大家供大家参考.具体实现方法如下: <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>精美js鼠标跟随代码</title> </head> <body> <script> A=doc

JS实现带鼠标效果的头像及文章列表代码_javascript技巧

本文实例讲述了JS实现带鼠标效果的头像及文章列表代码.分享给大家供大家参考.具体如下: 这是一种带图片功能的文章或新闻列表功能,鼠标滑过标题列表显示说明和图片,多见于SNS交友网站,不过你喜欢的话,你完全可以用哦. 运行效果截图如下: 在线演示地址如下: http://demo.jb51.net/js/2015/js-mouse-style-face-article-list-demo/ 具体代码如下: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.

Silverlight 5 beta新特性探索系列:4.Silverlight 5 beta中鼠标双击/鼠标多重点击的实现

在Silverlight 5中新增了鼠标双击和多重点击的实现,当然在这里包括鼠标左键和鼠标右键的双击,多重点击.在Silverlight 5的MouseButtonEventArgs类中新增了一个属性名为ClickCount:获取到触发事件源在单位时间内被点击的次数(注意:单位时间是由操作系统的"控制面板"-->"鼠标"-->"双击速度"设置的). 下面我们来看一个实例以判断是否双击还是多重点击,首先我们看实例的XAML代码: <

Flash动画实例:巧妙的鼠标效果

flash动画|鼠标      动画效果: 点击这里下载源文件 好,现在我们就开始至做这个效果. 第一步,我们先来建立一个graphic,在这个graphic里我们要画出被鼠标吸引的按钮的外观.我们的做法是使用多层绘制,单层合并的方法.做一个"◎"的矢量图.大小15*15 第二步,我们建立一个button,把graphic拖入button,在up,over,down调节一下Alpha值,使按钮在不同情况下,有不同的显示.在hit桢加上15*15的热区. 第三步,我们在建立一个Movie

Flash实例制作教程:鼠标效果

教程|鼠标 效果: 点击这里下载源文件

Silverlight 4 Beta之鼠标右键支持

Silverlight4Beta中终于加入了对鼠标右键捕获支持! 之前当我们在sl应用程序中点击鼠标右键时,我们只能得到一个囧的要死菜单 "Silverlight",其显示一些sl插件的基本信息,如版本.更新策略.本地存储配额等(事 实上谁会关注这些玩意?) 在Silverlight4beta中我们拥有了MouseRightButtonDown和MouseRightButtonUp事件,通 过它们,我们可以捕获鼠标右键!(弹出Silverlight菜单依然为默认行为,我是说,如果没 有

一个鼠标效果,代码简单易懂,效果不错的

var posYoubiao:Array = new Array();   posYoubiao[0] = 5;   for (i=1; i<6; i++) {           //预先设置好游标的位置           posYoubiao[i] = 5+(i)*95;   }   function youbiaoMotion(no:Number) {           youbiaoTarget = posYoubiao[no];           //从预先算好的游标位置中取得当

Win8.1系统“MOUSE WITHOUT BORDERS”鼠标失效提示“无法连接找不到主机”怎么办

  具体步骤如下: 1.去微软官网搜索下载:Microsoft Garage Mouse without Borders工具; 2.安装的时候,注意要先打开防火墙; 3.其中一台电脑点Yes,另一台点NO,然后输入另一台的安全码; 4.连接失败时,可多试几次,也可以试试再关闭防火墙; 5.想换共享的边缘,可以按住拖动就可以交换两台电脑的位置,然后apply就可以了; 6.如果本来两台是连接好的,然后有一台重装或怎么样的没了,那重新安装软件,然后注意网卡的选择.