WPF:Animation動畫--Per-FrameAnimation每幀動畫效果(1)

Pre-FrameAnimation幀動畫:

ColorChangingExample顏色幀變化示例

clipboard.png

實現效果:此方框實現每幀改變一次顏色canvas

  1. Rectangle.Fill填充純色畫刷SolidColorBrush,
  2. 後臺代碼實現CompositionTarget.Rendering事件,在每幀中更新純色畫刷的初始化的隨機顏色。
private readonly Random _rand = new Random();

public SimpleExample()
{
    CompositionTarget.Rendering += UpdateColor;
}

private void UpdateColor(object sender, EventArgs e)
{
    // Set a random color
    animatedBrush.Color = Color.FromRgb((byte) _rand.Next(255),
        (byte) _rand.Next(255),
        (byte) _rand.Next(255));
}

FollowExample一直跟隨鼠標的方框

clipboard.png
在Page每幀呈現的方法中獲取當前方框的座標與當前鼠標座標差量值,設置每幀方框往鼠標點移動一點點距離。造成方框慢慢跟隨到鼠標的效果。緩存

  1. 設置字段:最後一次鼠標位置_lastMousePosition及方框須要變化位置_rectangleVelocity值。
  2. 初始化Page時,在靜態類CompositionTarget.Rendering事件中附加每幀處理的方法。同時對鼠標移動事件附加處理方法:獲取當前鼠標相對容器的座標。
  3. 在每幀處理方法中,設置獲取方框在Canvas的左上座標值及與鼠標點的差量值。設置移動緩存係數,計算每幀移向的距離。
  4. 每幀從新設置方框在Canvas的位置。

public partial class FollowExample : Page
{dom

private Point _lastMousePosition = new Point(0, 0);
private Vector _rectangleVelocity = new Vector(0, 0);

public FollowExample()
{
    CompositionTarget.Rendering += UpdateRectangle;
    PreviewMouseMove += UpdateLastMousePosition;
}

private void UpdateRectangle(object sender, EventArgs e)
{
    var location = new Point(Canvas.GetLeft(followRectangle), Canvas.GetTop(followRectangle));

    //find vector toward mouse location
    var toMouse = _lastMousePosition - location;

    //add a force toward the mouse to the rectangles velocity
    var followForce = 0.01;
    _rectangleVelocity += toMouse*followForce;

    //dampen the velocity to add stability
    var drag = 0.8;
    _rectangleVelocity *= drag;

    //update the new location from the velocity
    location += _rectangleVelocity;

    //set new position
    Canvas.SetLeft(followRectangle, location.X);
    Canvas.SetTop(followRectangle, location.Y);
}

private void UpdateLastMousePosition(object sender, MouseEventArgs e)
{
    _lastMousePosition = e.GetPosition(containerCanvas);
}

}動畫

FrameIndependentFollowExample幀自主跟隨示例

clipboard.png

實現效果:this

  1. 紅框有慣性跟隨鼠標,相比上一個示例區別是,跟隨鼠標速度快,可是衝過鼠標偏移也大,在鼠標移動到忽然靜止時,紅框會在鼠標搖擺慢慢回覆到靜止點。

代碼此處增長一個字段:時間間隔值TimeSpan _lastRender,目的是獲取幀間隔時間值。其餘同上spa

public partial class FrameIndependentFollowExample : Page
{
    private Point _lastMousePosition = new Point(0, 0);
    //timing variables
    private TimeSpan _lastRender;
    private Vector _rectangleVelocity = new Vector(0, 0);

    public FrameIndependentFollowExample()
    {
        InitializeComponent();
        _lastRender = TimeSpan.FromTicks(DateTime.Now.Ticks);
        CompositionTarget.Rendering += UpdateRectangle;
        PreviewMouseMove += UpdateLastMousePosition;
    }
    
private void UpdateLastMousePosition(object sender, MouseEventArgs e)
{
    _lastMousePosition = e.GetPosition(containerCanvas);
}

此處與上例變化主要是幀間位移差量的計算,主要與參數(幀間時間值)有關。線程

  1. followForce爲移向同一方向鼠標的(力量)速度參數,值越大移動速度越快。
  2. drag爲慣性來回幅度值,當爲1時,永遠也不會靜止,紅框在鼠標點來回晃動。>1,紅框跑掉,越接近0時,幅度爲0.
  3. delta抑制移向鼠標速度參數,與followForce一塊兒決定移向鼠標的速度。不過做用度有點差別,由於中間有一個幅度乘係數。
private void UpdateRectangle(object sender, EventArgs e)
{
    var location = new Point(Canvas.GetLeft(followRectangle), Canvas.GetTop(followRectangle));

    //find vector toward mouse location
    var toMouse = _lastMousePosition - location;

    //add a force toward the mouse to the rectangles velocity
    var followForce = 0.01;
    _rectangleVelocity += toMouse*followForce;

    //dampen the velocity to add stability
    var drag = 0.8;
    _rectangleVelocity *= drag;

    //update the new location from the velocity
    location += _rectangleVelocity;            

    //set new position
    Canvas.SetLeft(followRectangle, location.X);
    Canvas.SetTop(followRectangle, location.Y);
}

ReusableFollow可重用的跟隨方框

clipboard.png

實現效果:
1.跟隨鼠標方框爲3個,這些都繼承同一個Canvas,都是先搖擺跟隨功能效果。
xaml代碼:3d

<Canvas Background="transparent">
    <perFrameAnimation:FollowMouseCanvas Canvas.Left="0" Canvas.Top="0" Background="red" Width="50" Height="50">
      <!-- could put more content that will also follow mouse here-->
    </perFrameAnimation:FollowMouseCanvas>
    <perFrameAnimation:FollowMouseCanvas Canvas.Left="300" Canvas.Top="0" Background="green" Width="50" Height="50">
      <!-- could put more content that will also follow mouse here-->
    </perFrameAnimation:FollowMouseCanvas>
    <perFrameAnimation:FollowMouseCanvas Canvas.Left="0" Canvas.Top="300" Background="blue" Width="50" Height="50">
      <!-- could put more content that will also follow mouse here-->
    </perFrameAnimation:FollowMouseCanvas>
  </Canvas>

繼承Canvas,實現搖擺跟隨功能:code

