I have been experimenting with Tkinter's canvas feature. I put turtle in the canvas and am trying to make a snake game. I tried to run the code but have some problems:
It doesn't print the score when you press close of escape to quit,
You can only take the pen up once, you can't put it back down or put it up again,
The turtle called player sometimes doesn't spawn on the part of the screen you can actually see,
The turtle called t doesn't add to the score as you touch the turtle called player or move the turtle called player.
There might be other problems but these are the ones I know.
Here is my code:
import tkinter as tk
import random
import turtle
import time
import sys
game = False
forward = False
left = False
right = False
backward = False
draw = True
score = 0
def spawn(e=None):
t.penup()
t.goto(0,0)
player=turtle.RawTurtle(app)
player.penup()
player.shapesize(0.5,0.5)
player.shape("square")
player.color("black")
xrand = random.randint(-100, 100)
yrand = random.randint(-100, 100)
player.goto(x=xrand,y=yrand)
if t.distance(player) <15:
x = random.randint(-100, -100)
y = random.randint(-100, -100)
player.goto(x,y)
score = score+1
def systemap(e=None):
app.place(x=100,y=-4)
button.place(x=660,y=470)
def f(e=None):
if game == False:
t.setheading(90)
t.forward(5)
elif game == True:
forward == True
while forward == True:
left == False
right == False
backward == False
t.forward(5)
if forward == False:
t.setheading(90)
t.forward(5)
def l(e=None):
if game == False:
t.setheading(180)
t.forward(5)
elif game == True:
left == True
while left == True:
forward == False
right == False
backward == False
t.forward(5)
if left == False:
t.setheading(180)
t.forward(5)
def r(e=None):
if game == False:
t.setheading(0)
t.forward(5)
elif game == True:
right == True
while right == True:
forward == False
left == False
backward == False
t.forward(5)
if right == False:
t.setheading(0)
t.forward(5)
def b(e=None):
if game == False:
t.setheading(270)
t.forward(5)
elif game == True:
backward == True
while backward == True:
forward == False
left == False
right == False
t.forward(5)
if backward == False:
t.setheading(270)
t.forward(5)
def quit(e=None):
if game == False:
time.sleep(1)
window.destroy()
sys.exit()
elif game == True:
time.sleep(2)
window.destroy()
print("Score: ",score)
sys.exit()
def pen(e=None):
if draw == True:
t.penup()
draw == False
if draw == False:
t.pendown()
draw == True
window = tk.Tk()
window.iconbitmap('py.ico')
window.title("Turtle Graphics")
window.geometry("750x500")
window.resizable(False, False)
button = tk.Button(window,
text=" Close ",
font="Calibri",
borderwidth=0,
background="White",
command=quit)
app = tk.Canvas(master=window, width=500, height=500, bg="white")
t=turtle.RawTurtle(app)
window.bind("<Up>", f)
window.bind("<Left>", l)
window.bind("<Right>", r)
window.bind("<Down>", b)
window.bind("<w>", f)
window.bind("<a>", l)
window.bind("<d>", r)
window.bind("<s>", b)
window.bind("<p>", pen)
window.bind("<Escape>", quit)
window.bind("<g>", spawn)
systemap()
window.mainloop()
So there are several correction that need to be made here. I think you have some misconceptions about a few things.
You need to define global
in your functions that contain variables that are in the global name space or need to be there. If you do not you run into errors like local variable 'score' referenced before assignment
when trying to update the variable.
The ==
is a comparison only. You are using it in places that need to be a single =
.
You define a function called quit
and this is a built in method. Please be careful not to overwrite build in methods.
You never see the score printed because game
is always False. Nothing in your code changes it to True.
while
and sleep()
should not be used in the same thread as tkinter. This will cause issue as both of those methods block the mainloop. One way to manage this is to use the after()
method or threading instead. In this case I think threading is overkill and after()
is probably the better choice here.
Lastly I cannot really completely fix you code as I am not sure where you need to add game = True
.
Here is your code cleaned up a bit. I have corrected most of what was listed but without some more details I cannot guess at what you are needing for the rest.
Let me know if you have any questions:
import tkinter as tk
import random, turtle
game = False
forward = False
left = False
right = False
backward = False
draw = True
score = 0
def spawn(_=None):
global score, forward, left, backward, player
t.penup()
t.goto(0, 0)
player = turtle.RawTurtle(app)
player.penup()
player.shapesize(0.5, 0.5)
player.shape("square")
player.color("black")
xrand = random.randint(-100, 100)
yrand = random.randint(-100, 100)
player.goto(x=xrand, y=yrand)
if t.distance(player) < 15:
x = random.randint(-100, -100)
y = random.randint(-100, -100)
player.goto(x, y)
score = score + 1
def systemap(_=None):
app.place(x=100, y=-4)
button.place(x=660, y=470)
def f(_=None):
global forward, left, right, backward
if not game:
t.setheading(90)
t.forward(5)
else:
forward = True
while forward:
left = False
right = False
backward = False
t.forward(5)
if not forward:
t.setheading(90)
t.forward(5)
def l(_=None):
global forward, left, right, backward
if not game:
t.setheading(180)
t.forward(5)
else:
left = True
while left:
forward = False
right = False
backward = False
t.forward(5)
if not left:
t.setheading(180)
t.forward(5)
def r(_=None):
global forward, left, right, backward
if not game:
t.setheading(0)
t.forward(5)
else:
right = True
while right:
forward = False
left = False
backward = False
t.forward(5)
if not right:
t.setheading(0)
t.forward(5)
def b(_=None):
global forward, left, right, backward
if not game:
t.setheading(270)
t.forward(5)
else:
backward = True
while backward:
forward = False
left = False
right = False
t.forward(5)
if not backward:
t.setheading(270)
t.forward(5)
def quit_func(_=None):
if not game:
window.destroy()
else:
window.destroy()
print("Score: ", score)
def pen(_=None):
global draw
if draw:
t.penup()
draw = False
else:
t.pendown()
draw = True
window = tk.Tk()
window.title("Turtle Graphics")
window.geometry("750x500")
window.resizable(False, False)
button = tk.Button(window, text="Close", font="Calibri", borderwidth=0, background="White", command=quit_func)
app = tk.Canvas(master=window, width=500, height=500, bg="white")
t = turtle.RawTurtle(app)
window.bind("<Up>", f)
window.bind("<Left>", l)
window.bind("<Right>", r)
window.bind("<Down>", b)
window.bind("<w>", f)
window.bind("<a>", l)
window.bind("<d>", r)
window.bind("<s>", b)
window.bind("<p>", pen)
window.bind("<Escape>", quit_func)
window.bind("<g>", spawn)
systemap()
window.mainloop()
The primary issue I see is that you want the turtle to move constantly with the user of the program only changing the direction. I don't believe you'll ever get that effect with an infinite loop like:
while right == True:
forward == False
left == False
backward == False
t.forward(5)
Which relies on some outside event to change the value of right
but not really pausing to let other events run. (Plus the incorrect use of ==
vs =
.)
Other problems include:
The player can only relocate once, always to the same spot due to a sign error:
x = random.randint(-100, -100)
y = random.randint(-100, -100)
Lack of necessary global
statements along with ==
vs =
misuse:
def pen(e=None):
if draw == True:
t.penup()
draw == False
if draw == False:
t.pendown()
draw == True
You never should have coded as much as you did without testing some of these basic functions. The more untested code you write, the harder it is to debug.
Below is my rework of your code, implementing constant motion of the turtle (snake). I also moved some turtle-related code out of the tkinter realm into turtle methods. I simplified some things for the example (eg only one set of motion keys, the arrows.) But I believe it's now a very basic but playable game:
import tkinter as tk
from turtle import TurtleScreen, RawTurtle
from random import randint
direction = None
score = 0
def spawn():
player = RawTurtle(screen)
player.hideturtle()
player.shape('square')
player.shapesize(0.5)
player.color('black')
player.penup()
x = randint(-100, 100)
y = randint(-100, 100)
player.goto(x, y)
player.showturtle()
players.append(player)
def check_collision():
global score
for player in players:
if turtle.distance(player) < 15:
x = randint(-100, 100)
y = randint(-100, 100)
player.goto(x, y)
score += 1
def f():
global direction
def move():
check_collision()
if direction == 'forward':
turtle.forward(5)
screen.ontimer(move, 100)
if direction != 'forward':
direction = 'forward'
turtle.setheading(90)
move()
def l():
global direction
def move():
check_collision()
if direction == 'left':
turtle.forward(5)
screen.ontimer(move, 100)
if direction != 'left':
direction = 'left'
turtle.setheading(180)
move()
def r():
global direction
def move():
check_collision()
if direction == 'right':
turtle.forward(5)
screen.ontimer(move, 100)
if direction != 'right':
direction = 'right'
turtle.setheading(0)
move()
def b():
global direction
def move():
check_collision()
if direction == 'backward':
turtle.forward(5)
screen.ontimer(move, 100)
if direction != 'backward':
direction = 'backward'
turtle.setheading(270)
move()
def pen():
if turtle.isdown():
turtle.penup()
else:
turtle.pendown()
def quit_game(e=None): # called from either turtle or tkinter
window.destroy()
print("Score:", score)
exit()
players = []
window = tk.Tk()
# window.iconbitmap('py.ico')
window.title("Turtle Graphics")
window.geometry("600x600")
window.resizable(False, False)
canvas = tk.Canvas(master=window, width=500, height=500)
canvas.pack()
tk.Button(window, width=17, text='Close', borderwidth=0, command=quit_game).pack()
screen = TurtleScreen(canvas)
turtle = RawTurtle(screen)
screen.onkey(f, 'Up')
screen.onkey(l, 'Left')
screen.onkey(r, 'Right')
screen.onkey(b, 'Down')
screen.onkey(pen, 'p')
screen.onkey(quit_game, 'Escape')
screen.onkey(spawn, 'g')
screen.listen()
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.