话不多说,详细的思路都在思维导图与代码注释里面了,很详细, 使用模块有pygame,sys, os, random
安装pygame: pip install pygame
详细代码如下:
# -*- coding: utf-8 -*-
import pygame
from pygame.locals import *
from sys import exit
from os import environ
from random import randrange
class GreedySnakeGame:
def __init__(self):
pygame.init() # 初始化pygame库
environ['SDL_VIDEO_CENTERED'] = '1' # 设置窗口居中显示
size = width, height = 840, 580 # 定义窗口大小
self.window = pygame.display.set_mode(size) # 显示窗口(实例变量)
pygame.display.set_caption("贪吃蛇 V1") # 设置窗口标题
self.speed = pygame.time.Clock() # 定义变量方便控制游戏进行速度(实例变量)
self.game_speed = 2 # 定义游戏初始的详细速度(实例变量)
self.score = 0 # 定义游戏初始分数(实例变量)
self.difficulty = 0 # 定义游戏初始难度等级(实例变量)
self.black = pygame.Color(0, 0, 0) # 定义颜色变量:黑色(实例变量)
self.white = pygame.Color(255, 255, 255, 255) # 定义颜色变量:白色(实例变量)
self.red = pygame.Color(255, 0, 0) # 定义颜色变量:红色(实例变量)
self.grey = pygame.Color(150, 150, 150) # 定义颜色变量:灰色(实例变量)
self.blue = pygame.Color(0, 0, 255) # 定义颜色变量:蓝色(实例变量)
self.cyan_blue = pygame.Color(0, 128, 128) # 定义颜色变量:青色(实例变量)
self.green = pygame.Color(0, 100, 0) # 定义颜色变量:绿色(实例变量)
self.basic_font = pygame.font.SysFont('arial', 100) # 定义游戏界面使用的字体1(实例变量)
self.basic_font1 = pygame.font.SysFont('arial', 35) # 定义游戏界面使用的字体2(实例变量)
self.stop = False # 定义控制游戏暂停的变量(实例变量)
def games_start(self): # 游戏开始
snake_head = [60, 100] # 初始化贪吃蛇头部位置
snake_body = [[60, 100], [40, 100], [20, 100]] # 初始化贪吃蛇身体的长度(这里以20*20为一个小格子)
direction = "right" # 初始化贪吃蛇前进方向
food = [300, 300] # 初始化食物的位置
food_flag = 1 # 初始化食物的标记,1表示还没有被吃掉
'''进入游戏主循环'''
while True:
for event in pygame.event.get(): # 遍历所有的事件
if event.type == QUIT: # 如果单击关闭窗口,则退出
pygame.quit()
exit(0)
if event.type == KEYDOWN: # 表示按下键盘的事件(按下键盘时),pygame.KEYUP表示释放键盘时
if (event.key == K_UP or event.key == K_w) and direction != 'down': # 贪吃蛇原本的方向是向下,直接方向转为向上不合理,所以这里把DOWN排除, event.key表示获取的按键, K_UP表示向上箭头,可以查看中文文档
direction = 'up'
if (event.key == K_DOWN or event.key == K_s) and direction != 'up':
direction = 'down'
if (event.key == K_LEFT or event.key == K_a) and direction != 'right':
direction = 'left'
if (event.key == K_RIGHT or event.key == K_d) and direction != 'left':
direction = 'right'
if event.key == K_ESCAPE: # 按ESC键退出游戏
pygame.quit()
exit(0)
if event.key == K_SPACE: # 按空格键则暂停
self.stop = True
while self.stop:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
exit(0)
if event.type == KEYDOWN:
if event.key == K_SPACE: # 再次按下空格键结束暂停状态
self.stop = False
'''根据键盘输入的方向,改变贪吃蛇的头部,进行转弯操作,这里不可以用elif,会报错'''
if direction == 'left':
snake_head[0] -= 20
if direction == 'right':
snake_head[0] += 20
if direction == 'up':
snake_head[1] -= 20
if direction == 'down':
snake_head[1] += 20
snake_body.insert(0, list(snake_head)) # 将蛇的头部当前的位置加入到贪吃蛇身体的列表中,插在第一个位置
# 判断食物是否被吃掉
if snake_head[0] == food[0] and snake_head[1] == food[1]:
food_flag = 0
else:
snake_body.pop() # 如果没有吃掉食物, 贪吃蛇加入了一个蛇头,就是去掉一个蛇尾,这样贪吃蛇肉眼看起来是在前进
if food_flag == 0: # 如果食物被吃掉了,则生成新的食物,# 随机生成食物的坐标x, y
food_list = []
for weight_element in range(0, 620, 20):
for height_element in range(0, 560, 20):
food_list.append([weight_element, height_element])
for coordinate in snake_body:
if coordinate in food_list:
food_list.remove(coordinate) # 移除身体的坐标,保证生成的食物不会出现在蛇的身体上
food = food_list[randrange(0, len(food_list))]
food_flag = 1 # 生成食物之后需要重置食物标记
'''这里需要每一次循环都要重新填充窗口颜色,因为下面的各个填充区域填充颜色之后会改变窗口原本的颜色,如果不重新填充颜色,则贪吃蛇移动之后的地方颜色不会自动重置'''
self.window.fill(self.cyan_blue) # 填充窗口背景颜色
pygame.draw.rect(self.window, self.grey, Rect(640, 0, 200, 580)) # 绘制分数,游戏难度显示区域
self.draw_snake(snake_body) # 画出贪吃蛇
self.draw_food(food) # 画出食物
current_score = len(snake_body) - 3 # 获取当前得分,需要减去原来的长度
self.display_score(current_score) # 显示当前分数
if current_score - self.score == 5: # 这部分只要是控制游戏速度和游戏难度等级
self.score = current_score # 将当前分数复制给score,方便下次计算
self.game_speed += 0.1 # 游戏速度增加0.1,假设原来每秒移动3,则现在每秒移动3.1
self.game_speed = round(self.game_speed, 1) # 保证浮点数只保留一位小数
self.difficulty += 1
self.display_game_speed(self.game_speed) # 显示游戏详细速度
self.display_difficulty(self.difficulty) # 显示游戏难度等级
self.display_about() # 显示游戏说明
pygame.display.flip() # 刷新pygame显示层
self.speed.tick(self.game_speed) # 游戏帧数,控制游戏速度
'''判断游戏结束'''
# 碰触边界
if snake_head[0] < 0 or snake_head[0] > 620: # 方块宽度长宽都是20,横坐标为520的时候,就已经触碰边界了,超过520说明撞墙了
self.display_game_over()
if snake_head[1] < 0 or snake_head[1] > 560:
self.display_game_over()
# 碰触自己
for element in snake_body[1:]: # 第一个是头,不可能头咬头,所以先排除
if snake_head[0] == element[0] and snake_head[1] == element[1]: # 坐标相同说明咬到身体了
self.display_game_over()
def draw_snake(self, snake_body): # 画蛇的方法
for element in snake_body: # 遍历蛇的身体的坐标,依次打印出来
if element[0] < 640: # 限制横坐标必须小于640,不限制当蛇头撞墙时会穿过一个坐标长度,不合理
pygame.draw.rect(self.window, self.black, Rect(element[0], element[1], 20, 20)) # 20, 20表示的是矩形的宽和高
def draw_food(self, food): # 打印出食物的方法
pygame.draw.rect(self.window, self.red, Rect(food[0], food[1], 20, 20)) # 打印食物
def display_score(self, score): # 打印出当前得分的方法
score_title = self.basic_font1.render(" score:", True, self.green) # 绘制文本“分数”两个字
score_title_rect = score_title.get_rect() # 获取矩形区域
score_title_rect.midtop = (700, 30) # 设置文本位置
self.window.blit(score_title, score_title_rect) # 绑定设置到窗口
score_text = self.basic_font1.render('%s' % (score), True, self.red) # 绘制具体分数
score_text_rect = score_text.get_rect() # 获取矩形区域
score_text_rect.midtop = (760, 30) # 设置分数位置
self.window.blit(score_text, score_text_rect) # 绑定设置到窗口
def display_game_speed(self, game_speed): # 显示游戏速度的方法
detailed_speed_title = self.basic_font1.render("speed:", True, self.green)
detailed_speed_rect = detailed_speed_title.get_rect()
detailed_speed_rect.midtop = (700, 70)
self.window.blit(detailed_speed_title, detailed_speed_rect)
game_speed_text = self.basic_font1.render('%s' % (game_speed), True, self.red)
game_speed_rect = game_speed_text.get_rect()
game_speed_rect.midtop = (760, 70)
self.window.blit(game_speed_text, game_speed_rect)
def display_difficulty(self, difficulty): # 显示游戏难度级别的方法
difficulty_title = self.basic_font1.render("level:", True, self.green)
difficulty_title_rect = difficulty_title.get_rect()
difficulty_title_rect.midtop = (710, 110)
self.window.blit(difficulty_title, difficulty_title_rect)
difficulty_text = self.basic_font1.render('%s' % (difficulty), True, self.red)
difficulty_text_rect = difficulty_text.get_rect()
difficulty_text_rect.midtop = (760, 110)
self.window.blit(difficulty_text, difficulty_text_rect)
def display_about(self): # 显示游戏相关信息的方法
#rule_stop = self.basic_font1.render("stop: space", True, self.green)
#rule_stop_rect = rule_stop.get_rect()
#rule_stop_rect.midtop = (720, 200)
#self.window.blit(rule_stop, rule_stop_rect)
about = self.basic_font1.render("Author: WYP", True, self.green)
about_rect = about.get_rect()
about_rect.midtop = (730, 230)
self.window.blit(about, about_rect)
def display_game_over(self): # 游戏结束的处理方法
game_over_text = self.basic_font.render('Game Over!', True, self.grey)
game_over_rect = game_over_text.get_rect()
game_over_rect.midtop = (330, 230)
self.window.blit(game_over_text, game_over_rect)
tips1 = self.basic_font1.render('Tips1: Press Tab to restart', True, self.blue) # 提示1:Game Overy后按Tab键重新开始游戏
tips1_rect = tips1.get_rect()
tips1_rect.midtop = (320, 80)
self.window.blit(tips1, tips1_rect)
tips2 = self.basic_font1.render('Tips2: Click X or press Esc to exit', True, self.blue) # 提示2:
tips2_rect = tips2.get_rect()
tips2_rect.midtop = (320, 130)
self.window.blit(tips2, tips2_rect)
pygame.display.flip() # 刷新Pygame的显示层
while True:
for event in pygame.event.get(): # 遍历所有事件
if event.type == QUIT: # 点击X关闭窗口,退出游戏
pygame.quit()
exit(0)
if event.type == KEYDOWN:
if event.key == K_ESCAPE: # 按ESC键退出游戏
pygame.quit()
exit(0)
if event.key == K_TAB: # 按Tab键重新开始游戏
self.game_speed = 2 # 还原游戏的速度,不能为0,0是极速,一瞬间撞墙
self.difficulty = 0 # 还原游戏的难度等级
self.games_start()
if __name__ == '__main__':
GreedySnakeGame().games_start()
程序运行效果: