WPF/Silverlight 每幀渲染完成後觸發 CompositionTarget.Rendering 事件,頻率鎖定於螢幕刷新率 (通常 60Hz,約 16.6ms/幀)。間隔不可人為調整,適合需與渲染管線嚴格同步的全域邏輯:攝影機平滑跟隨、大量粒子系統、物理模擬固定時間步長。
Rectangle rect;
double speed = 1; // 像素/幀
Point moveTo;
public Window1() // 原文 Window1,實為第 2 章視窗
{
InitializeComponent();
rect = new Rectangle { Fill = Brushes.Red, Width = 50, Height = 50, RadiusX = 5, RadiusY = 5 };
Carrier.Children.Add(rect);
Canvas.SetLeft(rect, 0); Canvas.SetTop(rect, 0);
CompositionTarget.Rendering += Timer_Tick; // 註冊渲染幀事件
}
private void Carrier_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
moveTo = e.GetPosition(Carrier);
}
private void Timer_Tick(object sender, EventArgs e)
{
double x = Canvas.GetLeft(rect);
double y = Canvas.GetTop(rect);
Canvas.SetLeft(rect, x + (x < moveTo.X ? speed : -speed));
Canvas.SetTop(rect, y + (y < moveTo.Y ? speed : -speed));
}
程式碼將 X、Y 速度同設為 speed=1,導致:
private void Timer_Tick(object sender, EventArgs e)
{
double x = Canvas.GetLeft(rect);
double y = Canvas.GetTop(rect);
double dx = moveTo.X - x;
double dy = moveTo.Y - y;
double dist = Math.Sqrt(dx*dx + dy*dy);
if (dist < speed) { // 到達目標
Canvas.SetLeft(rect, moveTo.X);
Canvas.SetTop(rect, moveTo.Y);
return;
}
double vx = dx / dist * speed;
double vy = dy / dist * speed;
Canvas.SetLeft(rect, x + vx);
Canvas.SetTop(rect, y + vy);
}
計算單位向量乘以速度,確保全向等速、平滑停止。此為向量數學在遊戲移動中的最基礎應用。
| 維度 | Storyboard (第 1 章) | CompositionTarget (本章) |
|---|---|---|
| 程式碼複雜度 | 較高 (聲明式動畫定義) | 極低 (命令式每幀更新) |
| 插值平滑度 | 自動線性/樣條插值 | 需手動實現向量插值 |
| 時間控制 | 精確 Duration、Easing | 固定 16.6ms/幀,難控制總時長 |
| 適用對象 | 單一/少量屬性漸變 | 大量同步更新物件 |
| 效能特性 | GPU 協助、獨立時間軸 | CPU 逐幀計算、可批次優化 |