I'm working on a Python Snake game using the turtle module. I have four files: main.py
, food.py
, scoreboard.py
, and snake.py
.
Here is my main.py
code:
from turtle import Screen
from snake import Snake
from food import Food
from scoreboard import Scoreboard
import time
screen = Screen()
screen.setup(600,600)
screen.title("Snake Game")
screen.bgcolor("black")
screen.tracer(0) # Turning the animation off
snake = Snake()
food = Food()
scoreboard = Scoreboard()
screen.listen()
screen.onkeypress(fun=snake.up,key="Up")
screen.onkeypress(fun=snake.down,key="Down")
screen.onkeypress(fun=snake.left,key="Left")
screen.onkeypress(fun=snake.right,key="Right")
is_game_on = True
score = 0
while is_game_on:
screen.update()
time.sleep(0.1)
snake.move()
# Detect collision with food
if snake.head.distance(food) < 15:
food.refresh()
scoreboard.score_update()
snake.extend()
# Detect collision with wall
if snake.head.xcor() > 280 or snake.head.xcor() < -280 or\
snake.head.ycor() > 280 or snake.head.ycor()<-280:
scoreboard.game_over()
is_game_on = False
screen.exitonclick()
Here is my food.py
code:
import random
from turtle import Turtle
class Food(Turtle):
def __init__(self) -> None:
super().__init__()
self.shape("circle")
self.penup()
self.shapesize(stretch_len=0.5,stretch_wid=0.5)
self.color("red")
self.speed("fastest")
self.refresh()
def refresh(self):
random_coordinates = ( random.randint(-280,280), random.randint(-280,280) )
self.goto(random_coordinates)
Here is my scoreboard.py
code:
from turtle import Turtle
ALIGNMENT = "center"
FONT_NAME = "Courier"
FONT_SIZE = 17
FONT_TYPE = "normal"
class Scoreboard(Turtle):
score = 0
def __init__(self):
super().__init__()
self.color("yellow")
self.hideturtle()
self.penup()
self.teleport(0,275)
self.write(arg="score = 0",move=False,align=ALIGNMENT,font=(FONT_NAME, FONT_SIZE, FONT_TYPE))
def score_update(self,):
self.score += 1
self.clear()
self.write(arg=f"score = {self.score}",move=False,align=ALIGNMENT,font=(FONT_NAME, FONT_SIZE, FONT_TYPE))
def game_over(self):
self.home()
self.write(arg=f"GAME OVER",move=False,align=ALIGNMENT,font=(FONT_NAME, FONT_SIZE, FONT_TYPE))
Here is my snake.py
code:
from turtle import Turtle, Screen
MOVE_DISTANCE = 20
UP = 90
DOWN = 270
LEFT = 180
RIGHT = 0
class Snake:
def __init__(self) -> None:
self.segments = []
self.create_snake()
self.head = self.segments[0]
def create_snake(self):
self.x_cor = 0
for i in range(3):
self.add_segment(self.x_cor)
self.x_cor -= 20
def add_segment(self,position):
segment = Turtle("square")
segment.color("white")
segment.penup()
segment.speed("slowest")
segment.teleport(x=position,y=0)
self.segments.append(segment)
def extend(self):
# print(type(self.segments[-1]))
self.add_segment((self.segments)[-1].pos())
def move(self):
for seq_num in range(len(self.segments) -1, 0 ,-1):
new_x = self.segments[seq_num - 1].xcor()
new_y = self.segments[seq_num - 1].ycor()
self.segments[seq_num].goto(new_x, new_y)
self.head.forward(MOVE_DISTANCE)
def up(self):
if self.head.heading() != DOWN:
self.head.setheading(UP)
def down(self):
if self.head.heading() != UP:
self.head.setheading(DOWN)
def left(self):
if self.head.heading() != RIGHT:
self.head.setheading(LEFT)
def right(self):
if self.head.heading() != LEFT:
self.head.setheading(RIGHT)
Whenever the snake eats food the programme stops and gives an error message. I think the problem with the add_segment
method.
Traceback (most recent call last):
File "/home/xenon_54/Snake_Game/main.py", line 29, in <module>
screen.update()
File "/usr/lib64/python3.12/turtle.py", line 1296, in update
t._drawturtle()
File "/usr/lib64/python3.12/turtle.py", line 3080, in _drawturtle
shape = self._polytrafo(self._getshapepoly(tshape))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib64/python3.12/turtle.py", line 3033, in _polytrafo
return [(p0+(e1*x+e0*y)/screen.xscale, p1+(-e0*x+e1*y)/screen.yscale)
~~^~~~~~~~~~~~~~~~~~~~~~~~~~
File "/usr/lib64/python3.12/turtle.py", line 248, in __add__
return Vec2D(self[0]+other[0], self[1]+other[1])
~~~~~^^^
TypeError: 'float' object is not subscriptable
I used goto
instead of teleport
Also in create_snake
function, the goto method expects a tuple (x, y) for positioning. Therefore, self.x_cor needed to be passed as a tuple (self.x_cor, 0). Here's the snake.py
code that worked for me:
from turtle import Turtle
MOVE_DISTANCE = 20
UP = 90
DOWN = 270
LEFT = 180
RIGHT = 0
class Snake:
def __init__(self) -> None:
self.segments = []
self.create_snake()
self.head = self.segments[0]
def create_snake(self):
self.x_cor = 0
for _ in range(3):
self.add_segment((self.x_cor, 0))
self.x_cor -= 20
def add_segment(self, position):
segment = Turtle("square")
segment.color("white")
segment.penup()
segment.speed("slowest")
segment.goto(position)
self.segments.append(segment)
def extend(self):
self.add_segment((self.segments)[-1].pos())
def move(self):
for seq_num in range(len(self.segments) - 1, 0, -1):
new_x = self.segments[seq_num - 1].xcor()
new_y = self.segments[seq_num - 1].ycor()
self.segments[seq_num].goto(new_x, new_y)
self.head.forward(MOVE_DISTANCE)
def up(self):
if self.head.heading() != DOWN:
self.head.setheading(UP)
def down(self):
if self.head.heading() != UP:
self.head.setheading(DOWN)
def left(self):
if self.head.heading() != RIGHT:
self.head.setheading(LEFT)
def right(self):
if self.head.heading() != LEFT:
self.head.setheading(RIGHT)