MakubeX

导航

[转载]Silverlight 动画与向量

这次将使用向量和动画结合来模拟物体在具有重力下的运动效果,主要逻辑:
1.定义小球的重力,摩擦力、以及运动速度的递减变量
2.根据鼠标拖拽小球的前后位置的差值来设置小球的起始速度,拖动越快速度也就越大。
3.小球开始运动的时候 ,首先根据小球的重力从新设置小球在Y轴上的运动速度,其次检测小球在运动到上下左右边界的情况,以及运动到角
落的情况,并重新设置小球位置。
运行效果图如下:
一、ball对象主要逻辑均有ball对象处理,其代码如下:
ball.xaml 代码
<UserControl.Resources>
<Storyboard x:Name="Move" Duration="00:00:00"/>
</UserControl.Resources>
<Canvas x:Name="LayoutRoot" Width="40" Height="40">
<Ellipse Width="40" Height="40" Canvas.Left="0" Canvas.Top="0" x:Name="redEllipse">
<Ellipse.Fill>
<RadialGradientBrush>
<RadialGradientBrush.RelativeTransform>
<TransformGroup>
<ScaleTransform ScaleX="1" ScaleY="1"/>
<SkewTransform AngleX="0" AngleY="0"/>
<RotateTransform Angle="0"/>
<TranslateTransform X="0.15" Y="-0.125"/>
</TransformGroup>
</RadialGradientBrush.RelativeTransform>
<GradientStop Color="#FFFFFFFF" Offset="0"/>
<GradientStop Color="#FFFF0000" Offset="1"/>
</RadialGradientBrush>
</Ellipse.Fill>
</Ellipse>
</Canvas>
ball.xaml.cs代码
public partial class ball : UserControl
{
/// <summary>
/// 重力
/// </summary>
public double Gravity;
/// <summary>
/// 容器高度
/// </summary>
public double RootHeight;
/// <summary>
/// 容器宽度
/// </summary>
public double RootWidth;
/// <summary>
/// 是否捕捉焦点
/// </summary>
private bool isMouseCaptured;
/// <summary>
/// 鼠标位置
/// </summary>
private Point mousePosition;
/// <summary>
/// 鼠标位置缓存
/// </summary>
private Point oldMouse;
/// <summary>
/// 小球位置
/// </summary>
private Point ballPosition;
/// <summary>
/// 小球X轴速度
/// </summary>
private double VelocityX = 0;
/// <summary>
/// 小球Y轴速度
/// </summary>
private double VelocityY = 0;
//偏移量,X/Y轴速度均要乘以此变量
private double restitution = .6;
//摩擦力
private double friction = .9;
public ball()
    {
        InitializeComponent();
this.MouseLeftButtonDown += new MouseButtonEventHandler(ball1_MouseLeftButtonDown);
this.MouseLeftButtonUp += new MouseButtonEventHandler(ball1_MouseLeftButtonUp);
this.MouseMove += new MouseEventHandler(ball1_MouseMove);
        Move.Completed += new EventHandler(Move_Completed);
    }
void Move_Completed(object sender, EventArgs e)
    {
//根据重力计算小球速度,重力影响Y轴速度
        VelocityY += Gravity;
//根据小球上一次的位置参数、小球的速度和方向更新ballPosition的值
        ballPosition.X += VelocityX;
        ballPosition.Y += VelocityY;
//考虑小球运动到角落的情况
if (ballPosition.Y + this.Height >= RootHeight && (ballPosition.X + this.Width) >= RootWidth)
        {
//小球运动到右下角
            ballPosition.X = RootWidth - (this.Width + 1);
        }
if (ballPosition.Y + this.Height >= RootHeight && ballPosition.X <= 0)
        {
//小球运动到左下角
            ballPosition.X = 0;
            VelocityX *= -restitution;
        }
if (ballPosition.Y <= 0)
        {
//小球运动到上边界的时候,则设置其Top值不能小于0,改变其Y轴运动方向
            ballPosition.Y = 0;
            VelocityY *= -restitution;
        }
else if ((ballPosition.Y + this.Height) >= RootHeight)
        {
//小球运动到下边界的时候,则设置其Top值为容器高度减自身高度,改变其Y轴运动方向,
//每次运动到底部都要根据虚拟的摩擦力来使X轴的速度减慢
            ballPosition.Y = RootHeight - this.Height;
            VelocityY *= -restitution;
            VelocityX *= friction;
        }
else if ((ballPosition.X + this.Width) >= RootWidth)
        {
//小球运动到右边界,则设置其Left值最大值为容器宽度减自身宽度,并改变X轴速度的方向
            ballPosition.X = RootWidth - this.Width;
            VelocityX *= -restitution;
        }
else if (ballPosition.X <= 0)
        {
//小球运动到左边界,则设置其Left值最小为0,不能超出边界,并改变X轴速度的方向
            ballPosition.X = 0;
            VelocityX *= -restitution;
        }
//设置小球最新位置
        Canvas.SetLeft(this, ballPosition.X);
        Canvas.SetTop(this, ballPosition.Y);
        Move.Begin();
    }
void ball1_MouseMove(object sender, MouseEventArgs e)
    {
        FrameworkElement item = sender as FrameworkElement;
if (isMouseCaptured)
        {
//记录鼠标点击点位置
            oldMouse.X = mousePosition.X;
            oldMouse.Y = mousePosition.Y;
//计算当前对象的坐标位置,根据扑捉点位置和当前位置计算
double deltaV = e.GetPosition(null).Y - mousePosition.Y;
double deltaH = e.GetPosition(null).X - mousePosition.X;
//计算小球最新位置
double newTop = deltaV + Canvas.GetTop(item);
double newLeft = deltaH + Canvas.GetLeft(item);
//设置对象的新位置
            Canvas.SetTop(this, newTop);
            Canvas.SetLeft(this, newLeft);
//检测小球拖动过程中是否触碰到边界
if (Canvas.GetLeft(this) < 0 || Canvas.GetTop(this) < 0)
            {
                outOfBounds(item);
            }
if (Canvas.GetLeft(this) + this.Width >= RootWidth)
            {
                outOfBounds(item);
            }
if (Canvas.GetTop(this) + this.Height >= RootHeight)
            {
                outOfBounds(item);
            }
            mousePosition = e.GetPosition(null);
//根据拖拽前后位置的差值设置小球运动的启始速度
            VelocityX = (mousePosition.X - oldMouse.X) / 2;
            VelocityY = (mousePosition.Y - oldMouse.Y) / 2;
        }
    }
void ball1_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
    {
        FrameworkElement item = sender as FrameworkElement;
        isMouseCaptured = false;
        item.ReleaseMouseCapture();
        mousePosition.X = mousePosition.Y = 0;
        item.Cursor = null;
//小球初始位置
        ballPosition.X = Canvas.GetLeft(this);
        ballPosition.Y = Canvas.GetTop(this);
        Move.Begin();
    }
void ball1_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
//捕捉焦点、停止动画、从新计算鼠标位置
        Move.Stop();
        FrameworkElement item = sender as FrameworkElement;
        mousePosition = e.GetPosition(null);//获取鼠标位置
        isMouseCaptured = true;
        item.CaptureMouse();
        item.Cursor = Cursors.Hand;
        VelocityX = 0;
        VelocityY = 0;
    }
