问题
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