Python实现贪吃蛇小游戏(单人模式)

简单用py写了一个贪吃蛇游戏,有单人、双人模式,比较简单,适合初学者练手。基本上每行重要的语句都有注释,做了什么事一目了然

这里先介绍单人模式

一、游戏设计要点

【Python实现贪吃蛇小游戏(单人模式)】1.游戏主体窗口(尺寸)、画布(尺寸、位置)、按钮(尺寸、位置)、文字(大小、颜色、位置)、图像、背景音乐及相关响应函数(主要是鼠标移动及点击的响应)的设计与合理排布
2.蛇与食物的类的属性设计
3.蛇位置的更新(根据键盘输入)、吃到食物加分的判定、食物的更新
4.蛇死亡的判定条件设计
二、主要模块

1.pygame
2.sys
3.random
三、用到的类

1.Snake类,定义蛇头蛇身元素的位置
2.Food类,定义食物元素的位置及单个元素的颜色
四、主要函数

1.new_food(),功能:生成一个不与蛇头位置重合的食物并返回该食物对象

def new_food(head):while True:# 循环,不断实例化new_food对象直到生成一个不与蛇头重合的食物new_food = Food(randint(0, 45) * 20, randint(0, 28) * 20, (randint(10, 255), randint(10, 255), randint(10, 255)))# 若new_food和蛇头重合则不创键if new_food.x != head.x and new_food.y != head.y:breakelse:continuereturn new_food

2.draw_snake()、draw_food()函数,功能:绘制蛇与食物的图像,传入参数为颜色和对象:
# 在窗体中绘制贪吃蛇# 形参:一个是颜色另一个是实例化对象def draw_snake(color, object):pygame.draw.circle(window, color, (object.x, object.y), 10)# 在窗体中绘制食物# 形参:实例化对象def draw_food(food):pygame.draw.circle(window, food.color, (food.x, food.y), 10)

3.show_end函数,功能:显示单人模式结束时的得分界面:
# 游戏结束时,单人模式显示得分的窗体的设置def show_end_single():while True:window.blit(init_background, (0, 0))for event in pygame.event.get():if event.type == pygame.QUIT:exit_end()# 定义标题pygame.display.set_caption("贪吃蛇大冒险")# 定义提示文字font = pygame.font.SysFont("simHei", 40)fontsurf = font.render('游戏结束! 你的得分为: %s' % score, False, black)window.blit(fontsurf, (250, 100))button("返回主菜单", 370, 300, 200, 40, blue, brightred, into_game)button("退出游戏", 370, 470, 200, 40, red, brightred, exit_end)pygame.display.update()clock.tick(20)

4.exit_end()函数,功能:在初始界面和游戏结束显示得分界面点击右上角的"×"时,直接退出整个游戏:
def exit_end():pygame.quit()sys.exit()

