The actual game code I would put into a main
function which you can call within a if __name__ == "__main__":
if __name__ == "__main__":
guard to allow importing this from another script. With these changes, your code becomes:
The actual game code I would put into a main
function which you can call within a if __name__ == "__main__":
guard to allow importing this from another script. With these changes, your code becomes:
The actual game code I would put into a main
function which you can call within a if __name__ == "__main__":
guard to allow importing this from another script. With these changes, your code becomes:
Currently you, your full snake is just a list of body parts. While this is nice, you also have a few functions that just operate on a snake, so it would be nice to add these two things together and make snake a class as well. I would doedo something like this, which inherits from list
so the rest of your code stays basically unchanged, except that instead of draw_snake()
you now have snake.draw()
, etc:
import pygame
import time
import random
pygame.init()
# defines the width and height of the display
display_width = 800
display_height = 600
white = (255, 255, 255)
d_white = (250, 250, 250)
black = (0, 0, 0)
teal = (0, 128, 128)
blue_black = (50, 50, 50)
game_display = pygame.display.set_mode((display_width, display_height))
factor = 10
clock = pygame.time.Clock()
class SnakeBody:
def __init__(self, x, y):
self.x, self.y = x, y
def __repr__(self):
return "SnakeBody({self.x}, {self.y})".format(self=self)
class Snake(list):
def __init__(self, start_x, start_y, n):
list.__init__(self, [SnakeBody(start_x, start_y + i * factor)
for i in range(n)])
def move_head(self, dx, dy):
self[0].x += dx
self[0].y += dy
def update(self, score):
for i in range(len(self) - 1, 0, -1):
self[i].x = self[i - 1].x
self[i].y = self[i - 1].y
def check_death(self):
if not (1 <= self[0].x <= display_width and 1 <= self[0].y <= display_height):
return True
return any(body_part.x == self[0].x and body_part.y == self[0].y for body_part in self[1:])
def draw(self):
for body_part in self:
pygame.draw.rect(game_display, teal,
(body_part.x, body_part.y, factor, factor))
def main():
food_x = random.randrange(5, display_width - 5)
food_y = random.randrange(5, display_height - 5)
print(food_x, food_y)
score = 60
snake = Snake(20, 20, 16)
x = 0
y = 0
x_change = 0
y_change = 0
first_time = True
eat = True
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
if event.type == pygame.KEYDOWN:
first_time = False
if event.key == pygame.K_a:
if x_change != 10:
x_change = -10
y_change = 0
elif event.key == pygame.K_d:
if x_change != -10:
x_change = 10
y_change = 0
elif event.key == pygame.K_w:
if y_change != 10:
x_change = 0
y_change = -10
elif event.key == pygame.K_s:
if y_change != -10:
x_change = 0
y_change = 10
elif event.key == pygame.K_c:
x_change = 0
y_change = 0
if not first_time:
snake.update(score)
if score % 10 == 0 and eat:
snake.append(snake_body(
snake[len(snake) - 1].x, snake[len(snake) - 1].y))
print(len(snake))
eat = False
snake.move_head(x_change, y_change)
if snake[0].x < food_x + 10 and snake[0].x > food_x - 10 and snake[0].y < food_y + 10 and snake[0].y > food_y - 10:
score += 10
food_x = random.randrange(5, display_width - 5)
food_y = random.randrange(5, display_height - 5)
eat = True
if snake.check_death():
pygame.quit()
quit()
# update game display
game_display.fill(white)
pygame.draw.rect(game_display, black, (food_x, food_y, factor, factor))
snake.draw()
pygame.display.flip()
time.sleep(0.035)
clock.tick(60)
if __name__ == "__main__":
main()
<br>
Currently you full snake is just a list of body parts. While this is nice, you also have a few functions that just operate on a snake, so it would be nice to add these two things together and make snake a class as well. I would doe something like this, which inherits from list
so the rest of your code stays basically unchanged, except that instead of draw_snake()
you now have snake.draw()
, etc:
import pygame
import time
import random
pygame.init()
# defines the width and height of the display
display_width = 800
display_height = 600
white = (255, 255, 255)
d_white = (250, 250, 250)
black = (0, 0, 0)
teal = (0, 128, 128)
blue_black = (50, 50, 50)
game_display = pygame.display.set_mode((display_width, display_height))
factor = 10
clock = pygame.time.Clock()
class SnakeBody:
def __init__(self, x, y):
self.x, self.y = x, y
def __repr__(self):
return "SnakeBody({self.x}, {self.y})".format(self=self)
class Snake(list):
def __init__(self, start_x, start_y, n):
list.__init__(self, [SnakeBody(start_x, start_y + i * factor)
for i in range(n)])
def move_head(self, dx, dy):
self[0].x += dx
self[0].y += dy
def update(self, score):
for i in range(len(self) - 1, 0, -1):
self[i].x = self[i - 1].x
self[i].y = self[i - 1].y
def check_death(self):
if not (1 <= self[0].x <= display_width and 1 <= self[0].y <= display_height):
return True
return any(body_part.x == self[0].x and body_part.y == self[0].y for body_part in self[1:])
def draw(self):
for body_part in self:
pygame.draw.rect(game_display, teal,
(body_part.x, body_part.y, factor, factor))
def main():
food_x = random.randrange(5, display_width - 5)
food_y = random.randrange(5, display_height - 5)
print(food_x, food_y)
score = 60
snake = Snake(20, 20, 16)
x = 0
y = 0
x_change = 0
y_change = 0
first_time = True
eat = True
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
if event.type == pygame.KEYDOWN:
first_time = False
if event.key == pygame.K_a:
if x_change != 10:
x_change = -10
y_change = 0
elif event.key == pygame.K_d:
if x_change != -10:
x_change = 10
y_change = 0
elif event.key == pygame.K_w:
if y_change != 10:
x_change = 0
y_change = -10
elif event.key == pygame.K_s:
if y_change != -10:
x_change = 0
y_change = 10
elif event.key == pygame.K_c:
x_change = 0
y_change = 0
if not first_time:
snake.update(score)
if score % 10 == 0 and eat:
snake.append(snake_body(
snake[len(snake) - 1].x, snake[len(snake) - 1].y))
print(len(snake))
eat = False
snake.move_head(x_change, y_change)
if snake[0].x < food_x + 10 and snake[0].x > food_x - 10 and snake[0].y < food_y + 10 and snake[0].y > food_y - 10:
score += 10
food_x = random.randrange(5, display_width - 5)
food_y = random.randrange(5, display_height - 5)
eat = True
if snake.check_death():
pygame.quit()
quit()
# update game display
game_display.fill(white)
pygame.draw.rect(game_display, black, (food_x, food_y, factor, factor))
snake.draw()
pygame.display.flip()
time.sleep(0.035)
clock.tick(60)
if __name__ == "__main__":
main()
Currently, your full snake is just a list of body parts. While this is nice, you also have a few functions that just operate on a snake, so it would be nice to add these two things together and make snake a class as well. I would do something like this, which inherits from list
so the rest of your code stays basically unchanged, except that instead of draw_snake()
you now have snake.draw()
, etc:
import pygame
import time
import random
pygame.init()
# defines the width and height of the display
display_width = 800
display_height = 600
white = (255, 255, 255)
d_white = (250, 250, 250)
black = (0, 0, 0)
teal = (0, 128, 128)
blue_black = (50, 50, 50)
game_display = pygame.display.set_mode((display_width, display_height))
factor = 10
clock = pygame.time.Clock()
class SnakeBody:
def __init__(self, x, y):
self.x, self.y = x, y
def __repr__(self):
return "SnakeBody({self.x}, {self.y})".format(self=self)
class Snake(list):
def __init__(self, start_x, start_y, n):
list.__init__(self, [SnakeBody(start_x, start_y + i * factor)
for i in range(n)])
def move_head(self, dx, dy):
self[0].x += dx
self[0].y += dy
def update(self, score):
for i in range(len(self) - 1, 0, -1):
self[i].x = self[i - 1].x
self[i].y = self[i - 1].y
def check_death(self):
if not (1 <= self[0].x <= display_width and 1 <= self[0].y <= display_height):
return True
return any(body_part.x == self[0].x and body_part.y == self[0].y for body_part in self[1:])
def draw(self):
for body_part in self:
pygame.draw.rect(game_display, teal,
(body_part.x, body_part.y, factor, factor))
def main():
food_x = random.randrange(5, display_width - 5)
food_y = random.randrange(5, display_height - 5)
print(food_x, food_y)
score = 60
snake = Snake(20, 20, 16)
x = 0
y = 0
x_change = 0
y_change = 0
first_time = True
eat = True
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
if event.type == pygame.KEYDOWN:
first_time = False
if event.key == pygame.K_a:
if x_change != 10:
x_change = -10
y_change = 0
elif event.key == pygame.K_d:
if x_change != -10:
x_change = 10
y_change = 0
elif event.key == pygame.K_w:
if y_change != 10:
x_change = 0
y_change = -10
elif event.key == pygame.K_s:
if y_change != -10:
x_change = 0
y_change = 10
elif event.key == pygame.K_c:
x_change = 0
y_change = 0
if not first_time:
snake.update(score)
if score % 10 == 0 and eat:
snake.append(snake_body(
snake[len(snake) - 1].x, snake[len(snake) - 1].y))
print(len(snake))
eat = False
snake.move_head(x_change, y_change)
if snake[0].x < food_x + 10 and snake[0].x > food_x - 10 and snake[0].y < food_y + 10 and snake[0].y > food_y - 10:
score += 10
food_x = random.randrange(5, display_width - 5)
food_y = random.randrange(5, display_height - 5)
eat = True
if snake.check_death():
pygame.quit()
quit()
# update game display
game_display.fill(white)
pygame.draw.rect(game_display, black, (food_x, food_y, factor, factor))
snake.draw()
pygame.display.flip()
time.sleep(0.035)
clock.tick(60)
if __name__ == "__main__":
main()
<br>
Here are some changes I would make:
Your snake_body
class (which should be called SnakeBody
, according to PEP8), does not need to initialize its attributes before the initialization, so you can just have:
class SnakeBody:
def __init__(self, x, y):
self.x, self.y = x, y
def __repr__(self):
return "SnakeBody({self.x}, {self.y})".format(self=self)
I also gave it a __repr__
method so it prints nicer.
Currently you full snake is just a list of body parts. While this is nice, you also have a few functions that just operate on a snake, so it would be nice to add these two things together and make snake a class as well. I would doe something like this, which inherits from list
so the rest of your code stays basically unchanged, except that instead of draw_snake()
you now have snake.draw()
, etc:
class Snake(list):
def __init__(self, start_x, start_y, n):
list.__init__(self, [SnakeBody(start_x, start_y + i * factor)
for i in range(n)])
def move_head(self, dx, dy):
self[0].x += dx
self[0].y += dy
def update(self, score):
for i in range(len(self) - 1, 0, -1):
self[i].x = self[i - 1].x
self[i].y = self[i - 1].y
def check_death(self):
if not (1 <= self[0].x <= display_width and 1 <= self[0].y <= display_height):
return True
return any(body_part.x == self[0].x and body_part.y == self[0].y for body_part in self[1:])
def draw(self):
for body_part in self:
pygame.draw.rect(game_display, teal,
(body_part.x, body_part.y, factor, factor))
Note that I also simplified the check_death
function. It now returns True
if the snake needs to die. I used the fact that Python can do multiple comparisons, so a <= x <= b
is legal in Python.
The actual game code I would put into a main
function which you can call within a if __name__ == "__main__":
guard to allow importing this from another script. With these changes, your code becomes:
Final code:
import pygame
import time
import random
pygame.init()
# defines the width and height of the display
display_width = 800
display_height = 600
white = (255, 255, 255)
d_white = (250, 250, 250)
black = (0, 0, 0)
teal = (0, 128, 128)
blue_black = (50, 50, 50)
game_display = pygame.display.set_mode((display_width, display_height))
factor = 10
clock = pygame.time.Clock()
class SnakeBody:
def __init__(self, x, y):
self.x, self.y = x, y
def __repr__(self):
return "SnakeBody({self.x}, {self.y})".format(self=self)
class Snake(list):
def __init__(self, start_x, start_y, n):
list.__init__(self, [SnakeBody(start_x, start_y + i * factor)
for i in range(n)])
def move_head(self, dx, dy):
self[0].x += dx
self[0].y += dy
def update(self, score):
for i in range(len(self) - 1, 0, -1):
self[i].x = self[i - 1].x
self[i].y = self[i - 1].y
def check_death(self):
if not (1 <= self[0].x <= display_width and 1 <= self[0].y <= display_height):
return True
return any(body_part.x == self[0].x and body_part.y == self[0].y for body_part in self[1:])
def draw(self):
for body_part in self:
pygame.draw.rect(game_display, teal,
(body_part.x, body_part.y, factor, factor))
def main():
food_x = random.randrange(5, display_width - 5)
food_y = random.randrange(5, display_height - 5)
print(food_x, food_y)
score = 60
snake = Snake(20, 20, 16)
x = 0
y = 0
x_change = 0
y_change = 0
first_time = True
eat = True
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
if event.type == pygame.KEYDOWN:
first_time = False
if event.key == pygame.K_a:
if x_change != 10:
x_change = -10
y_change = 0
elif event.key == pygame.K_d:
if x_change != -10:
x_change = 10
y_change = 0
elif event.key == pygame.K_w:
if y_change != 10:
x_change = 0
y_change = -10
elif event.key == pygame.K_s:
if y_change != -10:
x_change = 0
y_change = 10
elif event.key == pygame.K_c:
x_change = 0
y_change = 0
if not first_time:
snake.update(score)
if score % 10 == 0 and eat:
snake.append(snake_body(
snake[len(snake) - 1].x, snake[len(snake) - 1].y))
print(len(snake))
eat = False
snake.move_head(x_change, y_change)
if snake[0].x < food_x + 10 and snake[0].x > food_x - 10 and snake[0].y < food_y + 10 and snake[0].y > food_y - 10:
score += 10
food_x = random.randrange(5, display_width - 5)
food_y = random.randrange(5, display_height - 5)
eat = True
if snake.check_death():
pygame.quit()
quit()
# update game display
game_display.fill(white)
pygame.draw.rect(game_display, black, (food_x, food_y, factor, factor))
snake.draw()
pygame.display.flip()
time.sleep(0.035)
clock.tick(60)
if __name__ == "__main__":
main()