具有自定义速度曲线的WPF动画 [英] WPF Animation with Custom Speed Curve

查看:103
本文介绍了具有自定义速度曲线的WPF动画的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

大家好,

我正在制作一个动画地图控件,其中直线表示道路,椭圆对象沿这些线设置动画。路径目前在Expression Blend中绘制,但将来它们应该在代码中生成。这些路径在Expression中应用于移动路径。



我当前的代码如下所示:

Hello everybody,
I'm working on an animated map control, where lines represent roads and ellipse objects are animated along these lines. Paths are currently drawn in Expression Blend, but in future they should be generated in code. These paths are applied in Expression to moving paths.

My current code looks like this:

private void ApplyAnimationToElement(string animationName, DependencyProperty targetProperty, FrameworkElement target)
        {
            DoubleAnimationUsingPath anim = ((DoubleAnimationUsingPath)Resources[animationName]);
            AnimationClock animClock = anim.CreateClock();
            target.ApplyAnimationClock(targetProperty, animClock);
            animClock.Controller.Pause();

            clocks.Add(animClock);
        }

 ApplyAnimationToElement("animationX", Canvas.LeftProperty, ellipse);
 ApplyAnimationToElement("animationY", Canvas.TopProperty, ellipse);





其中一个动画如下所示:



One of the animations looks like this:

<DoubleAnimationUsingPath x:Key="animationY" Duration="0:0:5" Source="Y" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.Y)" Storyboard.TargetName="ellipse" IsAdditive="True">
            <DoubleAnimationUsingPath.PathGeometry>
					<PathGeometry Figures="M51,16.39761 C-24.537898,34.288169 -99.506096,99.331318 -180.99999,48.397609 C-272.95909,-9.0768199 -273.32109,-7.6023899 -396.99999,-7.6023899 C-542.68229,-7.6023899 -749.89068,-134.26628 -860.99998,32.397609 C-908.87698,104.21312 -973.26728,125.18958 -964.99998,224.39761 C-957.10698,319.1142 -881.84698,326.46864 -868.99998,416.3976 C-847.86878,564.316 -884.99998,746.27899 -884.99998,904.39759 C-1102.1311,947.82379 -1069,1082.9669 -1069,1392.3976 C-1069,1628.7411 -1144.1431,1787.4617 -676.99998,1728.3976"/>
				</DoubleAnimationUsingPath.PathGeometry>
			</DoubleAnimationUsingPath>





动画暂停并插入列表,因为我从每个动画步骤拍摄快照到创建一个视频(这就是重点,我正在使用WPF渲染一些视频,这可能有点愚蠢,但我找不到更简单的解决方案)。



现在一切正常,但我想根据时间表移动椭圆。我想我可以编写代码,提供一些自定义的折线实现,并结合时间数据我计算画布坐标。



另一方面,我认为使用具有一些基本速度曲线的内置动画会更容易,但我没有找到将自定义时间轴对象传递给DoubleAnimationUsingPath对象的方法。此外,如果稍后,当椭圆可能被替换为图片时我会用矩阵动画旋转它们会很好。



如果值得使用WPF构建,你能帮助我吗?在动画功能中,或者更确切地说是我自己的实现功能较少,但至少对象的移动是基于时间表的。如果我应该使用WPF动画,我怎么能将它设置为我的自定义时间轴?



更详细的描述:说我有路径在A,B,C,D点之间有三个部分。我的时间表包含,椭圆在4秒内从A移动到B,在9中从B移动到C,在3中从C移动到D,无论这些线有多长。可以使用WPF动画来实现吗?



