简体   繁体   中英

Tkinter & Turtle Snake Game

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:

  1. It doesn't print the score when you press close of escape to quit,

  2. You can only take the pen up once, you can't put it back down or put it up again,

  3. The turtle called player sometimes doesn't spawn on the part of the screen you can actually see,

  4. 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.

  1. 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.

  2. The == is a comparison only. You are using it in places that need to be a single = .

  3. You define a function called quit and this is a built in method. Please be careful not to overwrite build in methods.

  4. You never see the score printed because game is always False. Nothing in your code changes it to True.

  5. 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.

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