简体   繁体   中英

How to launch a turtle program with a tkinter messagebox?

I am trying to launch a turtle game stored in one file with a message box from tkinter stored in another py file but both in the same directory. However, I receive a _tkinter.TclError: image "pyimage2" doesn't exist error.

I have a function inside the game code that is called upon in the launcher code. This function runs all of the code inside the main game program apart from importing modules which I have included in the function but makes no difference.

Sorry for showing all but as I don't know what the problem is I thought this was best(removed as much code irrelevant to problem as I could(Assume anything unnamed that is called is deleted as irrelevant code)

def start():
    import turtle
    import math
    import time

    counter = 0

    wn = turtle.Screen()
    wn.setup(800, 600)

    wn.bgcolor("black")
    wn.title("Trooper shooter")
    wn.bgpic("background1.png")
    wn.update()

    turtle.register_shape("invader.gif")
    turtle.register_shape("plane.gif")
    turtle.register_shape("troop.gif")
    turtle.register_shape("player1.gif")
    turtle.register_shape("player2.gif")
    turtle.register_shape("bomb.gif")
    turtle.register_shape("boom.gif")

    #player
    soldier = turtle.Turtle()
    soldier.color("blue")
    soldier.shape("player1.gif")
    soldier.penup()
    soldier.speed(0)
    soldier.setposition(0,-200)
    soldier.setheading(90)
    soldierspd = 20

    #Bomb

    Numbombs = 2
    bombs = []
    for i in range(Numbombs):
        bombs.append(turtle.Turtle())
    for bomb in bombs:
        bomb.shape("bomb.gif")
        bomb.penup()
        bomb.speed(0)
        bomb.ht()
        x = -1700

        y = 2700
        bomb.setposition(x+30,y)
        bomb.setheading(270)
    bombspeed = 10

    #Plane
    plane = turtle.Turtle()
    plane.color("red")
    plane.shape("plane.gif")
    plane.penup()
    plane.speed(0)
    plane.setposition(-270,200)
    plane.setheading(360)
    planespd = 20

    #Plane2
    plane2 = turtle.Turtle()
    plane2.ht()
    plane2.color("red")
    plane2.shape("plane.gif")
    plane2.penup()
    plane2.speed(0)
    plane2.setposition(-270,200)
    plane2.setheading(360)
    planespd2 = 20

    #ParaTroopers
    num = 5
    Troopers = []

    for i in range(num):
        Troopers.append(turtle.Turtle())

    for Troop in Troopers:
        Troop.color("Purple")
        Troop.shape("troop.gif")
        Troop.penup()
        Troop.speed(0)
        Troop.ht()
        x = -170
        y = 270
        Troop.setposition(x+30,y)
        Troop.setheading(270)
    Troopspeed = 3

    #Bullet
    bullet = turtle.Turtle()
    bullet.color("yellow")
    bullet.shape("triangle")
    bullet.penup()
    bullet.speed(0)
    bullet.setheading(90)
    bullet.shapesize(0.5, 0.5)
    bullet.ht()

    bulletspeed = 30

    #Define bullet state
    #ready = ready to fire
    #fire = bullet is firing
    state = "ready"

    #Move player left
    def Left():
        x = soldier.xcor()
        x -= soldierspd
        soldier.setx(x)
        soldier.shape("player1.gif")
        if x < -280:
            x = -280
            soldier.setx(x)


    #Move player right
    def Right():
        x = soldier.xcor()
        x += soldierspd
        soldier.setx(x)
        soldier.shape("player2.gif")
        if x > 280:
            x = 280
            soldier.setx(x)
    #Shoot bullet

    def Shoot():
        #Declare bullet state as global
        global state
        if state == "ready":
            state = "fire"
            #Move bullet above player
            x = soldier.xcor()
            y = soldier.ycor()
            bullet.setposition(x, y +10)
            bullet.showturtle()

    #HitBoxes
    def checkCollision(A,B):
        distance = math.sqrt(math.pow(A.xcor() - B.xcor(), 2) +
        math.pow(A.ycor() - B.ycor(), 2))
        if distance < 30:
            return True
        else:
            return False

    #Move plane
    def MovePlane():

        x = plane.xcor()
        x += planespd
        plane.speed(1)
        plane.setx(x)
        if plane.xcor() > 280:
            plane.ht()

    turtle.listen()
    turtle.onkey(Left,"Left")
    turtle.onkey(Right,"Right")
    turtle.onkey(Shoot,"space")


    while True:
        #Move Plane
        MovePlane()

        #Move count
        incCount()



        #Show Paratrooper
        x = -200
        for Troop in Troopers:
            if plane.xcor() > x+50:
                x += 80
                Troop.setx(x)
                Troop.showturtle()
                y = Troop.ycor()
                y -= Troopspeed
                Troop.sety(y)
                if y < -280:
                    Troop.ht()

            if checkCollision(bullet, Troop):
                # Reset bullet
                bullet.ht()
                state = "ready"
                bullet.setposition(0, -400)
                Troop.shape("boom.gif")
                # Update Scoreboard
                score += 10
                scorestring = "Score: %s" % score
                score_pen.clear()
                score_pen.write(scorestring, False, align="left", font=("Arial", 14, "normal"))
                time.sleep(0.1)
                Troop.setposition(1000, 1000)

        #update background
        if counter == 30:
            wn.bgpic("background2.png")
            wn.update()
        if counter == 60:
            wn.bgpic("background3.png")
            wn.update()
        if counter == 90:
            wn.bgpic("background4.png")
            wn.update()
        if counter == 120:
            wn.bgpic("background5.png")
            wn.update()
        if counter == 150:
            wn.bgpic("background6.png")
            wn.update()


    wn.mainloop()

