动画

通过在动画窗口上快速改变绘图(帧),我们可以制作动画。

时间控制

因为计算机能够以很快的速度画图,因此我们通常需要在两帧间停顿一些时间。

注意:在这节中使用的函数都无法在无窗口模式(Headless模式)中工作。

在Easy Graphics中,我们可以使用delay()函数来让程序暂停指定的毫秒(milliseconds或ms)数。

控制FPS

因为每次绘图的实际用时都有可能不一样,因此更好的控制每帧时长的方法是使用delay_fps()函数。

FPS是”frames per second”(每秒钟帧数)的缩写。delay_fps()会计算每一帧的实际绘制时长,将程序暂停对应的时长,以保证每帧的总时长一致。

渲染模式(Render Mode)

在EasyGraphics中有两种渲染模式

  1. 自动模式(RenderMode.AUTO):所有的在绘图窗口中的绘制都会导致窗口立即刷新。这是缺省工作模式,用于普通的绘图。
  2. 手动模式(RenderMode.Manual):绘制的内容不会立即刷新显示在绘图窗口中。要一直等到pause()/delay()/delay_fps()/get_mouse_msg()等时间控制和鼠标键盘函数被调用时,窗口才会刷新。这个模式用来加速动画帧的绘制。

在显示动画前,将渲染模式设置为手动是个好习惯。

可以使用set_render_mode()函数来设置渲染模式。

注意:如果你不是在绘图窗口中进行绘制,那么渲染模式没有任何效果。

背景处理

在动画中,我们经常需要某个物体在特定背景下移动。如果背景较为复杂,那么每帧都从头绘制一遍背景会严重影响绘制的速度。

在这种情况下,一般的处理方式是将背景预先单独绘制在一个图片上,要动的物体绘制在另一个图片上。通过对两张图片进行合成,来得到最终的结果。

下面的程序绘制了一辆在道路背景上移动的公共汽车。注意is_run()函数的使用。

from easygraphics import *

init_graph(800, 600)
set_render_mode(RenderMode.RENDER_MANUAL)

background = create_image(800, 600)
set_target(background)
set_background_color(Color.LIGHT_YELLOW)
set_fill_color(Color.RED)
draw_circle(150, 150, 50)
set_fill_color(Color.DARK_BLUE)
draw_rect(0, 400, 800, 600)

car = create_image(162, 150)
set_target(car)
set_composition_mode(CompositionMode.SOURCE)
set_background_color(Color.TRANSPARENT)
set_fill_color("white")
draw_polygon(0, 0, 0, 60, 160, 60, 160, 40, 125, 20, 110, 0)
set_fill_color("darkgray")
draw_circle(35, 60, 20)
draw_circle(120, 60, 20)
set_fill_color("transparent")
draw_rect(10, 10, 40, 25)
draw_rect(50, 10, 80, 25)

set_target()
x = 0
while is_run():
    x = (x + 2) % 750
    draw_image(0, 0, background)
    draw_image(x, 350, car)
    delay_fps(100)

background.close()
car.close()
close_graph()

跳帧

有时,一帧的绘制可能会比较复杂,因此较慢,导致该帧无法在指定的帧时长内完成绘制。这会导致动画出现延迟。

delay_jfps()函数通过跳帧来保证动画的平稳。跳帧是指,如果某帧绘制的时长太长后续的帧就会被跳过不进行绘制(但是算成是已完成绘制的帧数),从而保证达到指定的FPS。

下面的例子展示了delay_jfps()的用法。注意我们用sleep()来模拟一个耗时的操作,以便观看跳帧的效果。

from easygraphics import *
import time

init_graph(640, 480)
set_color(Color.BLUE)
set_fill_color(Color.GREEN)
set_render_mode(RenderMode.RENDER_MANUAL)

x = 0
while is_run():
    x = (x + 1) % 440
    if delay_jfps(60, 0):
        clear_device()
        draw_ellipse(x + 100, 200, 100, 100)
        time.sleep(0.5)
close_graph()