#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from sys import exit#调用exit函数,用于终止python程序
from random import choice#调用choice函数,返回一个列表,元组或字符串的随机项
import pygame#调用pygame库
from pygame.locals import QUIT, KEYDOWN#调用quit(用于退出python),keydown函数(触发按下某键时的功能)
TITLE = '贪吃蛇--Transfer by 逗比小青年'
WIDTH = 660#宽度
HEIGHT = 500#长度
SNAKE_SIZE = 20#每一块蛇的大小
BOARD_COLOR = (0, 0, 100)#底板颜色
class Vector():
def __init__(self, x, y):
self._x = x
self._y = y
@property
def x(self):
return self._x
@property
def y(self):
return self._y
@x.setter
def x(self, value):
self._x = value
@y.setter
def y(self, value):
self._y = value
def __len__(self):#返回集合长度
return 2
def __getitem__(self, index):#getitem用于输出序列属性中的某个元素
if index == 0:
return self.x
if index == 1:
return self.y
raise IndexError#raise 关键字用于引发一个异常,即程序出现错误后,程序内部会显示"IndexError"
def copy(self):#复制对象子列
type_self = type(self)
return type_self(self.x, self.y)
def move(self, other):#运动函数
if isinstance(other, Vector):#isinstance() 函数用来判断一个对象是否是一个已知的类型
self.x += other.x
self.y += other.y
else:
self.x += other
self.y += other
return self
def __eq__(self, other):
if isinstance(other, Vector):
return self.x == other.x and self.y == other.y
return NotImplemented
def __ne__(self, other):
if isinstance(other, Vector):
return self.x != other.x or self.y != other.y
return NotImplemented
def __repr__(self):#repr() 函数将对象转化为供解释器读取的形式
type_self = type(self)
name = type_self.__name__
return '{}({!r}, {!r})'.format(name, self.x, self.y)
class Snake:#蛇
def __init__(self):
self.map = {(x, y): 0
for x in range(1,
int(WIDTH / SNAKE_SIZE) - 2)
for y in range(1,
int(HEIGHT / SNAKE_SIZE) - 2)}
self.body = [
Vector(5 * SNAKE_SIZE, 5 * SNAKE_SIZE),
Vector(6 * SNAKE_SIZE, 5 * SNAKE_SIZE)
]
self.head = self.body[-1].copy()
self.color = (0, 0, 0)
self.direction = {
'right': Vector(SNAKE_SIZE, 0),
'left': Vector(-SNAKE_SIZE, 0),
'up': Vector(0, -SNAKE_SIZE),
'down': Vector(0, SNAKE_SIZE)
}
self.move_direction = 'right'
self.speed = 4
self.score = 0
self.food = Vector(0, 0)
self.food_color = (255, 0, 0)
self.generate_food()
self.game_started = False
def generate_food(self):#食物生成
empty_pos = [
pos for pos in self.map.keys()
if Vector(pos[0] * SNAKE_SIZE, pos[1] *
SNAKE_SIZE) not in self.body
]
result = choice(empty_pos)
self.food.x = result[0] * 20
self.food.y = result[1] * 20
def move(self):#移动中的进食过程与死亡判断
self.head = self.body[-1].copy()
self.head.move(self.direction[self.move_direction])
if not self._islive(self.head):
return False
self.body.append(self.head)
if self.head == self.food:
self.score += 1
if self.score % 5 == 0:
self.speed += 2
self.generate_food()
else:
self.body.pop(0)
return True
def _islive(self, head):#死亡定义
return 0 < head.x < WIDTH - SNAKE_SIZE and 0 < head.y < HEIGHT - SNAKE_SIZE and head not in self.body
KEY_DIRECTION_DICT = {#操控键位设置
119: 'up', # W
115: 'down', # S
97: 'left', # A
100: 'right', # D
273: 'up', # UP
274: 'down', # DOWN
276: 'left', # LEFT
275: 'right', # RIGHT
}
def press(events, snake):#按压反馈
for event in events:
if event.type == QUIT:
exit()
if event.type == KEYDOWN:
if event.key == 13:
snake.game_started = True
if snake.game_started and event.key in KEY_DIRECTION_DICT:
return direction_check(snake.move_direction,
KEY_DIRECTION_DICT[event.key])
def draw_score(screen, score, position):#实时分数显示
tips_font = pygame.font.SysFont('arial', 20)
screen.blit(
tips_font.render('Score: {}'.format(score), True, (0, 0, 205),
(255, 255, 255)), position)
def game_continue(screen, snake):
init_board(screen)
draw_score(screen, snake.score, (500, 0))
for seg in snake.body:
pygame.draw.rect(screen, snake.color, [seg[0], seg[1], 20, 20], 0)
pygame.draw.rect(screen, snake.food_color,
[snake.food[0], snake.food[1], 20, 20], 0)
def game_over(screen, fonts, score):
screen.blit(fonts['game_over'], (250, 100))
draw_score(screen, score, (290, 200))
screen.blit(fonts['start'], (220, 310))
snake = Snake()
return snake
def direction_check(move_direction, change_direction):#键位感知
directions = [['up', 'down'], ['left', 'right']]
if move_direction in directions[0] and change_direction in directions[1]:
return change_direction
elif move_direction in directions[1] and change_direction in directions[0]:
return change_direction
return move_direction
def init(fonts):#游戏界面文字布置
fps_clock = pygame.time.Clock()
pygame.display.set_caption(TITLE)
screen = pygame.display.set_mode((WIDTH, HEIGHT), 0, 32)
screen.fill((255, 255, 255))
screen.blit(fonts['welcome'], (177, 100))
screen.blit(fonts['start'], (195, 310))
return fps_clock, screen
def init_board(screen):#边框定制
board_width = int(WIDTH / SNAKE_SIZE)
board_height = int(HEIGHT / SNAKE_SIZE)
color = BOARD_COLOR
width = 0
for i in range(board_width):
pos = i * SNAKE_SIZE, 0, SNAKE_SIZE, SNAKE_SIZE
pygame.draw.rect(screen, color, pos, width)
pos = i * SNAKE_SIZE, (board_height -
1) * SNAKE_SIZE, SNAKE_SIZE, SNAKE_SIZE
pygame.draw.rect(screen, color, pos, width)
# 上下边框占用了 Y: 0 26*20
for i in range(board_height - 1):
pos = 0, SNAKE_SIZE + i * SNAKE_SIZE, SNAKE_SIZE, SNAKE_SIZE
pygame.draw.rect(screen, color, pos, width)
pos = (
board_width - 1
) * SNAKE_SIZE, SNAKE_SIZE + i * SNAKE_SIZE, SNAKE_SIZE, SNAKE_SIZE
pygame.draw.rect(screen, color, pos, width)
def font_setting():#游戏初始,游戏结束,游戏胜利界面文字布置
title_font = pygame.font.SysFont('arial', 32)
welcome_words = title_font.render('Welcome to revision Snake', True, (0, 0, 0),
(255, 255, 255))
tips_font = pygame.font.SysFont('arial', 24)
start_game_words = tips_font.render('Press Enter to Start Game', True,
(0, 0, 0), (255, 255, 255))
gameover_words = title_font.render('GAME OVER', True, (205, 92, 92),
(255, 255, 255))
win_words = title_font.render('The snake is long enough and you win!',
True, (0, 0, 205), (255, 255, 255))
return {
'welcome': welcome_words,
'start': start_game_words,
'game_over': gameover_words,
'win': win_words
}
def main():
pygame.init()
fonts = font_setting()
fps_clock, screen = init(fonts)
snake = Snake()
direction = snake.move_direction
while True:
events = pygame.event.get()
new_direction = press(events, snake)
if snake.game_started:
if new_direction:
snake.move_direction = new_direction
screen.fill((255, 255, 255))
if not snake.move():
snake = game_over(screen, fonts, snake.score)
direction = snake.move_direction
else:
game_continue(screen, snake)
pygame.display.update()
fps_clock.tick(snake.speed)
if __name__ == '__main__':
main()