from tkinter import *
from tkinter import messagebox
import TrooperShooter



root = Tk()
launch = messagebox.askquestion("launcher","Play game?")
if launch == "yes":
    TrooperShooter.start()

When the launcher is run a messagebox should appear saying do you wish to play and when "yes" is clicked the function to start the game is launched. However I receive the error:

Traceback (most recent call last):
  File "C:/Users/marco/Desktop/Trooper shooter/launcher.py", line 10, in <module>
    TrooperShooter.start()
  File "C:\Users\marco\Desktop\Trooper shooter\TrooperShooter.py", line 18, in start
    wn.bgpic("background1.png")
  File "C:\Program Files (x86)\Python37-32\lib\turtle.py", line 1482, in bgpic
    self._setbgpic(self._bgpic, self._bgpics[picname])
  File "C:\Program Files (x86)\Python37-32\lib\turtle.py", line 738, in _setbgpic
    self.cv.itemconfig(item, image=image)
  File "<string>", line 1, in itemconfig
  File "C:\Program Files (x86)\Python37-32\lib\tkinter\__init__.py", line 2578, in itemconfigure
    return self._configure(('itemconfigure', tagOrId), cnf, kw)
  File "C:\Program Files (x86)\Python37-32\lib\tkinter\__init__.py", line 1476, in _configure
    self.tk.call(_flatten((self._w, cmd)) + self._options(cnf))
_tkinter.TclError: image "pyimage2" doesn't exist

Process finished with exit code 1

My first suggestion is that you use the turtle textinput() method (new in Python 3) instead of dragging tkinter and messagebox into the picture.

But if you're going to combine tkinter and turtle, you need to do it correctly. Turtle is designed to run either standalone with its own Tk window or embedded in an existing tkinter window. You're attempting to run it standalone, embedded in a tkinter window. Ie instead of the standalone Turtle & Screen interface, you should be working with the embedded TurtleScreen , RawTurtle and ScrolledCanvas interface.

Besides this issue, your code is generally buggy. You've lots of unfinished code. Your use of global has to become nonlocal when you move the entire program inside the start() function. You're missing pieces of code necessary to run. Finally, you have a while True: loop which has no business being in an event-driven environment like turtle. I've repaced it with a timer event.

I've reworked your code below to run as you intended. I've tossed incomplete and/or broken features to simplify the example. The startup code:

from tkinter import Tk
from tkinter import messagebox
import TrooperShooter

root = Tk()

launch = messagebox.askquestion("launcher", "Play game?")

if launch == "yes":

    TrooperShooter.start(root)

TrooperShooter.py

import tkinter as tk
from turtle import TurtleScreen, ScrolledCanvas, RawTurtle

