Skip to content Skip to sidebar Skip to footer

Error When Opening Different Windows In Turtle Using Tkinter

I have a problem using turtle with tkinter in Python 3.8. Still new to programming so thanks in advance! I have a tkinter window where you can chose to play either level one or two

Solution 1:

A number of changes need to be made to get a design that works:

First, when you use turtle within tkinter, you need to use embedded turtle (i.e. TurtleScreen, RawTurtle) not standalone turtle (Screen, Turtle).

Since TurtleScreen doesn't want to be a Toplevel instance, I swapped the maze and menu windows.

The turtle screen.clear() method is highly destructive -- besides clearing the screen, it undoes bindings, background colors, tracer setings, etc. and kills all the turtles. So we have to program accordingly.

Don't call screen.bye() if you plan to use the window again. Turtle has a distance() method, you don't have to reinvent it.

Finally, turtles wander a floating point plan. If you save the coordinates of your walls, they won't match turtle positions as turtles accumulate error. You need to coerce the comparison to integer.

Below is my attempt to rework your code to address the above issues:

from turtle import TurtleScreen, RawTurtle
from time import monotonic as my_timer
import tkinter as tk

# tk constants
TK_BG_COLOR = "light green"
FONT = ("comic sans ms", 20)
BUTTON_HEIGHT = 2
BUTTON_WIDTH = 10
PAD_X = 40
PAD_Y = 25

# turtle contants
BG_COLOR = 'black'
WALL_SHAPE = 'square'
WALL_COLOR = 'red'
WALL_SIZE = 24
PLAYER_SHAPE = 'classic'
PLAYER_COLOR = 'white'
CURSOR_SIZE = 20

level_1 = [
    '*************************',
    '*S*****          ********',
    '*   *******  *** ***    *',
    '** T        **** *** ** *',
    '**** ****** **** *** ** *',
    '**** **   ****   *** ** *',
    '***  ** * **         ** *',
    '**** *  * T  ******* *  *',
    '***  ***   ** T   ** * **',
    '*T *     ******** **   **',
    '** ***** ****        ** *',
    '**   ***T************** *',
    '* ** ***  ****    **  T *',
    '*T * ***       ***** ****',
    '** * **  ****        *  *',
    '** * **  * **  ***** * **',
    '**      ** **  ***     **',
    '****** ***    T   **** **',
    '**  ** ** * ** ** **** **',
    '*E* ** ** * ***** **** **',
    '* * ** **   *         ***',
    '* *       ***  **** *****',
    '* ***********  *T**    **',
    '*              *    **  *',
    '*************************'
]

level_2 = [
    '*************************',
    '*******S         ********',
    '**T *******  *** ***    *',
    '***        ****  *** ** *',
    '**** ****** **** *** ** *',
    '**** **   ****   *** ** *',
    '***  ** * **         ** *',
    '**** *  * T  ******* *  *',
    '***  ***   ** T   ** * **',
    '*T *     ******** **   **',
    '** ***** ****        ** *',
    '**   ***T************** *',
    '* ** ***  ****    **  T *',
    '*T * ***       ***** ****',
    '** * **  ****        *  *',
    '** * **  * **  ***** * **',
    '**      ** **  ***     **',
    '****** ***    T   **** **',
    '**  ** ** * ** ** **** **',
    '** ** ** * *** ** **** **',
    '*T* ** **   *         ***',
    '* *       ***  **** *****',
    '* ***********  *T**    **',
    '*              *    ** E*',
    '*************************'
]

levels = [("", None), ("Level 2", level_1), ("Level 2", level_2)]

class Walls(RawTurtle):
    def __init__(self, canvas):
        super().__init__(canvas)
        self.shape(WALL_SHAPE)
        self.color(WALL_COLOR)
        self.penup()

class Player(RawTurtle):
    def __init__(self, canvas):
        super().__init__(canvas)
        self.shape(PLAYER_SHAPE)
        self.color(PLAYER_COLOR)
        self.penup()
        self.setheading(270)

        self.gold = 0

    def move_up(self):
        self.setheading(90)
        if (int(self.xcor()), int(self.ycor()) + WALL_SIZE) not in wall_coordinates:
            self.sety(self.ycor() + WALL_SIZE)

    def move_down(self):
        self.setheading(270)
        if (int(self.xcor()), int(self.ycor()) - WALL_SIZE) not in wall_coordinates:
            self.sety(self.ycor() - WALL_SIZE)

    def move_left(self):
        self.setheading(180)
        if (int(self.xcor()) - WALL_SIZE, int(self.ycor())) not in wall_coordinates:
            self.setx(self.xcor() - WALL_SIZE)

    def move_right(self):
        self.setheading(0)
        if (int(self.xcor()) + WALL_SIZE, int(self.ycor())) not in wall_coordinates:
            self.setx(self.xcor() + WALL_SIZE)

    def has_collided(self, other):
        return self.distance(other) < 5

    def print_score(self):
        print("Your total score is: {} ".format(self.gold))

