如何做图像动画 [英] how to do image animation

查看:173
本文介绍了如何做图像动画的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的表格上有一个球形图像.

I have a ball image on my form. How can i animate it, striking the form boundaries, in a infinite loop...?

推荐答案

确定要在整个表单而不是整个表单上使用它吗?诸如面板之类的控件? -会花费更多的精力,但会增加布局的灵活性.如果要向表单添加控件怎么办?

您需要执行以下操作:

1)将表单的属性DoubleBuffered设置为true.

2)覆盖表单的OnPaint方法.使用通过事件参数传递的类Graphics的实例渲染球.渲染将取决于类型为System.Drawing.Point的当前球坐标.让我们将其设置为表单中名为BallPosition的字段.

3)创建一个单独的线程,在显示表单时将其命名为BallThread-覆盖表单的OnShown方法以启动该线程. 注意!有些人会建议您使用计时器.不要听他们的话.这似乎更容易.如果可能,请始终首选线程而不是计时器.

4)在BallThread线程中,组织无限循环,在循环内的特定时间段内使用System.Threading.Thread.Sleep.然后使用System.DateTime.Now计算当前时间;根据当前时间,更新BallPosition并调用Form.Invalidate.通过发送WM_PAINT给您的表格,它将触发球的重新渲染;它将调用您的OnPaint方法. 检查实时很重要;如果仅通过计算睡眠时间来计算时间,由于线程调度的随机性和某些系统延迟,您将无法获得足够的准确性.另外,您可以使用类System.Diagnostics.Stopwatch.


感谢Pete O''Hanlon提出的重要改进建议:将线程设置为等待状态的更可靠的方法是使用超时阻塞对System.Threading.Monitor.Wait(object, int)的调用.在正常的动画流程中,线程总是会被超时唤醒,但是如果需要立即退出动画循环,则可以向监视器发送脉冲.该技术可以与退出循环条件结合使用.它可能是为打破循环而设置为true的布尔成员.在这两种情况下,调用线程都将被操作系统关闭,并且直到唤醒后才安排回执行,因此它使用的CPU时间严格为零.
但是,我认为如果您需要一个在应用程序生存期内运行动画的简单应用程序,则Thread.Sleep就可以了.在应用程序退出时,您只需调用Thread.Abort.
请在下面的评论中查看我们与Pete的讨论.
[END EDIT]

(重要!不要直接从非UI线程在UI上调用任何东西.
您无法从非UI线程调用与UI相关的任何操作.相反,您需要使用System.Windows.Threading.DispatcherInvokeBeginInvoke方法(对于Forms或WPF)或System.Windows.Forms.Control(仅对于Forms).
在我过去的答案中,您将找到有关其工作原理的详细说明和代码示例:
Control.Invoke()与Control.BeginInvoke() [ ^ ],
Treeview Scanner和MD5的问题 [
Are you sure you want it on the whole form, not a form control such as panel? — would take a little more effort but add a lot of flexibility in layout. What if you want to add controls to the form.

You need to do the following:

1) Set the property DoubleBuffered of your form to true.

2) Override your form''s OnPaint method. Render the ball using the instance of the class Graphics passed through the event arguments. Rendering will depend on the current ball coordinates of the type System.Drawing.Point; let''s make it a field of your form named BallPosition.

3) Create a separate thread, let''s call it BallThread when the form is shown — override your form''s OnShown method to start the thread. Attention! Some will suggest you use timer. Don''t listen to them. It only seems to be easier. Always prefer thread to timer if possible.

4) In the BallThread thread, organize infinite loop, use System.Threading.Thread.Sleep for certain period of time inside the loop. Then calculate current time using System.DateTime.Now; depending on current time, update BallPosition and call Form.Invalidate. It will trigger re-rendering of the ball by sending WM_PAINT to you form; it will call your OnPaint method. Checking real time is important; if you simply calculate time by counting sleep times, you won''t get sufficient accuracy due to randomness of thread scheduling and some system latency. Alternatively, you can use the class System.Diagnostics.Stopwatch.


Thanks to Pete O''Hanlon for a suggestion of important improvement: a more robust way of setting a thread in a wait state is the blocking call to System.Threading.Monitor.Wait(object, int) with timeout. During normal animation flow, the thread will be awaken always by timeout, but if immediate break out of animation loop is required, the monitor can be pulsed. This technique can be used in combination with exit loop condition; it could be a Boolean member set to true for breaking the loop. In both cases, the calling thread will be switched off by OS and never scheduled back to execution until awaken, so it uses strictly zero CPU time.
However, I think if you need a simple application which runs the animation during the application life time, Thread.Sleep is just fine. On application exit you simply call Thread.Abort.
Please see our discussion with Pete in comments below.
[END EDIT]

(Important! Don''t call anything on UI directly from non-UI thread.
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[^].)

5) To improve performance invalidate only the part of the scene: around you previous ball position (store is as a form field as well) and new one. For this purpose, use the method Invalidate with parameters (Region or Rectangle). Also, for performance reasons, do not invalidate twice. Invalidate ether the rectangle covering both ball locations or the region which is composed as a union of the regions for both current and previous ball positions.

If you need to do animation on a custom control or Panel (which I would highly recommend), you need to do the same, but you have to make a control custom by subclassing System.Windows.Forms.Control or System.Windows.Forms.Panel. The main reason for this is: otherwise you won''t get access to double buffering. You need to call protected method System.Windows.Forms.Control.SetStyle. Add the following styles: System.Windows.Forms.ControlStyles.OptimizedDoubleBuffer | System.Windows.Forms.ControlStyles. AllPaintingInWmPaint.

If you fail to use double buffering, your animation will suffer heavy flicker, by obvious reasongs.

—SA


据我了解,您正在寻找的是一个简单的对象碰撞示例(在形式边界内). [
From what I understand, you are looking for is a simple object collision sample (within form boundaries). This[^] could help you get started.

The first answer is more comprehensive in terms of the strategy to implement this though.


这篇关于如何做图像动画的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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