Кодирование классической игры “Змейка” с графикой Python Turtle

Графика Python Turtle потрясающая! Его можно использовать для изучения и обучения программированию на Python и информатике от начального до продвинутого уровня. В моем блоге есть [сообщение] [1] о демонстрациях Turtle Graphics, которые поставляются с IDLE (среда разработки, поставляемая с Python).
Щелкните окно Turtle, чтобы включить управление с клавиатуры с помощью клавиш со стрелками.
Объяснение игровой программы Python Snake
Представление Змеи
Представляем нашу змейку в виде списка пар координат:
snake = [[0, 0], [20, 0], [40, 0]]
Использование sn
для обозначения n-го сегмента:
[s1, s2, s3]
Как движется змея?
Есть несколько подходов к программированию классической игры-змейки на Python (или других языках, если на то пошло). Основная задача – как заставить змею двигаться.
Вот два способа осмыслить, что по сути является одним и тем же:
Отрежьте последний сегмент и добавляйте его к передней части змеи каждый раз, когда змея «двигается».
Создайте копию головы, добавьте ее к передней части змеи, а затем отрежьте последний сегмент.
Создание нового элемента списка для новой позиции головы
new_head = snake[-1].copy() # snake[-1] means the rightmost item. Must be copied or original would be modified by next step.
То есть, new_head = s3
или new_head = [40, 0]
- Увеличиваем
x
координатуnew_head
, присваивая к нему[60, 0]
. - Добавляем новую голову змейке:
snake.append(new_head)
snake = [[0, 0], [20, 0], [40, 0], [60, 0]] now
или snake = [s1, s2, s3, H]
- Наконец, удалите крайний левый элемент (
s1
, или[0, 0]
), используяsnake.pop(0)
.
Итог: змея переместилась на одну позицию вперед!
Перемещение змеи с графикой Python Turtle
Основное движение змеи можно реализовать в простой программе, как показано здесь:
import turtle
def move_snake():
pen.clearstamps()
new_head = snake[-1].copy()
new_head[0] += 20
snake.append(new_head)
snake.pop(0)
for segment in snake:
pen.goto(segment[0], segment[1])
pen.stamp()
screen.update()
turtle.ontimer(move_snake, 200)
snake = [[0, 0], [20, 0], [40, 0]]
screen = turtle.Screen()
screen.tracer(0)
pen = turtle.Turtle("square")
pen.penup()
for segment in snake:
pen.goto(segment[0], segment[1])
pen.stamp()
move_snake()
turtle.done()
Листинг кода игры Python Classic Snake
Код нашей игры «Змейка» приведен ниже. В зависимости от вашего уровня опыта вы сможете понять, как именно это работает. Но каким бы ни был ваш уровень, вы должны экспериментировать с кодом. Например, вы можете изменить некоторые цвета, скорость змеи, элементы управления и т.д.
Удачного кодирования!
""" A simple snake game using Turtle Graphics. """
import turtle
import random
WIDTH = 500
HEIGHT = 500
FOOD_SIZE = 10
DELAY = 100 # milliseconds
offsets = {
"up": (0, 20),
"down": (0, -20),
"left": (-20, 0),
"right": (20, 0)
}
def reset():
global snake, snake_direction, food_pos, pen
snake = [[0, 0], [0, 20], [0, 40], [0, 60], [0, 80]]
snake_direction = "up"
food_pos = get_random_food_pos()
food.goto(food_pos)
# screen.update() Only needed if we are fussed about drawing food before next call to `draw_snake()`.
move_snake()
def move_snake():
global snake_direction
# Next position for head of snake.
new_head = snake[-1].copy()
new_head[0] = snake[-1][0] + offsets[snake_direction][0]
new_head[1] = snake[-1][1] + offsets[snake_direction][1]
# Check self-collision
if new_head in snake[:-1]: # Or collision with walls?
reset()
else:
# No self-collision so we can continue moving the snake.
snake.append(new_head)
# Check food collision
if not food_collision():
snake.pop(0) # Keep the snake the same length unless fed.
# Allow screen wrapping
if snake[-1][0] > WIDTH / 2:
snake[-1][0] -= WIDTH
elif snake[-1][0] < - WIDTH / 2:
snake[-1][0] += WIDTH
elif snake[-1][1] > HEIGHT / 2:
snake[-1][1] -= HEIGHT
elif snake[-1][1] < -HEIGHT / 2:
snake[-1][1] += HEIGHT
# Clear previous snake stamps
pen.clearstamps()
# Draw snake
for segment in snake:
pen.goto(segment[0], segment[1])
pen.stamp()
# Refresh screen
screen.update()
# Rinse and repeat
turtle.ontimer(move_snake, DELAY)
def food_collision():
global food_pos
if get_distance(snake[-1], food_pos) < 20:
food_pos = get_random_food_pos()
food.goto(food_pos)
return True
return False
def get_random_food_pos():
x = random.randint(- WIDTH / 2 + FOOD_SIZE, WIDTH / 2 - FOOD_SIZE)
y = random.randint(- HEIGHT / 2 + FOOD_SIZE, HEIGHT / 2 - FOOD_SIZE)
return (x, y)
def get_distance(pos1, pos2):
x1, y1 = pos1
x2, y2 = pos2
distance = ((y2 - y1) ** 2 + (x2 - x1) ** 2) ** 0.5
return distance
def go_up():
global snake_direction
if snake_direction != "down":
snake_direction = "up"
def go_right():
global snake_direction
if snake_direction != "left":
snake_direction = "right"
def go_down():
global snake_direction
if snake_direction != "up":
snake_direction = "down"
def go_left():
global snake_direction
if snake_direction != "right":
snake_direction = "left"
# Screen
screen = turtle.Screen()
screen.setup(WIDTH, HEIGHT)
screen.title("Snake")
screen.bgcolor("green")
screen.setup(500, 500)
screen.tracer(0)
# Pen
pen = turtle.Turtle("square")
pen.penup()
# Food
food = turtle.Turtle()
food.shape("circle")
food.color("red")
food.shapesize(FOOD_SIZE / 20) # Default size of turtle "square" shape is 20.
food.penup()
# Event handlers
screen.listen()
screen.onkey(go_up, "Up")
screen.onkey(go_right, "Right")
screen.onkey(go_down, "Down")
screen.onkey(go_left, "Left")
# Let's go
reset()
turtle.done()
For info on using the super-handy `stamp()` function of Python Turtle Graphics, check out [my video on Youtube][3]
### Python Classic Snake Game Code Listing
The listing for our Snake Game is below. Depending on your level of experiece, you may be able to understand exactly how it works or maybe just some of it. That's all fine.
Whatever your level, you should experiment with the code, play with it. For example you could change some colours, or the speed of the snake, or the controls etc.
For more experienced programmers, why not improve upon the basic idea by adding scoring and other features?
""" A simple snake game using Turtle Graphics. """
import turtle
import random
WIDTH = 500
HEIGHT = 500
FOOD_SIZE = 10
DELAY = 100 # milliseconds
offsets = {
"up": (0, 20),
"down": (0, -20),
"left": (-20, 0),
"right": (20, 0)
}
def reset():
global snake, snake_direction, food_pos, pen
snake = [[0, 0], [0, 20], [0, 40], [0, 50], [0, 60]]
snake_direction = "up"
food_pos = get_random_food_pos()
food.goto(food_pos)
# screen.update() Only needed if we are fussed about drawing food before next call to `draw_snake()`.
move_snake()
def move_snake():
global snake_direction
# Next position for head of snake.
new_head = snake[-1].copy()
new_head[0] = snake[-1][0] + offsets[snake_direction][0]
new_head[1] = snake[-1][1] + offsets[snake_direction][1]
# Check self-collision
if new_head in snake[:-1]: # Or collision with walls?
reset()
else:
# No self-collision so we can continue moving the snake.
snake.append(new_head)
# Check food collision
if not food_collision():
snake.pop(0) # Keep the snake the same length unless fed.
# Allow screen wrapping
if snake[-1][0] > WIDTH / 2:
snake[-1][0] -= WIDTH
elif snake[-1][0] < - WIDTH / 2:
snake[-1][0] += WIDTH
elif snake[-1][1] > HEIGHT / 2:
snake[-1][1] -= HEIGHT
elif snake[-1][1] < -HEIGHT / 2:
snake[-1][1] += HEIGHT
# Clear previous snake stamps
pen.clearstamps()
# Draw snake
for segment in snake:
pen.goto(segment[0], segment[1])
pen.stamp()
# Refresh screen
screen.update()
# Rinse and repeat
turtle.ontimer(move_snake, DELAY)
def food_collision():
global food_pos
if get_distance(snake[-1], food_pos) < 20:
food_pos = get_random_food_pos()
food.goto(food_pos)
return True
return False
def get_random_food_pos():
x = random.randint(- WIDTH / 2 + FOOD_SIZE, WIDTH / 2 - FOOD_SIZE)
y = random.randint(- HEIGHT / 2 + FOOD_SIZE, HEIGHT / 2 - FOOD_SIZE)
return (x, y)
def get_distance(pos1, pos2):
x1, y1 = pos1
x2, y2 = pos2
distance = ((y2 - y1) ** 2 + (x2 - x1) ** 2) ** 0.5
return distance
def go_up():
global snake_direction
if snake_direction != "down":
snake_direction = "up"
def go_right():
global snake_direction
if snake_direction != "left":
snake_direction = "right"
def go_down():
global snake_direction
if snake_direction != "up":
snake_direction = "down"
def go_left():
global snake_direction
if snake_direction != "right":
snake_direction = "left"
# Screen
screen = turtle.Screen()
screen.setup(WIDTH, HEIGHT)
screen.title("Snake")
screen.bgcolor("green")
screen.setup(500, 500)
screen.tracer(0)
# Pen
pen = turtle.Turtle("square")
pen.penup()
# Food
food = turtle.Turtle()
food.shape("circle")
food.color("red")
food.shapesize(FOOD_SIZE / 20) # Default size of turtle "square" shape is 20.
food.penup()
# Event handlers
screen.listen()
screen.onkey(go_up, "Up")
screen.onkey(go_right, "Right")
screen.onkey(go_down, "Down")
screen.onkey(go_left, "Left")
# Let's go
reset()
turtle.done()
*This article is based on a [post][5] on the [Compucademy blog][4]*
Happy coding!
*Robin Andrews*
[1]: http://compucademy.net/python-turtle-graphics-demos/
[2]: https://repl.it/@Compucademy/Snake-Game
[3]: https://www.youtube.com/watch?v=j9Nu08Jtrmw
[5]: https://compucademy.net/classic-snake-game-with-python-turtle-graphics/
[4]: https://compucademy.net/blog/