Back

Explore Courses Blog Tutorials Interview Questions
0 votes
4 views
in Python by (16.4k points)
closed by

So I've been dealing with a couple of games in Python (warships, spasm tac-toe and so forth) and the current week's venture is Snake. I have a fundamental set-up going; the snake can move and eats the food yet I haven't customized in impact discovery or going off the edge yet.The issue is reaction time. On the off chance that you run the code beneath, you'll see that the snake reacts to keypresses, yet not two or three - I'll call them outlines - after the press. I don't exactly see how the listen() strategy works; am I utilizing it appropriately? If not, how might I utilize it, and assuming this is the case, how might I fix the deferral? I think about Pygame, however a) I can't track down a simple to introduce 64-cycle rendition for python 3.4

import random

import turtle

import time

class Square:

    def __init__(self, x, y):

        self.x = x

        self.y = y

    def drawself(self, turtle):

        # draw a black box at its coordinates, leaving a small gap between cubes

        turtle.goto(self.x - 9, self.y - 9)

        turtle.begin_fill()

        for i in range(4):

            turtle.forward(18)

            turtle.left(90)

        turtle.end_fill()

class Food:

    def __init__(self, x, y):

        self.x = x

        self.y = y

        self.state = "ON"

    def changelocation(self):

        # I haven't programmed it to spawn outside the snake's body yet

        self.x = random.randint(0, 20)*20 - 200

        self.y = random.randint(0, 20)*20 - 200

    def drawself(self, turtle):

        # similar to the Square drawself, but blinks on and off

        if self.state == "ON":

            turtle.goto(self.x - 9, self.y - 9)

            turtle.begin_fill()

            for i in range(4):

                turtle.forward(18)

                turtle.left(90)

            turtle.end_fill()

    def changestate(self):

        # controls the blinking

        self.state = "OFF" if self.state == "ON" else "ON"

class Snake:

    def __init__(self):

        self.headposition = [20, 0] # keeps track of where it needs to go next

        self.body = [Square(-20, 0), Square(0, 0), Square(20, 0)] # body is a list of squares

        self.nextX = 1 # tells the snake which way it's going next

        self.nextY = 0

        self.crashed = False # I'll use this when I get around to collision detection

        self.nextposition = [self.headposition[0] + 20*self.nextX,

                             self.headposition[1] + 20*self.nextY]

        # prepares the next location to add to the snake

    def moveOneStep(self):

        if Square(self.nextposition[0], self.nextposition[1]) not in self.body:

            # attempt (unsuccessful) at collision detection

            self.body.append(Square(self.nextposition[0], self.nextposition[1]))

            # moves the snake head to the next spot, deleting the tail

            del self.body[0]

            self.headposition[0], self.headposition[1] = self.body[-1].x, self.body[-1].y

        # resets the head and nextposition

            self.nextposition = [self.headposition[0] + 20*self.nextX,

                                 self.headposition[1] + 20*self.nextY]

        else:

            self.crashed = True # more unsuccessful collision detection

    def moveup(self): # pretty obvious what these do

        self.nextX = 0

        self.nextY = 1

    def moveleft(self):

        self.nextX = -1

        self.nextY = 0

    def moveright(self):

        self.nextX = 1

        self.nextY = 0

    def movedown(self):

        self.nextX = 0

        self.nextY = -1

    def eatFood(self):

        # adds the next spot without deleting the tail, extending the snake by 1

        self.body.append(Square(self.nextposition[0], self.nextposition[1]))

        self.headposition[0], self.headposition[1] = self.body[-1].x, self.body[-1].y

        self.nextposition = [self.headposition[0] + 20*self.nextX,

                             self.headposition[1] + 20*self.nextY]

    def drawself(self, turtle): # draws the whole snake when called

        for segment in self.body:

            segment.drawself(turtle)

class Game:

    def __init__(self):

        # game object has a screen, a turtle, a basic snake and a food

        self.screen = turtle.Screen()

        self.artist = turtle.Turtle()

        self.artist.up()

        self.artist.hideturtle()

        self.snake = Snake()

        self.food = Food(100, 0)

        self.counter = 0 # this will be used later

        self.commandpending = False # as will this

    def nextFrame(self):

        while True: # now here's where it gets fiddly...

            game.screen.listen()

            game.screen.onkey(game.snakedown, "Down")

            game.screen.onkey(game.snakeup, "Up")

            game.screen.onkey(game.snakeleft, "Left")

            game.screen.onkey(game.snakeright, "Right")

            turtle.tracer(0) # follow it so far?

            self.artist.clear()

            if self.counter == 5:

            # only moves to next frame every 5 loops, this was an attempt to get rid of the turning delay

                if (self.snake.nextposition[0], self.snake.nextposition[1]) == (self.food.x, self.food.y):

                    self.snake.eatFood()

                    self.food.changelocation()

                else:

                    self.snake.moveOneStep()

                self.counter = 0

            else:

                self.counter += 1

            self.food.changestate() # makes the food flash

            self.food.drawself(self.artist) # show the food and snake

            self.snake.drawself(self.artist)

            turtle.update()

            self.commandpending = False

            time.sleep(0.05)

    def snakeup(self):

        print("going up") # put this in for debugging purposes

        if not self.commandpending:

        # should allow only one turn each frame; I don't think it's working

            self.snake.moveup()

            self.commandpending = True

    def snakedown(self):

        print("going down")

        if not self.commandpending:

            self.snake.movedown()

            self.commandpending = True

    def snakeleft(self):

        print("going left")

        if not self.commandpending:

            self.snake.moveleft()

            self.commandpending = True

    def snakeright(self):

        print("going right")

        if not self.commandpending:

            self.snake.moveright()

            self.commandpending = True

