Python Таймеры Черепахи / Tkinter Ускорение - PullRequest
0 голосов
/ 26 марта 2020

Я думал, что канонический способ сделать анимацию с Python Turtle Graphics заключается в том, чтобы сделать что-то вроде

def animate():
   # move stuff
   ontimer(animate, delay)

Изучая исходный код для turtle, он реализует tkinter after() в background.

Может кто-нибудь объяснить, почему в приведенной ниже программе анимация значительно ускоряется и замедляется, когда она остается запущенной?

Моя теория состоит в том, что, поскольку каждый раз создается новый .after() идентификатор ontimer() называется, существуют ли как-то несколько таймеров, которые мешают друг другу? А может это просто случайность в программе? Или, может быть, короткий интервал между обратными вызовами вызывает проблемы?

from random import *
from turtle import *
import math

class Vector(object):
    def __init__(self, x = 0.0, y = 0.0):
        self.x = x
        self.y = y

    def move(self, other):
        """ Move vector by other (in-place)."""
        self.__iadd__(other)

    def __iadd__(self, other):
        if isinstance(other, Vector):
            self.x += other.x
            self.y += other.y
        else:
            self.x += other
            self.y += other

    def rotate(self, angle):
        """Rotate vector counter-clockwise by angle (in-place)."""
        radians = angle * math.pi / 180.0
        cosine = math.cos(radians)
        sine = math.sin(radians)
        x = self.x
        y = self.y
        self.x = x * cosine - y * sine
        self.y = y * cosine + x * sine

ant = Vector(0, 0)
aim = Vector(2, 0)

def wrap(value):
    "Wrap value around -200 and 200."
    if value > 200:
        value = -200
    elif value < -200:
        value = 200
    return value

def draw():
    "Move ant and draw screen."
    ant.move(aim)
    ant.x = wrap(ant.x)
    ant.y = wrap(ant.y)

    aim.move(random() - 0.5)
    aim.rotate(random() * 10 - 5)

    clear()
    goto(ant.x, ant.y)
    dot(10)

    if running:
        ontimer(draw, 50)

setup(420, 420, 370, 0)
hideturtle()
tracer(False)
up()
running = True
draw()
done()

1 Ответ

0 голосов
/ 26 марта 2020

Я считаю, что ваша анимация ускоряется и замедляется, потому что вы используете tracer(), но не можете сделать явный update(). Функция tracer() отключает анимацию, но некоторые операции с черепахой делают неявный update() в качестве побочного эффекта. Поскольку вы не делали явного update(), вы только получали случайные обновления, вызванные этими побочными эффектами.

Ниже я добавил явный update() и упростил код сделать саму черепаху движущимся объектом, вместо штамповки и очистки . (Кстати, если вы сохраните результат stamp(), вы можете попросить его очистить себя.)

Я также переключился с изображения круга на изображение курсора черепахи и добавил в logi c, чтобы установить в направлении движения:

from random import random
from turtle import Screen, Turtle, Vec2D
from math import pi, cos, sin

class Vector(object):
    def __init__(self, x=0.0, y=0.0):
        self.x = x
        self.y = y

    def move(self, other):
        """ Move vector by other (in-place)."""

        self.__iadd__(other)

        self.wrap()

    def __iadd__(self, other):
        if isinstance(other, Vector):
            self.x += other.x
            self.y += other.y
        else:
            self.x += other
            self.y += other

    def rotate(self, degrees):
        """ Rotate vector counter-clockwise by angle (in-place). """

        radians = degrees * pi / 180.0
        cosine = cos(radians)
        sine = sin(radians)

        x = self.x
        y = self.y

        self.x = x * cosine - y * sine
        self.y = y * cosine + x * sine

    def position(self):
        return Vec2D(self.x, self.y)

    def wrap(self):
        """ Wrap value around -200 and 200. """

        x = self.x
        y = self.y

        if x > 200:
            self.x = -200
        elif x < -200:
            self.x = 200

        if y > 200:
            self.y = -200
        elif y < -200:
            self.y = 200

def draw():
    """ Move ant and draw screen. """

    ant.move(aim)

    position = ant.position()
    turtle.setheading(turtle.towards(position))
    turtle.setposition(position)

    screen.update()

    aim.move(random() - 0.5)
    aim.rotate(random() * 10 - 5)

    screen.ontimer(draw, 75)

screen = Screen()
screen.setup(420, 420)
screen.tracer(False)

turtle = Turtle()
turtle.hideturtle()
turtle.shape('turtle')
turtle.shapesize(0.5)
turtle.penup()
turtle.showturtle()

ant = Vector(0, 0)
aim = Vector(2, 0)

draw()

screen.mainloop()
...