python
复制代码
import random
import pygame, sys,time
# pygame.init()
# 全局变量
SCREEN_WIDTH = 640 # 屏幕宽度
SCREEN_HEIGHT = 480 # 屏幕高度
BLOCK_SIZE = 20 # 方格的宽、高长度
COLOR_GRAY = (150, 150, 150) # 灰色
COLOR_GREEN = (0, 150, 0) # 绿色
COLOR_WHITE = (255, 255, 255) # 白色
COLOR_RED = (255, 0, 0) # 红色
# 控制方向
DIRECTION_MOVE = {
pygame.K_DOWN: (0, 1), # down
pygame.K_RIGHT: (1, 0), # right
pygame.K_UP: (0, -1), # up
pygame.K_LEFT: (-1, 0) # left
}
# 头部图标旋转方向
DIRECTION_HEAD_ANGLE = {
pygame.K_DOWN: 0,
pygame.K_RIGHT: 90,
pygame.K_UP: 180,
pygame.K_LEFT: 270
}
# 封装蛇初始位置
class Snake():
def __init__(self):
self.direction = pygame.K_DOWN # 初始方向
self.score = 0
self.icon_direction = DIRECTION_HEAD_ANGLE[pygame.K_DOWN]
print(self.icon_direction)
print(DIRECTION_HEAD_ANGLE)
self.snake_body = [ # 蛇的位置 self.snake_body.insert(0, new_node) 在第一位新增 新增完蛇头改变到新增的位置 原本第二位改变到蛇头的位置
pygame.Rect(3 * BLOCK_SIZE, 3 * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE),
pygame.Rect(2 * BLOCK_SIZE, 3 * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE),
pygame.Rect(1 * BLOCK_SIZE, 3 * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE)
]
self.sanke_img = pygame.image.load("res/head-red.png") # 加载蛇头图片
self.sanke_direction = pygame.transform.rotate(self.sanke_img,self.icon_direction) # 旋转蛇头
self.snake_head = pygame.transform.scale(self.sanke_direction,(BLOCK_SIZE,BLOCK_SIZE)) # 设置蛇头大小
def draw(self,screen):
for x in self.snake_body[1:]: # 遍历初始位置 给窗口画图 跳过第一个给蛇头留位置
pygame.draw.rect(screen,COLOR_WHITE,x,border_radius=5) # 给窗口画图 (窗口 , 颜色 ,(x左边距离,y上边距离 ,宽,高),边框圆角 )
snake_pos = self.snake_body[0] # 保存初始化第一个位置
# print(snake_pos)
screen.blit(self.snake_head,(snake_pos.x,snake_pos.y)) # 给窗口渲染蛇头图片 坐标是初始化第一个位置 <rect(60, 60, 20, 20)> snake_pos.x第一个 60 snake_pos.y第二个 60
def move(self):
# pygame.Rect.copy() --- 拷贝Rect对象
# pygame.Rect.move() --- 移动Rect对象
# pygame.Rect.move_ip() --- 原地移动Rect对象
# pygame.Rect.inflate() --- 放大和缩小Rect对象的尺寸
# pygame.Rect.inflate_ip() --- 原地放大和缩小Rect对象的尺寸
# pygame.Rect.clamp() --- 将一个Rect对象移动到另一个Rect对象的中心
# pygame.Rect.clamp_ip() --- 原地将一个Rect对象移动到另一个Rect对象的中心
new_node = self.snake_body[0].copy() # 复制一份 <rect(60, 60, 20, 20)>
# print(new_node)
# print(new_node.x)
# print(new_node.y)
pos = DIRECTION_MOVE[self.direction] # (1, 0) 保存方向
new_node.x += (pos[0] * BLOCK_SIZE) # <rect(60, 60, 20, 20)> new_node.x第一个 60 pos(1, 0) 1
new_node.y += (pos[1] * BLOCK_SIZE) # <rect(60, 60, 20, 20)> new_node.y第二个 60 pos(1, 0) 0
self.snake_body.insert(0, new_node) # snake_body列表第一位 添加处理后的坐标 <rect(60+20, 60, 20, 20)> 列表第一位改变蛇头改变
# print(self.snake_body)
self.snake_body.pop() # 删除snake_body列表最后一项
# 判断移动按键是否合法
def is_direction_enable(self,event):
if event not in DIRECTION_MOVE: # 如果按键 没有在 上下左右范围内 则无效
return False
LR = (pygame.K_LEFT,pygame.K_RIGHT) # ( 按键左 ,按键右)
if event in LR and self.direction in LR: # 如果按键在左右 且蛇默认方向在左右 则按键无效
return False
UD = (pygame.K_UP ,pygame.K_DOWN) # ( 按键上 ,按键下)
if event in UD and self.direction in UD: # 如果按键在上下 且蛇默认方向在上下 则按键无效
return False
return True
# 修改方向默认值
def update_direction(self,event):
self.direction = event # 修改方向默认值
self.icon_direction = DIRECTION_HEAD_ANGLE[event] # 修改蛇头图标方向默认值
self.sanke_direction = pygame.transform.rotate(self.sanke_img, self.icon_direction) # 旋转蛇头
self.snake_head = pygame.transform.scale(self.sanke_direction, (BLOCK_SIZE, BLOCK_SIZE)) # 设置蛇头大小
def grow(self): # 添加尾巴
end = self.snake_body[-1].copy() # 复制 蛇列表 最后一项
self.snake_body.append(end) # 追加蛇列表
self.score += 1
# 封装随机出现的食物
class Food():
def __init__(self):
self.x = random.randint(0,SCREEN_WIDTH//BLOCK_SIZE - 1) # 食物随机出现的x坐标 0~ (640//20)-1 = 31 先求出有几个格子 再乘以20就是真实坐标
self.y = random.randint(0,SCREEN_HEIGHT//BLOCK_SIZE - 1) # 食物随机出现的x坐标 0~(480//20)-1 = 24
self.f_rect = pygame.Rect(self.x * BLOCK_SIZE, self.y * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE) # 保存食物位置
def draw(self,screen): # 随机生成食物方法
pygame.draw.rect(screen,COLOR_RED,(self.x * BLOCK_SIZE, self.y * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE), border_radius = 5) # 给窗口画图 (窗口 , 颜色 ,(x左边距离,y上边距离 ,宽,高),边框圆角 )
class Game():
def __init__(self):
pygame.init() # 初始化
self.screen = pygame.display.set_mode((SCREEN_WIDTH,SCREEN_HEIGHT)) # 创建窗口 (640,480) 用一个screen变量保存 窗口对象
pygame.display.set_caption("宝龙集团") # 给窗口添加标题
img = pygame.image.load("res/snake_logo.png") # 加载图标
pygame.display.set_icon(img) # 窗口添加图标
bg_img = pygame.image.load("res/bg.png") # 加载背景图
self.bg = pygame.transform.scale(bg_img,(SCREEN_WIDTH,SCREEN_HEIGHT)) # 背景图设置大小 (bg_img加载的背景图 ,(窗口宽640,窗口高480))
def start(self): #启动方法
s = Snake() # 实例化 蛇初始位置类
f = Food() # 实例化 随机食物类
# 获取clock
clock = pygame.time.Clock() # 帧率
while True:
events = pygame.event.get() # 获取用户所有操作事件 (鼠标点击 键盘输入) 等
for event in events: # 遍历事件 进行判断 触发哪些事件
if event.type == pygame.QUIT: # 鼠标点击 ×号 pygame库 停止工作 关闭系统
pygame.quit() # Pygame库停止工作
sys.exit() # 退出系统
elif event.type == pygame.KEYDOWN: # 判断按键是否合法
# print(event.key)
if s.is_direction_enable(event.key): # 判断移动按键是否合法
# print(event.key)
s.update_direction(event.key) # 改变方向默认值
self.screen.blit(self.bg, (0, 0)) # 给窗口渲染背景图 (背景图,(初始位置x = 0,y = 0)) 需要写在循环里,否则删除的数据不会消失
# 显示帧率 和 得分
fps = clock.get_fps() # 获取 帧率
font = pygame.font.SysFont("SimHei", 40) # 字体类型 字体大小
txt = font.render(f"帧率:%.2f"%fps, True, COLOR_RED) # 帧率文字 (帧率 ture 颜色)
self.screen.blit(txt, (0, 0)) # 窗口渲染颜色 (帧率文字 ,位置)
txt = font.render(f"得分:{s.score}", True, COLOR_RED) # 得分文字 (得分 ture 颜色)
self.screen.blit(txt, (0, 60)) # 窗口渲染颜色 (得分文字 ,位置)
for y in range(0,SCREEN_HEIGHT , BLOCK_SIZE): # 画横线 x range (0,480,20) = 0 20 40 ....
# 给窗口画横线 (窗口,线的颜色(150, 150, 150 灰色),(起点位置x距离左边多远,高度位置y左上边距离多远),(终点位置x距离右边多远,高度位置y下边距离多远))
pygame.draw.line(self.screen,COLOR_GRAY,(0,y),(SCREEN_WIDTH,y))
for x in range(0, SCREEN_WIDTH, BLOCK_SIZE): # 画纵线 y range (0,640,20) = 0 20 40 ....
# 给窗口画纵线 (窗口,线的颜色(150, 150, 150 灰色),(起点x距离左边多远,高度y左上边距离多远),(终点位置x距离右边多远,高度位置y下边距离多远))
pygame.draw.line(self.screen, COLOR_GRAY, (x, 0), (x,SCREEN_HEIGHT ))
s.draw(self.screen) # 调用蛇初始位置方法 传个窗口
f.draw(self.screen) # 调用随机食物生成
s.move() # 默认向右走
if s.snake_body[0] == f.f_rect: # 判断头是否等于食物位置
f = Food() # 头等于食物位置 食物重新生成
s.grow() # 调用添加尾巴方法(用变量拷贝蛇列表最后一项 再使用append 追加上去)
pygame.display.update() # 刷新 (显示渲染的内容)
# time.sleep(0.1) # 游戏节奏 0.1秒触发一次
clock.tick(10) # 每秒10帧
g = Game() # 实例化 贪吃蛇类
g.start() # 启动贪吃蛇