game = Game()

game.nextFrame()

print("game over!")

game.screen.mainloop()

closed

4 Answers

0 votes
by (25.7k points)
selected by
 
Best answer

import turtle

import time

delay = 0.1

# Set up the screen

window = turtle.Screen()

window.title("Snake Game")

window.bgcolor("black")

window.setup(width=600, height=600)

window.tracer(0)  # Turns off the screen updates

# Snake head

head = turtle.Turtle()

head.speed(0)

head.shape("square")

head.color("white")

head.penup()

head.goto(0, 0)

head.direction = "stop"

# Functions

def go_up():

    if head.direction != "down":

        head.direction = "up"

def go_down():

    if head.direction != "up":

        head.direction = "down"

def go_left():

    if head.direction != "right":

        head.direction = "left"

def go_right():

    if head.direction != "left":

        head.direction = "right"

def move():

    if head.direction == "up":

        y = head.ycor()

        head.sety(y + 20)

    if head.direction == "down":

        y = head.ycor()

        head.sety(y - 20)

    if head.direction == "left":

        x = head.xcor()

        head.setx(x - 20)

    if head.direction == "right":

        x = head.xcor()

        head.setx(x + 20)

# Keyboard bindings

window.listen()

window.onkeypress(go_up, "w")

window.onkeypress(go_down, "s")

window.onkeypress(go_left, "a")

window.onkeypress(go_right, "d")

# Main game loop

while True:

    window.update()

    # Check for collisions with the border

    if head.xcor() > 290 or head.xcor() < -290 or head.ycor() > 290 or head.ycor() < -290:

        time.sleep(1)

        head.goto(0, 0)

        head.direction = "stop"

    # Move the snake

    move()

    time.sleep(delay)

window.mainloop()

This code sets up the game window and initializes the Snake head. It also defines functions for each movement direction (up, down, left, and right) and a move() function to handle the snake's movement. The game loop continuously updates the screen, checks for collisions with the border, and moves the snake accordingly.
You can run this code to see the basic implementation of a Snake game using Turtle graphics. Feel free to modify and expand upon it to add additional features like food, score tracking, or obstacles.
0 votes
by (26.4k points)

You should utilize an ontimer() occasion to run your code perfectly with the occasion overseer. The following is my change of your code to do this alongside some other utilitarian and style changes

from turtle import Turtle, Screen

import random

import time

SIZE = 20

