Search code examples
pythonpython-3.xpython-multiprocessingturtle-graphics

How can I move 2 turtles at once in Python3


I want to make a fractal tree in python. I have made the tree, but I want to have 2 turtles or more to draw my fractal tree all at once. Is there a way to do that? I've looked for solutions but none of them is what I really want. Here is my code:

import turtle
tree = turtle.Turtle()
tree.ht()
tree.penup()
tree.sety(-200)
tree.left(90)

import turtle
tree0 = turtle.Turtle()
tree0.ht()
tree0.penup()
tree0.sety(-200)
tree0.left(90)

startx = tree.xcor()
starty = tree.ycor()
startx = tree0.xcor()
starty = tree0.ycor()

def fractalright(angle, length, x, y):
    tree.speed(0)
    tree.setx(x)
    tree.sety(y)
    tree.pendown()
    tree.forward(length)
    tree.right(angle)
    length = length - 20
    x = tree.xcor()
    y = tree.ycor()
    if length < 0:
        return
    tree.penup()
    fractalright(angle, length, x, y)
    tree.penup()
    tree.setx(x)
    tree.sety(y)
    tree.left(angle)
    fractalright (-angle, length, x, y)
def fractalleft(angle, length, x, y):
    tree0.speed(0)
    tree0.setx(x)
    tree0.sety(y)
    tree0.pendown()
    tree0.forward(length)
    tree0.right(angle)
    length = length - 20
    x = tree0.xcor()
    y = tree0.ycor()
    if length < 0:
        return
    tree0.penup()
    fractalleft(angle, length, x, y)
    tree0.penup()
    tree0.setx(x)
    tree0.sety(y)
    tree0.left(angle)
    fractalleft (-angle, length, x, y)

I am using python 3 and please let me know if you know a solution. Thanks!!


Solution

  • The key to using module threading with turtle is to not allow additional threads to manipulate the turtles -- they instead queue up their turtle requests and let the main thread process them:

    import queue
    from threading import Thread, active_count
    from turtle import Turtle, Screen
    
    def forward(turtle, distance):
        graphics.put((turtle.forward, distance))
    
    def right(turtle, angle):
        graphics.put((turtle.right, angle))
    
    def left(turtle, angle):
        graphics.put((turtle.left, angle))
    
    def fractalright(turtle, angle, length):
        forward(turtle, length)
    
        if length - 20 > 0:
            right(turtle, angle)
            fractalright(turtle, angle, length - 20)
            left(turtle, angle)
            fractalright(turtle, -angle, length - 20)
    
        forward(turtle, -length)
    
    def fractalleft(turtle, angle, length):
        forward(turtle, length)
    
        if length - 20 > 0:
            left(turtle, angle)
            fractalleft(turtle, angle, length - 20)
            right(turtle, angle)
            fractalleft(turtle, -angle, length - 20)
    
        forward(turtle, -length)
    
    def process_queue():
        while not graphics.empty():
            action, argument = graphics.get()
            action(argument)
    
        if active_count() > 1:
            screen.ontimer(process_queue, 100)
    
    START_X, START_Y = 0, -200
    
    screen = Screen()
    screen.mode('logo')  # make starting direction 0 degrees towards top
    
    tree1 = Turtle(visible=False)
    tree1.color('green')
    tree1.penup()
    tree1.goto(START_X, START_Y)
    tree1.pendown()
    
    tree2 = Turtle(visible=False)
    tree2.color('dark green')
    tree2.penup()
    tree2.goto(START_X, START_Y)
    tree2.pendown()
    
    graphics = queue.Queue(1)  # size = number of hardware threads you have - 1
    
    def fractal1():
        fractalright(tree1, 30, 100)
    
    def fractal2():
        fractalleft(tree2, 30, 100)
    
    thread1 = Thread(target=fractal1)
    thread1.daemon = True  # thread dies when main thread (only non-daemon thread) exits.
    thread1.start()
    
    thread2 = Thread(target=fractal2)
    thread2.daemon = True  # thread dies when main thread (only non-daemon thread) exits.
    thread2.start()
    
    process_queue()
    
    screen.exitonclick()
    

    We're using the queue module for thread-safe communications. I rewrote your fractalright() and fractalleft() functions to minimize the variety of graphics operations they require.

    enter image description here

    If all goes correctly, you should see the light green and dark green portions of the tree being drawn independently at the same time. Your computer needs to have at least a couple of hardware threads available.