笔者参考《Python编程从入门到实践》、开源代码等资源,写了一个简单的贪吃蛇游戏。
最初学习pygame库的时候遇到的难点笔者也深有体会,所以为了方便新手学习理解,特地将注释写的非常详细。因此不再进行多余讲解。阅读需要一定pygame库基础知识。阅读代码不理解时请及时查阅pygame官方英文文档,会有详细介绍。
游戏由下图几部分组成:
因为工程量较小,笔者使用IDLE开发,整个游戏由这6个文件组成。双击run_game文件运行游戏。
food文件包含食物类,包含图片初始化、置于随机位置、获得食物坐标、获得外接矩形、绘制食物功能。
snake文件包含蛇类、初始化蛇头、获得各点位置列表、移动蛇、吃掉食物、绘制蛇功能。
settings文件包含设置类、修改速度、窗口大小、背景颜色功能,便于修改设置。
response文件包含响应鼠标键盘事件、修改移动方向、控制蛇移动功能。
run_game文件为运行文件,协调各文件。功能详见代码。
apple2为图片,用于加载食物。
以下是具体代码:
food文件:
import pygame
import random
class Food:
"""食物类"""
def __init__(self,screen):
"""随机初始化第一个食物的位置"""
self.screen = screen
#加载食物图片并获取外接矩形 (pygame通过外接矩阵操作图片)
self.image = pygame.image.load('apple2.png')
#获得图片外接矩阵
self.rect = self.image.get_rect()
#随机获得图片中心横纵坐标
#(randint获得10~490的int类型随机数,包括10和490)
#(rect.centerx为中心横坐标)
self.rect.centerx = random.randint(20,480)
self.rect.centery = random.randint(20,480)
def reinit(self):
""" 随机获得一个食物,并返回食物坐标"""
self.rect.centerx = random.randint(20,480)
self.rect.centery = random.randint(20,480)
return [self.rect.centerx,self.rect.centery]
def position(self):
""" 返回食物坐标"""
return [self.rect.centerx,self.rect.centery]
def foodrect(self):
"""返回外接矩矩形"""
return self.rect
def blitme(self):
"""在指定位置绘制食物"""
self.screen.blit(self.image,self.rect)
response文件:
import pygame
#初始化移动状态,使一开始向上移动
move_up = True
move_down = False
move_left = False
move_right = False
def check_events(snake):
"""响应按键和鼠标事件"""
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
exit(0)
check_keydown_events(event)
redirection(snake)
def check_keydown_events(event):
"""响应键盘按下"""
#可修改全局变量
global move_up
global move_down
global move_left
global move_right
if event.type == pygame.KEYDOWN:
# and move_down == False 及类似代码使蛇不可回头
if event.key == pygame.K_UP and move_down == False:
#修改移动状态
move_up = True
move_down = False
move_left = False
move_right = False
if event.key == pygame.K_DOWN and move_up == False:
move_up = False
move_down = True
move_left = False
move_right = False
if event.key == pygame.K_LEFT and move_right == False:
move_up = False
move_down = False
move_left = True
move_right = False
if event.key == pygame.K_RIGHT and move_left == False:
move_up = False
move_down = False
move_left = False
move_right = True
def redirection(snake):
global move_up
global move_down
global move_left
global move_right
#传递给蛇类的方向方法,使蛇头方向变更
if move_up:
snake.direction('U')
if move_down:
snake.direction('D')
if move_left:
snake.direction('L')
if move_right:
snake.direction('R')
settings文件:
class Settings():
"""存储游戏所有设置的类"""
def __init__(self):
"""初始化游戏的设置"""
# 设置屏幕大小
self.screen_width = 500
self.screen_height = 500
#设置屏幕背景色
self.bg_color = [255,255,240]
#设置蛇移动速度(帧数)
self.speed = 20
#设置蛇的颜色
self.snake_color = [50,0,0]
snake文件:
import copy
class Snake:
def __init__(self):
"""初始化第一个点(蛇头)的位置"""
#创建存储每个点位置的列表,目前只有蛇头
self.poslist = [[250,250]]
def position(self):
"""返回存储连续点位置的列表"""
return self.poslist
def direction(self,new_direction):
"""控制蛇移动方向"""
count = len(self.poslist)
position = count-1
#所有点移动向下一位置
while position > 0:
self.poslist[position] = copy.deepcopy(self.poslist[position-1])
position -= 1
#更新蛇头位置,和移动方向有关
if new_direction is 'U':
self.poslist[0][1] -= 10
#设置可以穿墙
if self.poslist[0][1] < 0:
self.poslist[0][1] = 500
if new_direction is 'D':
self.poslist[0][1] += 10
if self.poslist[0][1] > 500:
self.poslist[0][1] = 0
if new_direction is 'L':
self.poslist[0][0] -= 10
if self.poslist[0][0] < 0:
self.poslist[0][0] = 500
if new_direction is 'R':
self.poslist[0][0] += 10
if self.poslist[0][0] > 500:
self.poslist[0][0] = 0
def eatfood(self,foodpoint):
"""吃掉食物并加入列表"""
self.poslist.append(foodpoint)
def draw_snake(self,poslist):
"""画蛇"""
self.poslist = poslist
run_game文件:
import pygame
#导入其他文件的类、函数
import response as res
from food import Food
from settings import Settings
from snake import Snake
def run_game():
#初始化pygame
pygame.init()
#设置时钟对象,控制帧数
clock = pygame.time.Clock()
#一个Settings类实例,便于控制游戏参数
run_settings = Settings()
#游戏窗口大小,参数为宽和高
screen = pygame.display.set_mode((run_settings.screen_width,
run_settings.screen_height))
#设置窗口名字
pygame.display.set_caption("贪吃蛇")
restart = True
#创建字体对象,绘制文本,返回surface。参数一:字体 参数二:字号
socre_font = pygame.font.Font(None,28)
#记录分数
score = 0
#是否重开
while restart:
#类的实例
snake = Snake()
food = Food(screen)
running = True
#是否游戏结束
while running:
#窗口背景颜色,用参数RGB设置
screen.fill(run_settings.bg_color)
#开始接收、响应键盘指令
res.check_events(snake)
#控制循环帧数,参数为每秒帧数
time_pass = clock.tick(run_settings.speed)
#接受食物图片的外接矩形
food_rect = food.foodrect()
#矩形中心的位置
food_point = food.position()
#绘制这个食物
food.blitme()
#绘制蛇
poslist = snake.position()
snakes_rect = []
for pos in poslist:
#pygame.draw.circle()返回外接矩形
snakes_rect.append(pygame.draw.circle(screen,run_settings.snake_color,pos,5,0))
#检测是否吃到食物
#pygame.Rect.collidepoint() 检测一个点是否包含在该Rect对象内
if food_rect.collidepoint(pos):
snake.eatfood(food_point)
food.reinit()
food.blitme()
food_rect = food.foodrect()
score += 1
break
#打印内容 参数:字符串、是否平滑、颜色
score_text = socre_font.render("score : "+str(score),True,(255,0,0))
score_rect = score_text.get_rect()
#设置字体位置
score_rect.centerx = 450
score_rect.centery = 10
screen.blit(score_text,score_rect)
#检测是否撞到自己 (蛇头和身体位置是否重合)
head_rect = snakes_rect[0]
count = len(snakes_rect)
while count > 1:
if head_rect.colliderect(snakes_rect[count-1]):
running = False
count -= 1
#更新屏幕
pygame.display.update()
#游戏结束界面
screen.fill([255,255,240])
#一个字体对象,参数一:字体(None为默认) 参数二:字体大小
font = pygame.font.Font(None,38)
#绘制文本,返回surface
text = font.render("Game Over! press space to restart. ",True,(255,0,0))
textRect = text.get_rect()
textRect.centerx = screen.get_rect().centerx
textRect.centery = screen.get_rect().centery
screen.blit(text,textRect)
#是否重开
while True:
event = pygame.event.poll()
if event.type == pygame.QUIT:
pygame.quit()
exit(0)
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
restart = True
#初始化对象、变量
#python自动清理,只用删除引用
score = 0
del snake
del food
break
#更新屏幕
pygame.display.update()
run_game()
游戏过程:
此版本为基础版本,可在版本上添加:
显示历史最高分
屏幕中设置墙
背景加载图片
增加游戏声效
美化蛇头、蛇身
根据等级加快行走速度
设置各关卡
等等……各种功能
限于篇幅不做更多讨论。
转载请告知作者。