Making the well-known Snake game
- 라임 샹큼
- Mar 13
- 4 min read
Everyone has atleast had one instance in which they downloaded snake.io on their phone and had a few goes at it.
I wanted to replicate it in python with the turtle module and its gui functions.
This projected required extensive knowledge on OOP classes,methods and attributes. However, through this project, I was able to grasp OOP better, not perfectly, but enough to be a little comfortable with the topic.
screen = Screen()
screen.setup(width = 600, height = 600)
screen.bgcolor('black')
screen.title('My snake game')
screen.tracer(0)
The code starts with setting the screen class from the turtle file. There is something new introduced here: screen tracer. By adding screen.tracer(0), it stops tracking animations of turtles until it is called upon once again.
snake = Snake()
food = Food()
score = Score()
I made three classes called such as above.
Snake() is for animations and movements associated with the actual snake. Food() is to track the placement and consumption of food by the snake. Score() is for tracking the scores after every instance in which the snake consumes the food.
from turtle import Turtle, Screen
import time
STARTINGPOSITION = [(0,0),(-20,0),(-40,0)]
DISTANCE = 20
class Snake:
def init(self):
self.segments = []
self.create_snake()
self.head = self.segments[0]
def create_snake(self):
for position in STARTINGPOSITION:
self.add_segment(position)
def add_segment(self,position):
snake = Turtle(shape='square')
snake.color('white')
snake.penup()
snake.goto(position)
self.segments.append(snake)
def extend(self):
#add new segment
self.add_segment(self.segments[-1].position())
def move_snake(self):
for seg_num in range(len(self.segments) - 1, 0, -1):
new_x = self.segments[seg_num - 1].xcor()
new_y = self.segments[seg_num - 1].ycor()
self.segments[seg_num].goto(new_x, new_y)
self.segments[0].forward(DISTANCE)
def up(self):
if self.head.heading() != 270:
self.segments[0].setheading(90)
def down(self):
if self.head.heading() != 90:
self.segments[0].setheading(270)
def right(self):
if self.head.heading() != 180:
self.segments[0].setheading(0)
def left(self):
if self.head.heading() != 0:
self.segments[0].setheading(180)
First off I had to get the main values out of the way with attributes(init).
For making the snake itself, the add_segment method is important. In the case of making the initial snake, I looped the for loop 3 times to create a three segment snake. But I had to make sure the snake grew after consumption. That is where extend comes in. The extend method adds a segment to the previous position of the snake's last segment.
The snake moves so that it follows the last segment's placement, the head being the only thing that moves essentially. The range has a function that lets you place the first number in a series and the last number in a series and write the amount the series decreases or increases. Range(2, 0, -1) indicates the series 2,1,0. This ensures that the series starts and ends and increases, decreases at the exact amount intended.
By getting the x and y coordinates, I made it so that the next segments were moved to that position.
I also made methods that adjusted the head of the snake so that it moved in that direction.
from turtle import Turtle
import random
class Food(Turtle):
def init(self):
super().__init__()
self.shape('circle')
self.penup()
self.shapesize(stretch_wid=0.5,stretch_len=0.5)
self.color('red')
self.speed('fastest')
self.refresh()
def refresh(self):
random_x = random.randint(-270, 270)
random_y = random.randint(-270, 270)
self.goto(random_x, random_y)
The Food class was written using class inheritance. It inherited the functions of the Turtle class and I simply added more functions to the new class.
This allows you to not assign the Turtle class to a variable in order to use it. You can just use self to refer to the turtle.
The thing about classes is that you don't need to have mentioned it beforehand for it to work like making functions works. You can see I've made a refresh method but used it before it was fully defined.
The refresh method allows for the food, after consumed, to reappear at a different place on the map. The created new coordinates are then put in to set the location.
from snake import Snake
from turtle import Screen
from food import Food
from score import Score
import time
screen = Screen()
screen.setup(width = 600, height = 600)
screen.bgcolor('black')
screen.title('My snake game')
screen.tracer(0)
snake = Snake()
food = Food()
score = Score()
screen.listen()
screen.onkey(snake.up,'Up')
screen.onkey(snake.down,'Down')
screen.onkey(snake.left,'Left')
screen.onkey(snake.right,'Right')
game_is_on = True
while game_is_on:
screen.update()
time.sleep(0.1)
snake.move_snake()
#detect collision with food, use distance method
if snake.head.distance(food) < 20:
food.refresh()
snake.extend()
score.increase_score()
#detect collision with wall
if snake.head.xcor() > 290 or snake.head.xcor() < -290 or snake.head.ycor() > 290 or snake.head.ycor() < -290:
score.game_over()
game_is_on = False
#detect collision with tail
#head collides with any segment in tail
for segment in snake.segments[1:]:
if snake.head.distance(segment) < 10:
game_is_on = False
score.game_over()
screen.exitonclick()
This is the final code.
Comments