5.start_game()函数,功能:实现单人正常模式:
def start_game():# 播放音乐pygame.mixer.music.play(-1)# 定义存分数的全局变量global scorescore = 0# 定义存放玩家键盘输入运动方向的变量,初始为向右run_direction = "right"# 定义贪吃蛇运动方向的变量,初始为玩家键入方向run = run_direction# 实例化贪吃蛇和食物对象head = Snake(randint(0, 30) * 20, randint(0, 20) * 20)# 实例化蛇身长度为2个单位snake_body = [Snake(head.x, head.y + 20), Snake(head.x, head.y + 40)]# 实例化食物列表,列表随着其中食物被吃掉应该不断缩短food_list = [Food(randint(0, 45) * 20, randint(0, 28) * 20, (randint(10, 255), randint(10, 255), randint(10, 255)))]for i in range(1,24):food_list.append(Food(randint(0, 45) * 20, randint(0, 28) * 20, (randint(10, 255), randint(10, 255), randint(10, 255))))# 实例化单个食物,方便循环内生成单个新食物food = Food(randint(0, 45) * 20, randint(0, 28) * 20, (randint(10, 255), randint(10, 255), randint(10, 255)))while True:window.blit(background, (0,0))# 监听玩家键盘输入的运动方向值,并根据输入转为up、down、right或left,方便程序中调用# pygame.event.get()返回一个列表,存放本次game执行中程序遇到的一连串事件(按时间顺序依次存放)for event in pygame.event.get():# pygame.QUIT事件是指用户点击窗口右上角的"×"if event.type == pygame.QUIT:# 显示结果界面show_end()# 若事件类型是按下键盘,分↑ ↓ ← →四种情况讨论elif event.type == pygame.KEYDOWN:# 若事件类型是按下键盘↑# key是键值,表示按下去的键值是什么if event.key == ord('w'):run_direction = "up"# 若事件类型是按下键盘↓if event.key == ord('s'):run_direction = "down"# 若事件类型是按下键盘←if event.key == ord('a'):run_direction = "left"# 若事件类型是按下键盘→if event.key == ord('d'):run_direction = "right"# 绘制初始化的25个食物图像(24+1=25)# 随着该列表中的食物被吃掉,列表应该不断pop以清除已经被吃的事物for item in food_list:draw_food(item)# 绘制被贪吃蛇吃掉后新增的食物图像draw_food(food)# 绘制蛇头图像draw_snake(black, head)# 绘制蛇身图像for item in snake_body:draw_snake(blue, item)# 判断贪吃蛇原运动方向(run)与玩家键盘输入的运动方向(run_direction)是否违反正常运动情况if run == "up" and not run_direction == "down":run = run_directionelif run == "down" and not run_direction == "up":run = run_directionelif run == "left" and not run_direction == "right":run = run_directionelif run == "right" and not run_direction == "left":run = run_direction# 插入蛇头位置到蛇身列表中snake_body.insert(0, Snake(head.x, head.y))# 根据玩家键入方向进行蛇头xy的更新if run == "up":head.y -= 20elif run == "down":head.y += 20elif run == "left":head.x -= 20elif run == "right":head.x += 20# 判断是否死亡die_flag = False# 遍历存放贪吃蛇位姿的列表,从第1个开始,(第0个位蛇头)for body in snake_body[1:]:# 如果蛇头的xy和蛇身xy相等,则判定相撞,设置flag为tureif head.x == body.x and head.y == body.y:die_flag = True# 若蛇头的xy在显示窗体外,或flag为true,则显示结束界面,并退出游戏if die_flag == True or head.x < 0 or head.x > 960 or head.y < 0 or head.y > 600:# 停止播放音乐pygame.mixer.music.stop()show_end()# die_snake(head, snake_body)# 判断蛇头和食物坐标,若相等,则加分,并生成新的食物# 定义标志,表明是否找到和蛇头相等的事物global flagflag = 0# 如果蛇头和食物重合for item in food_list:if head.x == item.x and head.y == item.y or head.x == food.x and head.y == food.y:flag = 1score += 1# 弹出被吃掉的这个食物food_list.pop(food_list.index(item))# 再产生一个食物food = new_food(head)# 把新食物插入food_list,下一次循环中会更新绘制食物全体food_list.append(food)breakif flag == 0:snake_body.pop()font = pygame.font.SysFont("simHei", 25)mode_title = font.render('正常模式', False, grey)socre_title = font.render('得分: %s' % score, False, grey)window.blit(mode_title, (50, 30))window.blit(socre_title, (50, 65))# 更新蛇头蛇身和食物的数据pygame.display.update()# 通过帧率设置贪吃蛇速度clock.tick(8)

6.start_kgame()函数,功能:实现单人穿墙模式:
def start_kgame_single():# 播放音乐pygame.mixer.music.play(-1)global scorescore = 0# 定义存放玩家键盘输入运动方向的变量,初始为向右run_direction = "right"# 定义贪吃蛇运动方向的变量,初始为玩家键入方向run = run_direction# 实例化蛇头、蛇身、食物对象head = Snake(160, 160)# 实例化蛇身snake_body = [Snake(head.x, head.y + 20), Snake(head.x, head.y + 40), Snake(head.x, head.y + 60)]# 实例化食物列表,列表随着其中食物被吃掉应该不断缩短food_list = [Food(randint(0, 45) * 20, randint(0, 28) * 20, (randint(10, 255), randint(10, 255), randint(10, 255)))]for i in range(1,24):food_list.append(Food(randint(0, 45) * 20, randint(0, 28) * 20, (randint(10, 255), randint(10, 255), randint(10, 255))))# 实例化单个食物,方便循环内生成单个新食物food = Food(randint(0, 45) * 20, randint(0, 28) * 20, (randint(10, 255), randint(10, 255), randint(10, 255)))# 死循环,监听键盘键值while True:window.blit(background, (0, 0))for event in pygame.event.get():if event.type == pygame.QUIT:show_end_single()elif event.type == pygame.KEYDOWN:# 若事件类型是按下键盘w# key是键值,表示按下去的键值是什么if event.key == ord('w'):run_direction = "up"# 若事件类型是按下键盘sif event.key == ord('s'):run_direction = "down"# 若事件类型是按下键盘aif event.key == ord('a'):run_direction = "left"# 若事件类型是按下键盘dif event.key == ord('d'):run_direction = "right"# 绘制初始化的25个食物图像(24+1=25)# 随着该列表中的食物被吃掉,列表应该不断pop以清除已经被吃的事物for item in food_list:draw_food(item)# 绘制被贪吃蛇吃掉后新增的食物图像draw_food(food)# 绘制蛇头图像draw_snake(black, head)# 绘制蛇身图像for item in snake_body:draw_snake(blue, item)# 判断贪吃蛇原运动方向与玩家键盘输入的运动方向是否违反正常运动情况if run == "up" and not run_direction == "down":# 若运动方向为向上,玩家输入运动方向向下,则违背贪吃蛇正常运动情况run = run_directionelif run == "down" and not run_direction == "up":run = run_directionelif run == "left" and not run_direction == "right":run = run_directionelif run == "right" and not run_direction == "left":run = run_direction# 插入蛇头位置到蛇身列表中snake_body.insert(0, Snake(head.x, head.y))# 根据玩家键入方向进行蛇头xy的更新if run == "up":head.y -= 20elif run == "down":head.y += 20elif run == "left":head.x -= 20elif run == "right":head.x += 20# 穿墙实现# 定义标志位die_flag = False# 遍历,蛇头碰到蛇身时,flag为true退出游戏for body in snake_body[1:]:if head.x == body.x and head.y == body.y:die_flag = Trueif die_flag:pygame.mixer.music.stop()show_end()else: # 当蛇头穿出窗体时有四种情况,分别讨论if head.x < 0:head.x = 960if head.x > 960:head.x = 0if head.y < 0:head.y = 600if head.y > 600:head.y = 0# 判断蛇头和食物坐标,若相等,则加分,并生成新的食物# 定义标志,表明是否找到和蛇头相等的事物global flagflag = 0# 如果蛇头和食物重合for item in food_list:if head.x == item.x and head.y == item.y or head.x == food.x and head.y == food.y:flag = 1score += 1# 弹出被吃掉的这个食物food_list.pop(food_list.index(item))# 再产生一个食物food = new_food(head)# 把新食物插入food_list,下一次循环中会更新绘制食物全体food_list.append(food)break# 若没吃到食物则从蛇身pop一个元素以更新蛇位置if flag == 0:snake_body.pop()font = pygame.font.SysFont("simHei", 25)mode_title = font.render('穿墙模式', False, grey)socre_title = font.render('得分: %s' % score, False, grey)window.blit(mode_title, (50, 30))window.blit(socre_title, (50, 65))# 绘制更新pygame.display.update()# 通过帧率设置贪吃蛇速度clock.tick(8)

