Get coordinates of “treasure” (turtles) in Maze Game that uses Python tkinter and turtle

|▌冷眼眸甩不掉的悲伤 提交于 2021-01-29 14:50:44

问题


I am using Python 3 to make a maze using tkinter and turtle graphics. Most of the code works, except I cannot figure out how to "destroy" the "gold" in the game. Specifically, calling player.collision(), it says Question object has no attribute xcor even though I got this from a tutorial about a turtle Python maze game. I figured it would work the same as it did in that context, but with tkinter, everything seems to change. The problem occurs under player.collision() and the while loop at the end. Those are the two sections of code that are meant to "destroy," or hide, the "gold" turtles. I have included (almost) my entire code so everyone can see what is going on.

(In addition to this question, I would like to create a way to move the player using the arrow keys rather than the buttons on the frame, but I can't figure out how.)

I have tried naming the turtle specifically rather than just "other" in the collision() function. I have also tried making new methods under the Question class to "getX" and "getY" by returning tur3.xcor() and tur3.ycor() respectively. But this did not do anything except give me another error. Like I said, this code WORKED when it was just a turtle maze, but since adding tkinter, I have had to change a whole bunch of things.

import turtle
import tkinter
import math

# Create window and canvas using tkinter.
root = tkinter.Tk()
root.title("Language Labyrinth")
cv = tkinter.Canvas(root, width=600, height=600)
cv.pack()

# Create frame where button(s) will be.
frame = tkinter.Frame(root)
frame.pack()

# Create Pen class to draw the maze.
class Pen():
    def __init__(self):
        global tur
        global screen
        tur = turtle.RawTurtle(cv)
        screen = tur.getscreen()
        tur.shape("square")
        tur.color("white")
        screen.bgcolor("black")
        tur.penup()
        tur.speed(0)

# Create setup so the maze will be drawn.
    def setup(self, level):
        global tur, walls
        for y in range(len(level)):
            for x in range(len(level[y])):
                char = level[y][x]

                screenx = -288 + (x * 24)
                screeny = 288 - (y * 24)

                if char == "X":
                    tur.goto(screenx, screeny)
                    tur.stamp()

                    walls.append((screenx, screeny))

# Create player class to have a player.
class Player():
    def __init__(self):
        global tur2
        tur2 = turtle.RawTurtle(cv)
        tur2.shape("square")
        tur2.color("blue")
        tur2.penup()
        tur2.speed(0)

# Create setup to create the player on the screen.
    def setup2(self, level):
        global tur2
        for y in range(len(level)):
            for x in range(len(level[y])):
                char = level[y][x]

                screenx = -288 + (x * 24)
                screeny = 288 - (y * 24)

                if char == "P":
                    tur2.goto(screenx, screeny)

# Define a function that will allow player to move up.
    def up(self):
        global tur2, walls
        # Calculate the spot to move to.
        movetoX = tur2.xcor()
        movetoY = tur2.ycor() + 24

        # Check if the space has a wall.
        if (movetoX, movetoY) not in walls:
            tur2.goto(movetoX, movetoY)

# Define a function that will allow player to move down.
    def down(self):
        global tur2, walls
        # Calculate the spot to move to.
        movetoX = tur2.xcor()
        movetoY = tur2.ycor() - 24

        # Check if the space has a wall.
        if (movetoX, movetoY) not in walls:
            tur2.goto(movetoX, movetoY)

# Define a function that will allow player to move left.
    def left(self):
        global tur2, walls
        # Calculate the spot to move to.
        movetoX = tur2.xcor() - 24
        movetoY = tur2.ycor()

        # Check if the space has a wall.
        if (movetoX, movetoY) not in walls:
            tur2.goto(movetoX, movetoY)

# Define a function that will allow player to move right.
    def right(self):
        global tur2, walls
        # Calculate the spot to move to.
        movetoX = tur2.xcor() + 24
        movetoY = tur2.ycor()

        # Check if the space has a wall.
        if (movetoX, movetoY) not in walls:
            tur2.goto(movetoX, movetoY)

# Check if player touches the question.
    def collision(self, other):
        global tur2
        a = tur2.xcor() - other.xcor()
        b = tur2.ycor() - other.ycor()
        distance = math.sqrt((a ** 2) + (b ** 2))

        if distance < 5:
            return True
        else:
            return False

# Create Question class to create the "gold" in the game.
class Question():
    def __init__(self, x, y):
        global tur3
        tur3 = turtle.RawTurtle(cv)
        tur3.shape("circle")
        tur3.color("gold")
        tur3.penup()
        tur3.speed(0)
        tur3.goto(x, y)

    # Define function that will remove gold when collided with.
    def destroy(self):
        global tur3
        tur3.goto(2000, 2000)
        tur3.hideturtle()

# Create a levels list.
levels = [""]

# Define first level.
level_1 = [
"XXXXXXXXXXXXXXXXXXXXXXXXX",
"XP XXXXXXX          XXXXX",
"X  XXXXXXX  XXXXXX  XXXXX",
"X       XX  XXXXXX  XXXXX",
"X       XX  XXX        XX",
"XXXXXX  XX  XXX   Q    XX",
"XXXXXX  XX  XXXXXX  XXXXX",
"XXXXXX  XX    XXXX  XXXXX",
"X  XXX Q      XXXX  XXXXX",
"X  XXX  XXXXXXXXXXXXXXXXX",
"X         XXXXXXXXXXXXXXX",
"X     Q          XXXXXXXX",
"XXXXXXXXXXXX     XXXXX  X",
"XXXXXXXXXXXXXXX  XXXXX  X",
"XXX  XXXXXXXXXX         X",
"XXX               Q     X",
"XXX         XXXXXXXXXXXXX",
"XXXXXXXXXX  XXXXXXXXXXXXX",
"XXXXXXXXXX              X",
"XX   XXXXX        Q     X",
"XX   XXXXXXXXXXXXX  XXXXX",
"XX    XXXXXXXXXXXX  XXXXX",
"XX    Q     XXXX        X",
"XXXX                    X",
"XXXXXXXXXXXXXXXXXXXXXXXXX"
]

# Add questions list.
questions = []

# Add the level(s) to the levels list.
levels.append(level_1)

# Class instances.
pen = Pen()
player = Player()

# Wall coordinate list.
walls = []

# Define function to setup the "gold" in the game.
def setup3(level):
    for y in range(len(level)):
        for x in range(len(level[y])):
            char = level[y][x]

            screenx = -288 + (x * 24)
            screeny = 288 - (y * 24)

            if char == "Q":
                questions.append(Question(screenx, screeny))

#screen.onkeypress(player.up, "Up")
#screen.onkeypress(player.down, "Down")
#screen.onkeypress(player.left, "Left")
#screen.onkeypress(player.right, "Right")

# Creation of buttons that will allow player to move. (BIND ARROWS W/O BUTTONS??)
up = tkinter.Button(frame, text="Up", command=player.up)
up.bind("<Up>", player.up)
up.pack()
down = tkinter.Button(frame, text="Down", command=player.down)
down.bind("<Down>", player.down)
down.pack()
left = tkinter.Button(frame, text="Left", command=player.left)
left.bind("<Left>", player.left)
left.pack()
right = tkinter.Button(frame, text="Right", command=player.right)
right.bind("<Right>", player.right)
right.pack()

# Define a function for the quit button.
def quitPlaying():
    root.destroy()
    root.quit()

# Creation of quit button.
quitButton = tkinter.Button(frame, text="Quit", command=quitPlaying)
quitButton.pack()

# Game loop in regards to the gold. (Needs debugging)
while True:
    # Check for player collision with a question.
    # Iterate through the questions list.
    for question in questions:
        if player.collision(question):
            # Destroy the question.
            question.destroy()
            # Remove question from questions list.
            questions.remove(question)

    # Update screen.
    screen.update()

# Call main game loop.
tkinter.mainloop()

Basically, I expect that when I move over the "gold" turtles, I want them to disappear as if I've collected them.

(And for the movement, I would expect to use the arrow keys for movement instead of the buttons, but again, this is a secondary thing.)


回答1:


Your immediate problem is this:

if player.collision(question):

def collision(self, other):
    # ...
    a = tur2.xcor() - other.xcor()

You call collision() with question as it's second argument and the function assumes that the second argument is a turtle when it invokes .xcor() on it. But it isn't a turtle, it's a Question instance that contains a turtle.

The larger problem is that your program is a complete misunderstanding of classes, instances and globals. Consider the pen instance of the Pen class -- you create it and ignore it as it's work is done by the global tur you created as a side-effect! This sort of thing recurs throughout your program. And it's clear you don't understand the global keyword so I suggest your (re)read about that.

I've reworked your program below to fix many, but not all, of the problems I saw. The classes Pen, Player, and Question are now subclasses of RawTurtle, rather than containing one. And no globals are set via side-effect. Your gold now disappears when you reach it and your can use the arrow keys (just click on the window first.)

from turtle import RawTurtle, TurtleScreen
import tkinter

# Create Pen class to draw the maze.
class Pen(RawTurtle):
    def __init__(self):
        super().__init__(screen, shape='square')
        self.speed('fastest')
        self.color('white')
        self.penup()

    # Create setup so the maze will be drawn.
    def setup(self, level):
        for y in range(len(level)):
            screen_y = 288 - (y * 24)

            for x in range(len(level[y])):
                if level[y][x] == 'X':
                    screen_x = (x * 24) - 288

                    self.goto(screen_x, screen_y)
                    self.stamp()

                    walls.append((screen_x, screen_y))

# Create player class to have a player.
class Player(RawTurtle):
    def __init__(self):
        super().__init__(screen, shape='square')
        self.speed('fastest')
        self.color('blue')
        self.penup()

    # Create setup to create the player on the screen.
    def setup(self, level):
        for y in range(len(level)):
            for x in range(len(level[y])):
                if level[y][x] == 'P':
                    screen_x = (x * 24) - 288
                    screen_y = 288 - (y * 24)

                    self.goto(screen_x, screen_y)

                    return

    # Define a function that will allow player to move up.
    def move_up(self):
        # Calculate the spot to move to.
        movetoX = self.xcor()
        movetoY = self.ycor() + 24

        # Check if the space has a wall.
        if (movetoX, movetoY) not in walls:
            self.goto(movetoX, movetoY)

            gold_encounter()

    # Define a function that will allow player to move down.
    def move_down(self):
        # Calculate the spot to move to.
        movetoX = self.xcor()
        movetoY = self.ycor() - 24

        # Check if the space has a wall.
        if (movetoX, movetoY) not in walls:
            self.goto(movetoX, movetoY)

            gold_encounter()

    # Define a function that will allow player to move left.
    def move_left(self):
        # Calculate the spot to move to.
        movetoX = self.xcor() - 24
        movetoY = self.ycor()

        # Check if the space has a wall.
        if (movetoX, movetoY) not in walls:
            self.goto(movetoX, movetoY)

            gold_encounter()

    # Define a function that will allow player to move right.
    def move_right(self):
        # Calculate the spot to move to.
        movetoX = self.xcor() + 24
        movetoY = self.ycor()

        # Check if the space has a wall.
        if (movetoX, movetoY) not in walls:
            self.goto(movetoX, movetoY)

            gold_encounter()

    # Check if player touches the question.
    def collision(self, other):
        return self.distance(other) < 5

# Create Question class to create the "gold" in the game.
class Question(RawTurtle):
    def __init__(self, x, y):
        super().__init__(screen, shape='circle', visible=False)

        self.speed('fastest')
        self.color('gold')
        self.penup()
        self.goto(x, y)
        self.showturtle()

    # Define function that will remove gold when collided with.
    def destroy(self):
        self.hideturtle()

# Define function to setup the "gold" in the game.
def setup(level):
    for y in range(len(level)):
        for x in range(len(level[y])):
            char = level[y][x]

            screen_x = -288 + (x * 24)
            screen_y = 288 - (y * 24)

            if char == 'Q':
                questions.append(Question(screen_x, screen_y))

# Define a function for the quit button.
def quitPlaying():
    root.destroy()
    root.quit()

# Game loop in regards to the gold.
def gold_encounter():
    # Check for player collision with a question.
    # Iterate through the questions list.
    for question in questions:
        if player.collision(question):
            # Destroy the question.
            question.destroy()
            # Remove question from questions list.
            questions.remove(question)

# Create window and canvas using tkinter.
root = tkinter.Tk()
root.title("Language Labyrinth")

canvas = tkinter.Canvas(root, width=600, height=600)
canvas.pack()

screen = TurtleScreen(canvas)
screen.bgcolor('black')

# Create frame where button(s) will be.
frame = tkinter.Frame(root)
frame.pack()

# Add questions list.
questions = []

# Wall coordinate list.
walls = []

# Create a levels list.
levels = []

# Define first level.
level_1 = [
"XXXXXXXXXXXXXXXXXXXXXXXXX",
"XP XXXXXXX          XXXXX",
"X  XXXXXXX  XXXXXX  XXXXX",
"X       XX  XXXXXX  XXXXX",
"X       XX  XXX        XX",
"XXXXXX  XX  XXX   Q    XX",
"XXXXXX  XX  XXXXXX  XXXXX",
"XXXXXX  XX    XXXX  XXXXX",
"X  XXX Q      XXXX  XXXXX",
"X  XXX  XXXXXXXXXXXXXXXXX",
"X         XXXXXXXXXXXXXXX",
"X     Q          XXXXXXXX",
"XXXXXXXXXXXX     XXXXX  X",
"XXXXXXXXXXXXXXX  XXXXX  X",
"XXX  XXXXXXXXXX         X",
"XXX               Q     X",
"XXX         XXXXXXXXXXXXX",
"XXXXXXXXXX  XXXXXXXXXXXXX",
"XXXXXXXXXX              X",
"XX   XXXXX        Q     X",
"XX   XXXXXXXXXXXXX  XXXXX",
"XX    XXXXXXXXXXXX  XXXXX",
"XX    Q     XXXX        X",
"XXXX                    X",
"XXXXXXXXXXXXXXXXXXXXXXXXX"
]

# Add the level(s) to the levels list.
levels.append(level_1)

# Class instances.
pen = Pen()
pen.setup(level_1)
player = Player()
player.setup(level_1)
setup(level_1)

# Creation of quit button.
quitButton = tkinter.Button(frame, text='Quit', command=quitPlaying)
quitButton.pack()

screen.onkeypress(player.move_up, 'Up')
screen.onkeypress(player.move_down, 'Down')
screen.onkeypress(player.move_left, 'Left')
screen.onkeypress(player.move_right, 'Right')

screen.listen()

# Call main game loop.
screen.mainloop()

You seem to get very little out of embedding turtle in tkinter and this might have been cleaner left a standalone turtle program. And since your various setup*() methods/functions never got called, your posted code doesn't really do anything.



来源:https://stackoverflow.com/questions/56092732/get-coordinates-of-treasure-turtles-in-maze-game-that-uses-python-tkinter-an

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!