/// <summary>
/// 处理小球超出边界的行为,当执行此方法将释放焦点,并开始动画
/// </summary>
private void outOfBounds(FrameworkElement item)
    {
        isMouseCaptured = false;
        item.ReleaseMouseCapture();
        item.Cursor = null;
        ballPosition.X = Canvas.GetLeft(this);
        ballPosition.Y = Canvas.GetTop(this);
        Move.Begin();
    }
}
二、gravityBall对象
此对象容器,承载小球
gravityBall.xaml代码
<Canvas x:Name="LayoutRoot" Background="White" Width="800" Height="600">
<Rectangle x:Name="borderStroke" Width="800" Height="600" Stroke="#FF000000" Canvas.Left="0" Canvas.Top="0">
<Rectangle.Fill>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FF03174D" Offset="1"/>
<GradientStop Color="#FFC8C8C8" Offset="0"/>
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
<Slider Width="150" Canvas.Top="38" Canvas.Left="12" x:Name="gravitySlider"/>
<TextBlock Text="重 力: " TextWrapping="Wrap" Canvas.Left="14" Canvas.Top="10" x:Name="msgGravity"/>
</Canvas>
gravityBall.xaml.cs代码
public partial class gravityBall : Page
{
private ball redBall;
//初始重力
private double globalGravity = .6;
public gravityBall()
    {
        InitializeComponent();
        redBall = new ball();
        gravitySlider.Minimum = 0;
        gravitySlider.Maximum = 2;
        gravitySlider.Value = globalGravity;
        msgGravity.Text = "重 力: " + globalGravity;
        Canvas.SetLeft(redBall, 100);
        Canvas.SetTop(redBall, 100);
        redBall.Gravity = globalGravity;
        redBall.RootWidth = LayoutRoot.Width;
        redBall.RootHeight = LayoutRoot.Height;
        LayoutRoot.Children.Add(redBall);
        gravitySlider.ValueChanged += new RoutedPropertyChangedEventHandler<double>(gravitySlider_ValueChanged);
    }
private void gravitySlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
    {
//更改小球的重力
        globalGravity = gravitySlider.Value;
        redBall.Gravity = globalGravity;
        msgGravity.Text = "重 力: " + globalGravity.ToString("0.00");
    }
}
至此整个示例的的代码完成。

posted on 2011-01-24 00:35  Makubex  阅读(422)  评论(0编辑  收藏  举报