7.button()函数,功能:实现按钮样式设计和响应鼠标操作:
def button(msg, x, y, w, h, ic, ac, action=None):# 获取鼠标位置mouse = pygame.mouse.get_pos()# 获取鼠标点击情况click = pygame.mouse.get_pressed()if x + w > mouse[0] > x and y + h > mouse[1] > y:pygame.draw.rect(window, ac, (x, y, w, h))if click[0] == 1 and action != None:action()else:pygame.draw.rect(window, ic, (x, y, w, h))# 设置按钮中的文字样式和居中对齐font = pygame.font.SysFont('simHei', 20)smallfont = font.render(msg, True, white)smallrect = smallfont.get_rect()smallrect.center = ((x + (w / 2)), (y + (h / 2)))window.blit(smallfont, smallrect)

8.into_game()函数,功能:实现游戏初始界面,选择模式:
def into_game():while True:window.blit(init_background, (0, 0))for event in pygame.event.get():if event.type == pygame.QUIT:exit_end()# 设置字体font = pygame.font.SysFont("simHei", 50)# 初始界面显示文字fontsurf = font.render('欢迎来到贪吃蛇大冒险!', True, black)# 文字fontrect = fontsurf.get_rect()fontrect.center = ((480), 200)window.blit(fontsurf, fontrect)button("正常模式", 370, 370, 200, 40, blue, brightred, start_game)button("可穿墙模式", 370, 420, 200, 40, violte, brightred, start_kgame)button("退出游戏", 370, 470, 200, 40, red, brightred, exit_end)pygame.display.update()clock.tick(20)

9.主函数,功能:初始化参数设定,进入游戏:

if __name__ == '__main__':# 定义需要用到的颜色white = (255, 255, 255)red = (200, 0, 0)green = (0, 128, 0)blue = (0, 202, 254)violte = (194, 8, 234)brightred = (255, 0, 0)brightgreen = (0, 255, 0)black = (0, 0, 0)grey = (129, 131, 129)# 设计窗口window = pygame.display.set_mode((960, 600))# 定义标题pygame.display.set_caption("贪吃蛇大冒险")# 定义背景图片init_background = pygame.image.load("image/init_bgimg.jpg")background = pygame.image.load("image/bgimg.jpg")# 背景音乐pygame.mixer.init()pygame.mixer.music.load("background.mp3")# 创建时钟clock = pygame.time.Clock()# 初始化,自检所有模块是否完整pygame.init()# 初始界面into_game()

注:其中的图片、背景音乐需要自己找合适(尺寸要与窗口大小相适应)的,也可以参考我上传的资源:贪吃蛇单人版源代码+背景+音乐

附:Blog:双人模式详解

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

    推荐阅读