用250行代码编一个贪吃蛇游戏
"""贪吃蛇"""
import random
import time
import sys
from typing import NamedTuple
import pygame
pygame.init()
class Food(NamedTuple):
"""蛇的食物"""
x: int
y: int
def display(self):
"""将食物绘制在屏幕上"""
rect = pygame.Rect(0, 0, CELL_SIZE, CELL_SIZE)
rect.left, rect.top = \
self.x * CELL_SIZE, self.y * CELL_SIZE
pygame.draw.rect(screen, FOOD_COLOR, rect)
def new_food():
"""创建食物"""
food_ = Food(
random.randint(0, ROWS - 1),
random.randint(0, COLS - 1)
)
while any(food_.x == body.x and food_.y == body.y for body in snake.bodys):
food_ = Food(
random.randint(0, ROWS - 1),
random.randint(0, COLS - 1)
)
return food_
def game_over():
"""游戏结束"""
global game_running
time.sleep(.5)
game_running = False
class SnakeBody(NamedTuple):
"""蛇身子"""
x: int
y: int
class Snake:
"""蛇"""
def __init__(self):
"""初始化"""
self.direction = 'DOWN'
start_x = random.randint(10, ROWS - 11)
start_y = random.randint(10, COLS - 11)
self.bodys = [
SnakeBody(start_x, start_y),
SnakeBody(start_x, start_y - 1),
SnakeBody(start_x, start_y - 2)
]
self.prev_time = time.time()
@ property
def head(self):
"""蛇头"""
return self.bodys[0]
def update(self):
"""刷新"""
if ((now := time.time()) - self.prev_time) < .1: return
self.prev_time = now
match self.direction:
case 'UP':
tail = SnakeBody(
self.head.x,
self.head.y - 1
)
case 'DOWN':
tail = SnakeBody(
self.head.x,
self.head.y + 1
)
case 'LEFT':
tail = SnakeBody(
self.head.x - 1,
self.head.y
)
case _:
tail = SnakeBody(
self.head.x + 1,
self.head.y
)
self.bodys.insert(0, tail)
global food
if self.head == food:
score_board.add_points()
food = new_food()
else:
self.bodys.pop()
if any(
(
self.head.x == -1 and self.direction == 'LEFT',
self.head.y == -1 and self.direction == 'UP',
self.head.x == ROWS and self.direction == 'RIGHT',
self.head.y == COLS and self.direction == 'DOWN',
)
):
game_over()
for body in self.bodys[1:]:
if self.head == body:
game_over()
break
def display(self):
"""将蛇绘制在屏幕上"""
for body in self.bodys:
rect = pygame.Rect(0, 0, CELL_SIZE, CELL_SIZE)
rect.x, rect.y = \
body.x * CELL_SIZE, body.y * CELL_SIZE
pygame.draw.rect(screen, SNAKE_COLOR, rect)
class ScoreBoard:
"""计分板"""
def __init__(self):
"""初始化"""
self.score = 0
self.font = pygame.font.Font(FONT, 50)
def add_points(self):
"""加分"""
self.score += 1000
def display(self):
surface = self.font.render(
format(self.score, ',') + '分',
1,
(255, 255, 255)
)
rect = surface.get_rect()
rect.topright = screen_rect.topright
screen.blit(surface, rect)
def check_events():
"""检查退出和键盘事件"""
global game_running, snake, food, score_board
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.KEYDOWN:
if not game_running:
game_running = True
snake = Snake()
food = new_food()
score_board = ScoreBoard()
else:
if event.key == pygame.K_UP:
snake.direction = 'UP'
elif event.key == pygame.K_DOWN:
snake.direction = 'DOWN'
elif event.key == pygame.K_LEFT:
snake.direction = 'LEFT'
elif event.key == pygame.K_RIGHT:
snake.direction = 'RIGHT'
def display_grid():
"""绘制格子"""
for x in range(
CELL_SIZE,
WINDOW_WIDTH - CELL_SIZE + 1,
CELL_SIZE
):
pygame.draw.line(screen, LINE_COLOR, (x, 0), (x, WINDOW_HEIGHT))
for y in range(
CELL_SIZE,
WINDOW_HEIGHT - CELL_SIZE + 1,
CELL_SIZE
):
pygame.draw.line(screen, LINE_COLOR, (0, y), (WINDOW_WIDTH, y))
def display():
"""将东西绘制在窗口上"""
screen.fill(BG)
if not game_running:
screen.blit(title, title_rect)
else:
display_grid()
snake.display()
food.display()
score_board.display()
pygame.display.update()
BG = 0, 0, 0
LINE_COLOR = 50, 50, 50
FOOD_COLOR = 255, 0, 0
SNAKE_COLOR = 0, 255, 0
CELL_SIZE = 20
ROWS = 50
COLS = 45
WINDOW_WIDTH = CELL_SIZE * ROWS
WINDOW_HEIGHT = CELL_SIZE * COLS
FONT = r'C:\Windows\Fonts\simfang.ttf'
game_running = False
score = 0
snake = Snake()
food = new_food()
score_board = ScoreBoard()
screen = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))
screen_rect = screen.get_rect()
pygame.display.set_caption('贪吃蛇')
title_font = pygame.font.Font(FONT, 300)
title_content = '贪吃蛇'
title = title_font.render(title_content, True, (255, 255, 255))
title_rect = title.get_rect()
title_rect.center = screen_rect.center
if __name__ == '__main__':
while True:
check_events()
if game_running:
snake.update()
display()