def start(root):

    # Move player left
    def Left():
        soldier.shape("player1.gif")

        x = soldier.xcor() - soldierspd
        soldier.setx(x)

        if x < -280:
            soldier.setx(-280)

    # Move player right
    def Right():
        soldier.shape("player2.gif")

        x = soldier.xcor() + soldierspd
        soldier.setx(x)

        if x > 280:
            soldier.setx(280)

    # Shoot bullet
    def Shoot():
        # Declare bullet state as global
        nonlocal state

        if state == "ready":
            state = "fire"
            # Move bullet above player
            x, y = soldier.position()
            bullet.setposition(x, y + 10)
            bullet.showturtle()

    # HitBoxes
    def checkCollision(a, b):
        return a.distance(b) < 30

    # Move plane
    def MovePlane():
        x = plane.xcor() + plane_speed
        plane.setx(x)

        if plane.xcor() > 280:
            plane.hideturtle()

    def action():
        nonlocal state, score

        # Move Plane
        MovePlane()

        # Show Paratrooper
        x = -200
        for troop in troopers:
            if plane.xcor() > x + 50:
                x += 80
                troop.setx(x)
                troop.showturtle()
                y = troop.ycor() - troop_speed
                troop.sety(y)
                if y < -280:
                    troop.hideturtle()

            if checkCollision(bullet, troop):
                # Reset bullet
                bullet.hideturtle()
                state = "ready"
                bullet.setposition(0, -400)
                troop.shape("boom.gif")
                # Update Scoreboard
                score += 10
                scorestring = "Score: %s" % score
                score_pen.clear()
                score_pen.write(scorestring, align="left", font=("Arial", 14, "normal"))
                troop.setposition(1000, 1000)

        if state == "fire":
            y = bullet.ycor()

            if y > 300:
                state = 'ready'
                bullet.hideturtle()
            else:
                bullet.sety(y+ bullet_speed)

        screen.ontimer(action, 100)

    score = 0

    # Define bullet state
    # ready = ready to fire
    # fire = bullet is firing
    state = "ready"

    root.geometry("800x600")
    root.title("Trooper shooter")

    canvas = ScrolledCanvas(root)
    canvas.pack(fill=tk.BOTH, expand=tk.YES)

    screen = TurtleScreen(canvas)

    screen.bgcolor("black")
    screen.bgpic("background1.png")

    screen.register_shape("invader.gif")
    screen.register_shape("plane.gif")
    screen.register_shape("troop.gif")
    screen.register_shape("player1.gif")
    screen.register_shape("player2.gif")
    screen.register_shape("boom.gif")

    # Player
    soldier = RawTurtle(screen)
    soldier.color("blue")
    soldier.shape("player1.gif")
    soldier.penup()
    soldier.speed('fastest')
    soldier.setposition(0, -200)
    soldier.setheading(90)
    soldierspd = 20

    # Score
    score_pen = RawTurtle(screen)
    score_pen.speed('fastest')
    score_pen.hideturtle()

    # Plane
    plane = RawTurtle(screen)
    plane.color("red")
    plane.shape("plane.gif")
    plane.penup()
    plane.speed('fastest')
    plane.setposition(-270, 200)
    plane.setheading(360)
    plane_speed = 20

    # ParaTroopers
    number_troops = 5
    troopers = []

    for _ in range(number_troops):
        troop = RawTurtle(screen)
        troop.color("Purple")
        troop.shape("troop.gif")
        troop.penup()
        troop.speed('fastest')
        troop.hideturtle()
        x, y = -170, 270
        troop.setposition(x + 30, y)
        troop.setheading(270)

        troopers.append(troop)

    troop_speed = 3

    # Bullet
    bullet = RawTurtle(screen)
    bullet.color("yellow")
    bullet.shape("triangle")
    bullet.penup()
    bullet.speed('fastest')
    bullet.setheading(90)
    bullet.shapesize(0.5)
    bullet.hideturtle()

    bullet_speed = 30

    screen.onkey(Left, "Left")
    screen.onkey(Right, "Right")
    screen.onkey(Shoot, "space")
    screen.listen()

    action()

    screen.mainloop()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM