MichaelT572
MichaelT572

Reputation: 328

How to prevent python turtle from "flickering"?

So I decided to model a differential equation in python turtle, but if the turtle is moving fast it starts to "cut", with the circle repeatedly being cutoff at points

I tried to make it smoother by using tracer(0, 0) and updating it only when I need to but that still doesn't work

from turtle import *
import time
from threading import Thread
import math

setup(500, 500)
bgcolor("black")
b = Turtle()
s = b.getscreen()
tracer(0, 0)
b.color("sky blue")
b.shape("circle")
b.up()
b.goto(0, -100)
s.update()

globals()['lastt'] = 0
globals()['auto'] = 0
globals()['angle'] = 0
globals()['speed'] = 0
globals()['accel'] = 0

globals()['air'] = .5
#Starting speed
def measurespeed():
    while True:
        time.sleep(.01)
        while globals()['auto'] == 0:
            past = globals()['angle']
            time.sleep(.01)
            globals()['speed'] = (angle - past)/.01

dspeed = Thread(target=measurespeed)
dspeed.start()

#Auto
def equation():
    while True:
        time.sleep(.01)
        while globals()['auto'] == 1:
            globals()['accel'] = -5 * math.sin(angle) - (air * speed)
            globals()['speed'] += accel * .01
            globals()['angle'] += speed * .01
            time.sleep(.01)
            b.goto(100 * math.cos(angle - (math.pi / 2)), 100 * math.sin(angle - (math.pi / 2)))
            s.update()


move = Thread(target=equation)
move.start()

#Dragging
def drag(x, y):
    if x == 0:
        if y >= 0:
            b.goto(0, 100)
        else:
            b.goto(0, -100)
    elif x > 0:
        globals()['angle'] = math.atan(y/x) + (math.pi / 2)
    else:
        globals()['angle'] = math.atan(y/x) + (3 * math.pi / 2)
    b.goto(100 * math.cos(angle - (math.pi / 2)), 100 * math.sin(angle - (math.pi / 2)))
    s.update()

def static(x, y):
    globals()['auto'] = 0
    globals()['speed'] = 0

def resume(x, y):
    globals()['auto'] = 1



b.ondrag(drag)
b.onclick(static)
b.onrelease(resume)
s.mainloop()

Sorry for the lack of comments, this was supposed to be a quick experiment

Upvotes: 0

Views: 824

Answers (1)

cdlane
cdlane

Reputation: 41905

I took a crack at this: I turned off the drag handler while inside the drag handler as this can cause problems including faux recursion stack overflow.

Other changes not directly affecting function include using standard Python global notation and other style stuff like parentheses reduction:

from turtle import Screen, Turtle
from threading import Thread
from time import sleep
import math

AIR = 0.5

auto = False
angle = 0
speed = 0
accel = 0

# Starting speed
def measurespeed():
    global speed

    while True:
        sleep(0.01)

        while not auto:
            past = angle
            sleep(0.01)
            speed = (angle - past) / 0.01

# Auto
def equation():
    global accel, angle, speed

    while True:
        sleep(0.01)

        while auto:
            accel = -5 * math.sin(angle) - AIR * speed
            speed += accel * 0.01
            angle += speed * 0.01
            sleep(0.01)
            turtle.goto(100 * math.cos(angle - math.pi/2), 100 * math.sin(angle - math.pi/2))
            screen.update()

# Dragging
def drag(x, y):
    global angle

    turtle.ondrag(None)  # disable handler inside handler

    if x == 0:
        if y >= 0:
            turtle.goto(0, 100)
        else:
            turtle.goto(0, -100)
    elif x > 0:
        angle = math.atan(y / x) + math.pi/2
    else:
        angle = math.atan(y / x) + 3 * math.pi/2

    turtle.goto(100 * math.cos(angle - math.pi/2), 100 * math.sin(angle - math.pi/2))
    screen.update()

    turtle.ondrag(drag)  # reenable handler

def static(x, y):
    global auto, speed

    auto = False
    speed = 0

def resume(x, y):
    global auto

    auto = True

screen = Screen()
screen.setup(500, 500)
screen.bgcolor('black')
screen.tracer(False)

turtle = Turtle()
turtle.shape('circle')
turtle.color("sky blue")
turtle.penup()
turtle.sety(-100)

screen.update()

dspeed = Thread(target=measurespeed)
dspeed.start()

move = Thread(target=equation)
move.start()

turtle.ondrag(drag)
turtle.onclick(static)
turtle.onrelease(resume)

screen.mainloop()

Another issue to consider is that traditionally you could only do turtle graphic operations like goto() from the main thread. However, this seems to work better in the latest Python and latest tkinter. If you're still having issues, make sure to upgrade to current software. If that doesn't help, search for some of the turtle and threading questions on SO.

In the context of a drag, the click and release events appear to work fine, but on their own they don't work the way you'd expect -- both are invoked on each down and each up of the button.

Upvotes: 1

Related Questions