首页 > 解决方案 > 使用 Python Turtle 图形和图章的平滑动画

问题描述

使用 Turtle Graphics 和方法是否可以获得stamp()比下面的代码更平滑的动画效果?

我做的一个尝试是只使用stamper.clearstamps(1)inside清除第一个图章move_blocks,并且每次只绘制新块,但结果看起来是一样的。我认为问题可能是Screen.update()在后台打了电话,尽管我还没有证实这一点。

import turtle


def move_blocks():
    stamper.clearstamps()
    new_block = blocks[-1].copy()
    new_block[0] += 20
    if new_block[0] > 250:
        new_block[0] = - 250
    blocks.append(new_block)
    blocks.pop(0)

    for block in blocks:
        stamper.goto(block[0], block[1])
        stamper.stamp()

    screen.update()
    turtle.ontimer(move_blocks, 100)


screen = turtle.Screen()
screen.setup(500, 500)
screen.tracer(0)  # Turn off automatic animation

stamper = turtle.Turtle("square")
stamper.penup()

blocks = [[0, 0], [20, 0], [40, 0], [60, 0]]

for block in blocks:
    stamper.goto(block[0], block[1])
    stamper.stamp()

move_blocks()
turtle.done()

非常感谢任何帮助。

标签: pythonanimationturtle-graphics

解决方案


我认为问题可能是后台调用 Screen.update() ,尽管我还没有确认这一点。

这似乎是正确的,并且很容易确认,但不一定是整个问题。下面是我对您的代码的返工,通过仅删除失效的邮票 ID 来优化它,但它看起来并不比您的好。你可以看到我已经注释掉了screen.update(),这没什么区别:

from turtle import Screen, Turtle

def move_blocks():
    new_block = blocks.pop(0)
    new_block[0] = blocks[-1][0] + 20

    if new_block[0] > 250:
        new_block[0] = -250

    blocks.append(new_block)

    stamper.goto(new_block)
    stamper.clearstamp(ids.pop(0))
    ids.append(stamper.stamp())

    # screen.update()
    screen.ontimer(move_blocks, 100)

screen = Screen()
screen.setup(500, 500)
screen.tracer(0)  # Turn off automatic animation

stamper = Turtle('square')
stamper.hideturtle()
stamper.penup()

blocks = [[0, 0], [20, 0], [40, 0], [60, 0]]
ids = []

for block in blocks:
    stamper.goto(block)
    ids.append(stamper.stamp())

# screen.update()

move_blocks()

screen.exitonclick()

为了聪明一点,我想做一个绘图冲压的比较,但结果是一样的,填充操作触发 ascreen.update()并让我们回到我们开始的地方:

from turtle import Screen, Turtle

CURSOR_SIZE = 20

def move_blocks():
    filler.clear()

    new_block = blocks.pop(0)
    new_block[0] = blocks[-1][0] + 20

    if new_block[0] > 250:
        new_block[0] = -250

    blocks.append(new_block)

    for block in blocks:
        fill(block)

    # screen.update()
    screen.ontimer(move_blocks, 100)

def fill(position):
    filler.goto(position)

    filler.begin_fill()
    for _ in range(4):
        filler.forward(CURSOR_SIZE)
        filler.left(90)
    filler.end_fill()

screen = Screen()
screen.setup(500, 500)
screen.tracer(0)  # Turn off automatic animation

filler = Turtle()
filler.hideturtle()
filler.penup()

blocks = [[0, 0], [20, 0], [40, 0], [60, 0]]

for block in blocks:
    fill(block)

# screen.update()

move_blocks()

screen.exitonclick()

tracer()最后,我做了一个由程序员发起的screen.update()调用控制的实现。我只是重塑光标并移动它以进行比较。你可以看到这次screen.update()被注释掉的区别。

from turtle import Screen, Turtle

CURSOR_SIZE = 20
CURSOR_LENGTH = 80
STEP_SIZE = 1

def move():
    x = turtle.xcor() + STEP_SIZE

    if x - CURSOR_LENGTH/2 > 250:
        turtle.setx(-250 - CURSOR_LENGTH/2)
    else:
        turtle.forward(STEP_SIZE)

    screen.update()
    screen.ontimer(move, 5 * STEP_SIZE)

screen = Screen()
screen.setup(500, 500)
screen.tracer(0)  # Turn off automatic animation

turtle = Turtle()
turtle.shape('square')
turtle.shapesize(stretch_len=CURSOR_LENGTH/CURSOR_SIZE)
turtle.penup()

screen.update()

move()

screen.exitonclick()

然而,这个实现指出,早期较差的视觉性能也是由于步长大 - 如果您更改STEPSIZE = CURSOR_SIZE,那么您将拥有与原来相同的步长和相同的性能。


推荐阅读