是否有任何方法可以更快地在画布上渲染大量移动对象(c# w/ WPF)
本文关键字:移动 对象 WPF 方法 任何 是否 | 更新日期: 2023-09-27 17:50:17
我正在制作一个粒子游戏(到目前为止,只使用水),并且元素中的Draw()方法非常慢,一次只能使用几个。我认为这是因为它每秒要计算很多东西,但我仍然对它很不满意,因为它们只是基本的2D形状。我怎样才能使它更有效率?
下面是我的代码:
(循环)(每50毫秒运行一次)(注意,我只是为计时器包含了表单,我使用WPF)
void TimeKeeper_Tick(object sender, EventArgs e)
{
foreach (Element ele in Elements)
{
ele.Draw();
}
}
和绘制方法。Pos是一个"Vector2"(类我做,以节省我的时间):
public void Draw()
{
Pos.Add(3, 10);
if (Pos.Y > (int)canvas.ActualHeight)
{
Pos.Set(Pos.X, (int)shape.RenderSize.Width);
}
if (Pos.X+shape.RenderSize.Width > (int)canvas.ActualWidth)
{
Pos.Set(0, Pos.Y+(int)shape.RenderSize.Height);
}
shape.SetValue(Canvas.LeftProperty, (double)Pos.X);
shape.SetValue(Canvas.TopProperty, (double)Pos.Y);
if (canvas.Children.IndexOf(shape) != null)
{
canvas.Children.Remove(shape);
}
canvas.Children.Add(shape);
}
在Canvas后代中重写Canvas.OnRender
是您对许多移动形状的最佳选择。
WPF针对静态形状进行了优化。如果您移动所有这些静态形状,那么您将经历此优化的所有开销,而不会从中受益(因为形状移动)。
代码看起来像这样:
public delegate void RenderEventHandler(CanvasRender sender, DrawingContext dc);
public class CanvasRender : Canvas
{
public event RenderEventHandler Render;
public CanvasRender()
{
}
protected override void OnRender(DrawingContext dc)
{
if (Render != null)
Render(this, dc);
base.OnRender(dc);
}
}
然后使用这个类代替Canvas
,并为Render
事件分配一个处理程序。在这种情况下,您可以使用对DrawingContext
的显式调用来重新绘制整个视觉效果。
这听起来好像你用这种方式做了更多的工作,但这实际上比创建所有移动的对象然后移动它们要高效得多。特别是当这些对象是角度/长度随时间变化的线条时,因为WPF无法在移动时预渲染它们和预渲染的形状。
如果你想让它非常快,你必须使用一些高级的技术。特别是这些所谓的过程动画和使用可写位图的动画。
这里有一篇很好的博客文章描述了这些技术(有一个粒子效果的例子):http://blogs.claritycon.com/blog/2011/03/30/advanced-animation-animating-15000-visuals-in-silverlight-2/。它是关于Silverlight的,但是因为Silverlight是WPF的一个子集,所以技术是相同的。
这在很大程度上取决于你如何看待"慢"
如果你每隔50毫秒移动一个形状,你就必须每隔一段时间移动它们更多,以使它们移动得更快。
但是像你那样添加计时器并不是在WPF中创建动画的最佳方式。
有两个选项:
-
为每个形状指定一个速度(例如:每秒10个单位),然后随着屏幕的每次更新,根据距离上次移动的时间和速度移动形状。因此,您还需要跟踪经过的时间。
-
创建故事板,它们有自己的计时器(时间线),所以你所要做的就是设置开始和结束的位置,并指定持续时间,最后播放动画