Python命令行小游戏—贪吃蛇
前言一、贪吃蛇游戏初始界面及地图1.游戏初始界面2.游戏地图二、命令符的设置、输出刷新和按键检测1.库支持2.c语言代码3.Python代码(变量初始化及游戏初始化)三、蛇的移动四、蛇的方向控制五、食物的设置六、游戏结束七、主程序八、演示效果总结前言
为了初步学习Python更有兴趣,决定做个学编程大多都会做的小游戏—贪吃蛇,因为是刚刚开始学习,不足之处,希望大家多多指正。
一、贪吃蛇游戏初始界面及地图
1.游戏初始界面
def mune():os.system("color 0a")dll.set_cmd(0, 2);print("□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□")dll.set_cmd(0, 3);print("□□□□□■■■■□□□□□□□贪吃蛇□□□□□□□□□■□□□ 操作指南 □□□□")#7dll.set_cmd(0, 4);print("□□□□■■□□■■□□□□□□□□□□□□□□□□□□■□□□方向键 改变方向□□□□")#5dll.set_cmd(0, 5);print("□□□■■□□□□□□□□□□.05.06□□□□□□□□■□□□ESC退出游戏□□□□□□")dll.set_cmd(0, 6);print("□□□□■■□□□□□□□□□□□□□□□□□□□□□□■□□□SPACE 暂停游戏□□□□□□□□□")dll.set_cmd(0, 7);print("□□□□□■■■■□□□□■■■■□□□□■■■□□□□■□□■■□□□□■■■■■□□")dll.set_cmd(0, 8);print("□■□□□□□■■■□□■□□□□■□□■□□□■□□□■■□□□□□□■□□□□□■□")dll.set_cmd(0, 9);print("□□■□□□□□■■■□■□□□□■□■□□□□■□□□■■□□□□□■□□■■■■□□")dll.set_cmd(0,10);print("□□□■■□□■■■□□■□□□□■□□■□□■□■□□■□■□□□□□■□□□□□□□")dll.set_cmd(0,11);print("□□□□■■■■□□□□■□□□□■□□□■■□□■■□■□□■■■□□□■■■■■□□")#24dll.set_cmd(0,12);print("□□□□□□□□□□□□□□□□□□按空格开始游戏□□□□□□□□□□□□□□□□□□□")
这里使用了os库和ctypes库以及调用的.dll自建动态库,第二节会详细说明
2.游戏地图
def wall(x,y):#绘制围墙i=0;j=0while i<=x:print('■',end="")for j in range(y):if i==0:print('■', end="")elif i==20:print('■', end="")else:print(" ",end="")j+=1print('■')i+=1j=0
简单的使用Python的输出函数print()做一个围墙,默认情况下函数内的end=“/n”
二、命令符的设置、输出刷新和按键检测
1.库支持
os库中的os.system(“命令行指令”)函数可执行命令行中的指令,具体指令可在命令行中输入help回车获得相关信息c语言能够更好的对命令行的输出进行刷新,这里通过调用.dll的方式调用c语言,具体的使用可观看此视频python和C语言混合编程2.c语言代码
#include<stdio.h>#include<stdlib.h>#include<windows.h>#include<conio.h>//命令行光标显示(1)隐藏(0)_declspec(dllexport) void _stdcall init_cmd(int x){HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);CONSOLE_CURSOR_INFO CursorInfo;GetConsoleCursorInfo(handle, &CursorInfo);//获取控制台光标信息CursorInfo.bVisible = x; //控制台光标状态,x=1显示,x=0隐藏SetConsoleCursorInfo(handle, &CursorInfo);//设置控制台光标状态}//命令行光标移动函数_declspec(dllexport) void _stdcall set_cmd(int x, int y){COORD pos;pos.X = x;pos.Y = y;SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos);}//获取键盘输入_declspec(dllexport) int _stdcall c_getch(){int key;if (_kbhit()) {//_kbhit()为按键检测,有按键输出1,没有输出0key = _getch();Sleep(10);return key;}else;}
3.Python代码(变量初始化及游戏初始化)
import os,time,ctypes,randomwall_x,wall_y ,eat_flag= 20,21,1move_up,move_down,move_left,move_right,esc,space = 72,80,75,77,27,32def init_game():#游戏界面初始化global getkey, key, snake_x, snake_y, snake_list#全局变量声明os.system("mode con cols=48 lines=22") # 设置命令符窗口大小os.system("cls")os.system("color 2b") # 设置字体和背景颜色wall(wall_x, wall_y) # 绘制围墙dll.set_cmd(0, 1)print("■□□□□○")snake_list = [[2, 1], [4, 1], [6, 1], [8, 1], [10, 1]]snake_x, snake_y ,getkey,key= 10, 1,0,0def init():#命令符及游戏初始化ctypes.windll.kernel32.SetConsoleTitleW("贪吃蛇") # 修改命令符标题os.system("mode con cols=88 lines=15") # 设置命令符窗口大小dll.init_cmd(0) # 设置光标状态
当定义函数内有全局变量的值发生变化时,需要进行全局变量声明
三、蛇的移动
def snake_move(*lis):#蛇移动dll.set_cmd(snake_list[0][0], snake_list[0][1])print(" ")snake_list.append(lis[0])if eat_flag==0:snake_list.pop(0)dll.set_cmd(snake_list[-1][0], snake_list[-1][1])print("○")n = 0for n in range(len(snake_list)-2):dll.set_cmd(snake_list[-2-n][0], snake_list[-2-n][1])print("□")n += 1def move():#蛇移动防倒走global snake_x, snake_yif [snake_x, snake_y] in snake_list[-2:]:snake_x = snake_list[-1][0]snake_y = snake_list[-1][1]else:snake_move([snake_x, snake_y])
蛇的身体的每个小块对应列表内的一个坐标,头的位置处于列表最后一项。当移动时消除第一个坐标所在的位置,使用pop(0)方法弹出第一项将下一个头的位置(由snake_ctrl函数提供)使用append()方法添加到列表最后通过检测位置坐标(x in y)是否为靠近头的一段来防止蛇倒走。
四、蛇的方向控制
def get_key():#获得键盘输入global getkey,keya = dll.c_getch()if a in [esc,space]:getkey = aif a in [move_up,move_down,move_left,move_right]:if ((key == move_up) and (a != move_down))or ((key == move_down) and (a != move_up)) \or(key == 0) or((key == move_left) and (a != move_right)) \or ((key == move_right) and (a != move_left)):key = aelse:passelse:passdef snake_ctrl():#根据键盘输入判断方向已经功能操作global getkey, key, snake_x, snake_yif key == move_down:snake_y += 1elif key == move_up:snake_y -= 1elif key == move_right:snake_x += 2elif key == move_left:snake_x -= 2else:passif getkey == space:time.sleep(1)getkey = 0while 1:getkey = dll.c_getch()if getkey == space:getkey = 0breakelif getkey == esc:breakelse:passelse:pass
检测按键输入get_key()以及设置相应按键实现的功能snake_ctrl()
五、食物的设置
def putfood():#放置食物global food_x,food_y,eat_flagif eat_flag==1:food_x = snake_xfood_y = snake_ywhile [food_x,food_y] in snake_list:food_x = random.randint(1, 20) * 2food_y = random.randint(1, 19)eat_flag = 0dll.set_cmd(food_x,food_y)print("●")else :passdef eatfood():#吃掉食物判断global eat_flag,snake_list,snake_x, snake_yif ([food_x,food_y] in snake_list)and(eat_flag==0) :eat_flag = 1else:pass
不得不说Python中成员判断真的很好用。
通过食物坐标点点是否已经包含到蛇身体的列表中来判断是否吃到食物食物的产生通过随机函数(random.randint(x,y))来提供坐标是否放置食物由是否吃掉的标志(eat_flag)来判断
六、游戏结束
def gameover():#游戏结束判断if (snake_x>42)|(snake_y>19)\|(snake_x<2)|(snake_y==0):return 1elif snake_list.count(snake_list[-1])>1:return 1else :return 0def over_next():#结束后的操作global getkey,eat_flagif gameover():dll.set_cmd(16, 9)print("得分:{}分".format(len(snake_list)-5))dll.set_cmd(6, 10)print("游戏结束,esc退出,space重新开始")while 1:getkey = dll.c_getch()if getkey == esc:os.system("cls")dll.init_cmd(1)os.system("exit")breakelif getkey == space:init_game()eat_flag = 1breakelse:passelse:pass
贪吃蛇撞墙的判断就简单粗暴的坐标判断,如果地图复杂可能需要使用列表将每部分墙体的起始坐标录入进行判断,贪吃蛇只需要判断头的位置就能够判断是否撞到了墙。使用列表的count方法能够很简单的判断序列中有没有两相同的元素,来检测蛇有没有吃到自己。
七、主程序
if __name__ == '__main__':#主函数maindll = ctypes.windll.LoadLibrary("set_cmd.dll") # 调用c语言程序init()mune()while 1:getkey = dll.c_getch()if getkey == space:breakelse:passinit_game()while 1:get_key()putfood()eatfood()snake_ctrl()move()over_next()if getkey == esc:os.system("cls")dll.init_cmd(1)os.system("exit")breakelse:passget_key()time.sleep(0.15)
通过两次按键get_key()检测来减少按键的检测缺失可以通过调整循环等待时间time.sleep(0.15)来调整游戏内蛇的速度
八、演示效果
生成.exe文件需要用到pyinstaller,没有的话需要进行以下步骤
运行命令符输入pip install pyinstaller等待安装完成,输入pyinstaller -F xxx.py(文件位置)
以下是演示效果
评价:能玩
总结
虽然最后成品比较简陋,但还是有些成就感的,比之前光看书感觉效率提高很多。
下面是所有文件的网盘链接点击下载
提取码:6v5o