  1. 多了個字段:Canvas _parentCanvas;做爲獲取上級容器鼠標點的一個引用。其餘與上例同理。
  2. 最下面代碼獲取鼠標在容器中座標時作了方框背景色差別判斷,以區分方框的不一樣位置。
  3. 註釋的一行代碼爲源碼,原意爲綠色系藍色方框過一段時間才能出現,由於位移距離太大了,緣由是第一幀TimeSpan.FromTicks(DateTime.Now.Ticks)值過大
public class FollowMouseCanvas : Canvas
{
    private TimeSpan _lastRender;
    private Canvas _parentCanvas;
    private Point _parentLastMousePosition = new Point(0, 0);
    private Vector _velocity = new Vector(0, 0);

    public FollowMouseCanvas()
    {
        //_lastRender = TimeSpan.FromTicks(DateTime.Now.Ticks);//註釋掉是由於初始值太大,最後location差值過大而一開始不會顯示綠色與藍色方框。
        CompositionTarget.Rendering += UpdatePosition;
    }

    private void UpdatePosition(object sender, EventArgs e)
    {
        var renderingArgs = (RenderingEventArgs) e;

        var deltaTime = (renderingArgs.RenderingTime - _lastRender).TotalSeconds;
        _lastRender = renderingArgs.RenderingTime;

        if (_parentCanvas == null)
        {
            _parentCanvas = VisualTreeHelper.GetParent(this) as Canvas;
            if (_parentCanvas == null)
            {
                //parent isnt canvas so just abort trying to follow mouse
                CompositionTarget.Rendering -= UpdatePosition;
            }
            else
            {
                //parent is canvas, so track mouse position and time
                _parentCanvas.PreviewMouseMove += UpdateLastMousePosition;
            }
        }
        

        //get location
        var location = new Point(GetLeft(this), GetTop(this));

        //check for NaN's and replace with 0,0
        if (double.IsNaN(location.X) || double.IsNaN(location.Y))
            location = new Point(0, 0);

        //find vector toward mouse location
        var toMouse = _parentLastMousePosition - location;

        //add a force toward the mouse to the rectangles velocity
        var followForce = 1.0;
        _velocity += toMouse*followForce;

        //dampen the velocity to add stability
        var drag = 0.95;
        _velocity *= drag;

        //update the new location from the velocity
        location += _velocity*deltaTime;

        //set new position
        SetLeft(this, location.X);
        SetTop(this, location.Y);
    }

    private void UpdateLastMousePosition(object sender, MouseEventArgs e)
    {
        if (_parentCanvas == null)
            return;
        if (this.Background==Brushes.Blue)
        {
            _parentLastMousePosition.X = e.GetPosition(_parentCanvas).X+100;
            _parentLastMousePosition.Y = e.GetPosition(_parentCanvas).Y;
        }
        else if (this.Background== Brushes.Green)
        {
            _parentLastMousePosition.X = e.GetPosition(_parentCanvas).X - 100;
            _parentLastMousePosition.Y = e.GetPosition(_parentCanvas).Y;
        }
        else
        {
            _parentLastMousePosition = e.GetPosition(_parentCanvas);
            
        }            
    }
}

ParticleEffets

clipboard.png

見第2章對象

擴展:

clipboard.png

CompositionTarget類:表示您的應用程序的顯示圖面。

  1. WPF 動畫引擎爲建立基於幀的動畫提供了許多功能。 可是,在有些應用程序方案中,您須要根據每一個幀控制呈現。 使用 CompositionTarget 對象,能夠基於每一個幀回調來建立自定義動畫。
  2. CompositionTarget.Rendering事件

HwndTarget 類:表示到支持可視化撰寫的窗口句柄的綁定。

  1. HwndTarget.RootVisual 屬性:獲取或設置由此窗口承載的頁面的根可視化對象。
  2. HwndTarget.RenderMode 屬性:獲取或設置由此 HwndTarget 引用的窗口的呈現模式。

VisualTarget 類:提供用於跨越線程邊界將一個可視化樹鏈接到另外一個可視化樹的功能。

RenderingEventArgs 類:Rendering 事件的必需參數。

  1. RenderingEventArgs.RenderingTime 獲取將呈現動畫的下一個幀的估計目標時間。
  2. 每幀間的間隔時長,與呈現實時幀數的倒數反映出
相關文章
相關標籤/搜索