Animation is paused and inserted into a list, because I take snapshots from each animation step to create a video (that's the whole point, I'm using WPF to render some video, which may be a bit dumb, but I didn't find easier solution for me).

Everything is working fine now, but I want to move the ellipse according to timetable. I thought about that I could write code which provide some custom implementation of polyline and combined with time data I calculate the Canvas coordinates.

On the other hand, I think that it would be easier to use the built-in animation with some basic speed curve, but I didn't find way to pass a custom timeline object to DoubleAnimationUsingPath object. Moreover it would be nice if later, when the ellipse might be replaced with pictures I could rotate them using matrixanimation.

Could you help me if it's worth using WPF's built-in animation capabilities or rather write my own implementation which would be less capable, but at least objects' movements are based on timetable. If I should use WPF animation, how could I set to it my custom timeline?

Bit more detailed description: Say I have a path with three sections between points A,B,C,D . My timetable contains, that the ellipse moves from A to B in 4 sec, B to C in 9, C to D in 3 no matter how long these lines are. Can this be achieved using WPF animations?

推荐答案

我在对这个问题的评论中表达了我的观点。我希望你理解我的建议动机,摆脱使用WPF动画功能的想法。动画可以通过更高效的第一原则制作,实质上是一种简单的方式。



这是一个想法:你创建一个单独的线程拍摄风景(在这种情况下,带有路线的地图和关于这些路线的一些数据)并在其上建立一些物理,使用一般和简单的运动学和机械定律来表示物体在这个风景上的运动。这个线程本身应该专门用于数据,计算和时间。



时机是一个微妙的问题。比如,你在你的线程中创建一个循环:它需要当前坐标,在你建模的物理世界上花费的时间,并在配置空间中计算新的广义坐标( https://en.wikipedia.org/wiki/Degrees_of_freedom_%28physics_and_chemistry%29 )。但是,当执行周期性地到达这一点时,你无法依赖假设你的循环给你相等的持续时间 - 这不是一个实时系统。相反,您可以使用类 System.Diagnostics.Stopwatch 并在需要时获得实时时间:

https://msdn.microsoft.com/en-us/library/system.diagnostics .stopwatch%28v = vs.110%29.aspx [ ^ ]。



通过这种方式,您可以获得真正的时间点并计算从系统获取的时刻的坐标。例如,对于速度 v 和加速度 a 的运动,坐标计算 x = x 0 + vt +a²t应使用此获得的 t 的值。你的框架之间的时间跨度不会相等,但是,对于人眼来说,动作看起来非常平滑和逼真;我有很多情况需要确定。



现在,你需要更新你的UI并对你的动作进行适当的渲染。您不能从非UI线程调用与UI相关的任何内容。相反,您需要使用 Invoke System.Windows.Threading的方法。 Dispatcher (对于Forms或WPF)或 System.Windows.Forms.Control (仅限表单)。



您将在我过去的答案中找到有关其工作原理和代码示例的详细说明:

Control.Invoke()与Control.BeginInvoke()

使用Treeview扫描仪和MD5的问题



另请参阅有关线程的更多参考资料:

如何在vb.net中的另一个线程上运行keydown事件

在启用禁用+多线程后控制事件没有触发



在你的情况下,动画,你将需要使用 Dispatcher.Invoke ,而不是 BeginInvoke ,保持计算动作的线程,并防止此线程产生更多的情况以及配置空间中更多计算的坐标,您的渲染不遵循速度。这是你需要使用秒表的另一个原因。


基本上,这就是全部。如果您有任何后续问题,请随时询问。



-SA
I expressed my opinion in my comments to the question. I hope you understand my motivation of the advice to get rid of the idea of using WPF animation feature. The animation could be made out of first principles in a more efficient, and, in essence, a simper way.

Here is the idea: you create a separate thread which takes the scenery (in this case, the map with routes and some data about these routes) and build some "physics" over it, using general and simple kinematic and mechanic laws to represent motion of objects on this scenery. This thread itself should work exclusively with data, calculation and time.

The timing is delicate issue. Say, you create a loop in your thread: it takes current coordinates, time spend on the physical world you model and calculate new generalized coordinates in your configuration space (https://en.wikipedia.org/wiki/Degrees_of_freedom_%28physics_and_chemistry%29). However, no way you can rely on the assumption that your loops gives you equal time durations when the execution periodically comes to this point — this is not a real-time system. Instead, you can use the class System.Diagnostics.Stopwatch and get the real time when you need it:
https://msdn.microsoft.com/en-us/library/system.diagnostics.stopwatch%28v=vs.110%29.aspx[^].

This way, you can get a real point of time and calculate the coordinates for the moment of time you acquire from the system. For example, for the motion with the speed v and acceleration a, coordinate calculations x = x₀ + vt + a²t should use this acquired value of t. The time spans between your "frames" won't be equal, nevertheless, the motion will look quite smooth and realistic to a human eye; I had many cases to be sure.

Now, you need to update your UI and perform proper rendering of you motion. You cannot call anything related to UI from non-UI thread. Instead, you need to use the method Invoke or BeginInvoke of System.Windows.Threading.Dispatcher (for both Forms or WPF) or System.Windows.Forms.Control (Forms only).

You will find detailed explanation of how it works and code samples in my past answers:
Control.Invoke() vs. Control.BeginInvoke(),
Problem with Treeview Scanner And MD5.

See also more references on threading:
How to get a keydown event to operate on a different thread in vb.net,
Control events not firing after enable disable + multithreading.

In you case, animation, you will need to use Dispatcher.Invoke, not BeginInvoke, to hold on your thread calculating the motion, and to prevent the situations when this thread produces more and more calculated coordinates in the configuration space and your rendering does not follow the tempo. This is yet another reason you need to use Stopwatch.

Basically, that's all. Feel free to ask if you have any follow-up questions.

—SA


这篇关于具有自定义速度曲线的WPF动画的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