class Treasure(RawTurtle):
    def __init__(self, canvas, x, y):
        super().__init__(canvas)
        self.shape('circle')
        self.color('yellow')
        self.penup()
        self.goto(x, y)

        self.gold = 100

    def destroy(self):
        self.hideturtle()

class Finish(RawTurtle):
    def __init__(self, canvas, x, y):
        super().__init__(canvas)
        self.shape('square')
        self.color('green')
        self.penup()
        self.goto(x, y)

def load_level(level):
    global player

    hide_menu()
    title, maze = levels[level]
    root.title(title)
    player = Player(screen)  # recreate as it's destroyed by screen.clear()
    set_up_maze(maze)

    # rebind turtle key bindings as they're unbound by screen.clear()
    screen.onkey(player.move_up, 'Up')
    screen.onkey(player.move_down, 'Down')
    screen.onkey(player.move_left, 'Left')
    screen.onkey(player.move_right, 'Right')
    screen.listen()

    level_finished = False
    start_time = my_timer()

    while not level_finished:
        for treasure in treasures:
            if player.has_collided(treasure):
                player.gold += treasure.gold
                treasure.destroy()
                treasures.remove(treasure)

        for end in end_points:
            if player.has_collided(end):
                level_finished = True

        screen.update()

    screen.clear()
    screen.bgcolor(BG_COLOR)  # redo as it's undone by clear()
    screen.tracer(0)  # redo as it's undone by clear()

    show_menu()

    end_time = my_timer()
    total_time = end_time - start_time
    player.print_score()
    print("Total time was {:.2f} seconds".format(total_time))

def set_up_maze(maze):
    walls = Walls(screen)

    for y, row in enumerate(maze):  # get the character co ordinates
        for x, character in enumerate(row):
            screen_x = -288 + (x * WALL_SIZE)  # calculate the screen co ordinates
            screen_y = 288 - (y * WALL_SIZE)

            if character == '*':
                walls.goto(screen_x, screen_y)  # make the  * characters into walls
                walls.stamp()
                wall_coordinates.append((screen_x, screen_y))
            elif character == 'S':  # make the player start point
                player.goto(screen_x, screen_y)
            elif character == 'T':  # make the treasure spawn points
                treasures.append(Treasure(screen, screen_x, screen_y))
            elif character == 'E':  # make the end point
                end_points.append(Finish(screen, screen_x, screen_y))

def hide_menu():
    menu.withdraw()

def show_menu():
    menu.deiconify()
    menu.update()

# lists
wall_coordinates = []
treasures = []
end_points = []

root = tk.Tk()
root.title("Maze game")
root.resizable(width=False, height=False)

canvas = tk.Canvas(root, width=700, height=700)
canvas.pack()

screen = TurtleScreen(canvas)
screen.bgcolor(BG_COLOR)
screen.tracer(0)

player = None

menu = tk.Toplevel(root)
menu.title("Maze game")
menu.config(bg=TK_BG_COLOR)
menu.geometry("250x600+600+100")
menu.resizable(width=False, height=False)

title_label = tk.Label(menu, text="Maze Game", font=FONT, bg=TK_BG_COLOR)
title_label.grid(row=0, column=0, padx=PAD_X, pady=PAD_Y)
level_1_btn = tk.Button(menu, text="Level 1", font=FONT, height=BUTTON_HEIGHT, width=BUTTON_WIDTH, bg=TK_BG_COLOR, command=lambda: load_level(1))
level_1_btn.grid(row=1, column=0, padx=PAD_X, pady=PAD_Y)
level_2_btn = tk.Button(menu, text="Level 2", font=FONT, height=BUTTON_HEIGHT, width=BUTTON_WIDTH, bg=TK_BG_COLOR, command=lambda: load_level(2))
level_2_btn.grid(row=2, column=0, padx=PAD_X, pady=PAD_Y)
close_btn = tk.Button(menu, text="Exit", font=FONT, height=BUTTON_HEIGHT, width=BUTTON_WIDTH, bg=TK_BG_COLOR, command=quit)
close_btn.grid(row=3, column=0, padx=PAD_X, pady=PAD_Y)

screen.mainloop()

Post a Comment for "Error When Opening Different Windows In Turtle Using Tkinter"