class Square:

    def __init__(self, x, y):

        self.x = x

        self.y = y

    def drawself(self, turtle):

        """ draw a black box at its coordinates, leaving a small gap between cubes """

        turtle.goto(self.x - SIZE // 2 - 1, self.y - SIZE // 2 - 1)

        turtle.begin_fill()

        for _ in range(4):

            turtle.forward(SIZE - SIZE // 10)

            turtle.left(90)

        turtle.end_fill()

class Food:

    def __init__(self, x, y):

        self.x = x

        self.y = y

        self.is_blinking = True

    def changelocation(self):

        # I haven't programmed it to spawn outside the snake's body yet

        self.x = random.randint(0, SIZE) * SIZE - 200

        self.y = random.randint(0, SIZE) * SIZE - 200

    def drawself(self, turtle):

        # similar to the Square drawself, but blinks on and off

        if self.is_blinking:

            turtle.goto(self.x - SIZE // 2 - 1, self.y - SIZE // 2 - 1)

            turtle.begin_fill()

            for _ in range(4):

                turtle.forward(SIZE - SIZE // 10)

                turtle.left(90)

            turtle.end_fill()

    def changestate(self):

        # controls the blinking

        self.is_blinking = not self.is_blinking

class Snake:

    def __init__(self):

        self.headposition = [SIZE, 0]  # keeps track of where it needs to go next

        self.body = [Square(-SIZE, 0), Square(0, 0), Square(SIZE, 0)]  # body is a list of squares

        self.nextX = 1  # tells the snake which way it's going next

        self.nextY = 0

        self.crashed = False  # I'll use this when I get around to collision detection

        self.nextposition = [self.headposition[0] + SIZE * self.nextX, self.headposition[1] + SIZE * self.nextY]

        # prepares the next location to add to the snake

    def moveOneStep(self):

        if Square(self.nextposition[0], self.nextposition[1]) not in self.body: 

            # attempt (unsuccessful) at collision detection

            self.body.append(Square(self.nextposition[0], self.nextposition[1])) 

            # moves the snake head to the next spot, deleting the tail

            del self.body[0]

            self.headposition[0], self.headposition[1] = self.body[-1].x, self.body[-1].y 

            # resets the head and nextposition

            self.nextposition = [self.headposition[0] + SIZE * self.nextX, self.headposition[1] + SIZE * self.nextY]

        else:

            self.crashed = True  # more unsuccessful collision detection

    def moveup(self):  # pretty obvious what these do

        self.nextX, self.nextY = 0, 1

    def moveleft(self):

        self.nextX, self.nextY = -1, 0

    def moveright(self):

        self.nextX, self.nextY = 1, 0

    def movedown(self):

        self.nextX, self.nextY = 0, -1

    def eatFood(self):

        # adds the next spot without deleting the tail, extending the snake by 1

        self.body.append(Square(self.nextposition[0], self.nextposition[1]))

        self.headposition[0], self.headposition[1] = self.body[-1].x, self.body[-1].y

        self.nextposition = [self.headposition[0] + SIZE * self.nextX, self.headposition[1] + SIZE * self.nextY]

    def drawself(self, turtle):  # draws the whole snake when called

        for segment in self.body:

            segment.drawself(turtle)

class Game:

    def __init__(self):

        # game object has a screen, a turtle, a basic snake and a food

        self.screen = Screen()

        self.artist = Turtle(visible=False)

        self.artist.up()

        self.artist.speed("slowest")

        self.snake = Snake()

        self.food = Food(100, 0)

        self.counter = 0  # this will be used later

        self.commandpending = False  # as will this

        self.screen.tracer(0)  # follow it so far?

        self.screen.listen()

        self.screen.onkey(self.snakedown, "Down")

        self.screen.onkey(self.snakeup, "Up")

        self.screen.onkey(self.snakeleft, "Left")

        self.screen.onkey(self.snakeright, "Right")

    def nextFrame(self):

        self.artist.clear()

        if (self.snake.nextposition[0], self.snake.nextposition[1]) == (self.food.x, self.food.y):

            self.snake.eatFood()

            self.food.changelocation()

        else:

            self.snake.moveOneStep()

        if self.counter == 10:

            self.food.changestate()  # makes the food flash slowly

            self.counter = 0

        else:

            self.counter += 1

        self.food.drawself(self.artist)  # show the food and snake

        self.snake.drawself(self.artist)

        self.screen.update()

        self.screen.ontimer(lambda: self.nextFrame(), 100)

    def snakeup(self):

        if not self.commandpending: 

            self.commandpending = True

            self.snake.moveup()

            self.commandpending = False

    def snakedown(self):

        if not self.commandpending:

            self.commandpending = True

            self.snake.movedown()

            self.commandpending = False

    def snakeleft(self):

        if not self.commandpending:

            self.commandpending = True

            self.snake.moveleft()

            self.commandpending = False

    def snakeright(self):

        if not self.commandpending:

            self.commandpending = True

            self.snake.moveright()

            self.commandpending = False

game = Game()

screen = Screen()

screen.ontimer(lambda: game.nextFrame(), 100)

screen.mainloop()

Want to become an expert in Python? Join the python course fast!

0 votes
by (15.4k points)

import turtle

import time

delay = 0.1

# Set up the screen

window = turtle.Screen()

window.title("Snake Game")

window.bgcolor("black")

window.setup(width=600, height=600)

window.tracer(0)

# Snake head

head = turtle.Turtle("square")

head.color("white")

head.penup()

# Functions

def move():

    head.forward(20)

    window.update()

    window.ontimer(move, delay)

# Keyboard bindings

window.listen()

window.onkey(lambda: head.setheading(90), "w")

window.onkey(lambda: head.setheading(270), "s")

window.onkey(lambda: head.setheading(180), "a")

window.onkey(lambda: head.setheading(0), "d")

# Main game loop

move()

window.mainloop()

This shortened version utilizes lambda functions to set the heading of the snake directly in the keyboard bindings, eliminating the need for separate functions for each movement direction. The move() function is simplified to move the snake forward, update the screen, and use ontimer() to call itself repeatedly with the given delay.

Note that this code does not handle collision detection, scoring, or other advanced features. It focuses on providing a basic structure for the Snake game using Turtle graphics. You can extend and enhance it according to your requirements.

0 votes
by (19k points)

import turtle

delay = 0.1

window = turtle.Screen()

window.setup(600, 600)

head = turtle.Turtle("square")

head.color("white")

head.penup()

def move():

    head.forward(20)

    window.ontimer(move, delay)

window.listen()

window.onkey(lambda: head.setheading(90), "w")

window.onkey(lambda: head.setheading(270), "s")

window.onkey(lambda: head.setheading(180), "a")

window.onkey(lambda: head.setheading(0), "d")

move()

window.mainloop()

In this condensed version, unnecessary comments and variable declarations have been removed to create a more concise representation of the Snake game code. The logic and functionality remain the same as the previous version.

Related questions

Browse Categories

...