Python 玩出花儿了!一文教你用 Python 制作吃豆人游戏!| 附代

文章图片

文章图片
作者|李秋键
责编|Carol
封图|CSDN下载自视觉中国
近几年来Python语言得到了快速发展 , 而Pygame作为Python开发应用和游戏必备的库更是展现了Python的优越性 。
而今天我们就将借助Pygame建立吃豆人游戏 。

文章图片
吃豆人是电子游戏历史上的经典街机游戏 , 由Namco公司的岩谷彻设计并由MidwayGames在1980年发行
。 Pac-Man被认为是80年代最经典的街机游戏之一 , 游戏的主角小精灵的形象甚至被作为一种大众文化符号 , 或是此产业的代表形象 。
而Pygame模块是跨平台Python模块 , 专为电子游戏设计 , 包含图像、声音 。 建立在SDL基础上 , 允许实时电子游戏研发而无需被低级语言(如机器语言和汇编语言)束缚 。
最终游戏效果如下可见:

文章图片

文章图片
一、实验前的准备
【Python 玩出花儿了!一文教你用 Python 制作吃豆人游戏!| 附代】首先我们使用的python版本是3.6.5所用到的模块是pygame模块 , 用来创建游戏框架 。 Random模块用来随机生成方向 。

文章图片
素材准备
首先我们将图片放到images目录下 , 背景音乐放到sounds目录下 。
如下图可见:

文章图片

文章图片
游戏搭建
1、定义一些精灵:
整体的类变量定义包括墙类 , 通过pygame的图片填充作为墙类的加载;同理还包括食物类和角色 。 而怪物的随机运动使用random产生随机运动方向 。
其对应的代码如下:
importrandomimportpygame'''墙类'''classWall(pygame.sprite.Sprite):def__init__(self,x,y,width,height,color,**kwargs):pygame.sprite.Sprite.__init__(self)self.image=pygame.Surface([width,height])self.image.fill(color)self.rect=self.image.get_rectself.rect.left=xself.rect.top=y'''食物类'''classFood(pygame.sprite.Sprite):def__init__(self,x,y,width,height,color,bg_color,**kwargs):pygame.sprite.Sprite.__init__(self)self.image=pygame.Surface([width,height])self.image.fill(bg_color)self.image.set_colorkey(bg_color)pygame.draw.ellipse(self.image,color,[0,0,width,height])self.rect=self.image.get_rectself.rect.left=xself.rect.top=y'''角色类'''classPlayer(pygame.sprite.Sprite):def__init__(self,x,y,role_image_path):pygame.sprite.Sprite.__init__(self)self.role_name=role_image_path.split('/')[-1].split('.')[0]self.base_image=pygame.image.load(role_image_path).convertself.image=self.base_image.copyself.rect=self.image.get_rectself.rect.left=xself.rect.top=yself.prev_x=xself.prev_y=yself.base_speed=[30,30]self.speed=[0,0]self.is_move=Falseself.tracks=self.tracks_loc=[0,0]'''改变速度方向'''defchangeSpeed(self,direction):ifdirection[0]<0:self.image=pygame.transform.flip(self.base_image,True,False)elifdirection[0]>0:self.image=self.base_image.copyelifdirection[1]<0:self.image=pygame.transform.rotate(self.base_image,90)elifdirection[1]>0:self.image=pygame.transform.rotate(self.base_image,-90)self.speed=[direction[0]*self.base_speed[0],direction[1]*self.base_speed[1]]returnself.speed'''更新角色位置'''defupdate(self,wall_sprites,gate_sprites):ifnotself.is_move:returnFalsex_prev=self.rect.lefty_prev=self.rect.topself.rect.left+=self.speed[0]self.rect.top+=self.speed[1]is_collide=pygame.sprite.spritecollide(self,wall_sprites,False)ifgate_spritesisnotNone:ifnotis_collide:is_collide=pygame.sprite.spritecollide(self,gate_sprites,False)ifis_collide:self.rect.left=x_prevself.rect.top=y_prevreturnFalsereturnTrue'''生成随机的方向'''defrandomDirection(self):returnrandom.choice([[-0.5,0],[0.5,0],[0,0.5],[0,-0.5]])
2、游戏关卡定义:
在这里设置好了关卡一 。 关卡的定义必须包括墙的位置 , 不同关卡墙的位置和怪物的位置不同 。 更多关卡可以参照设置
对应代码如下:
importpygamefromSpritesimport*NUMLEVELS=1'''关卡一'''classLevel1:def__init__(self):self.info='level1''''创建墙'''defsetupWalls(self,wall_color):self.wall_sprites=pygame.sprite.Groupwall_positions=[[0,0,6,600],[0,0,600,6],[0,600,606,6],[600,0,6,606],[300,0,6,66],[60,60,186,6],[360,60,186,6],[60,120,66,6],[60,120,6,126],[180,120,246,6],[300,120,6,66],[480,120,66,6],[540,120,6,126],[120,180,126,6],[120,180,6,126],[360,180,126,6],[480,180,6,126],[180,240,6,126],[180,360,246,6],[420,240,6,126],[240,240,42,6],[324,240,42,6],[240,240,6,66],[240,300,126,6],[360,240,6,66],[0,300,66,6],[540,300,66,6],[60,360,66,6],[60,360,6,186],[480,360,66,6],[540,360,6,186],[120,420,366,6],[120,420,6,66],[480,420,6,66],[180,480,246,6],[300,480,6,66],[120,540,126,6],[360,540,126,6]]forwall_positioninwall_positions:wall=Wall(*wall_position,wall_color)self.wall_sprites.add(wall)returnself.wall_sprites'''创建门'''defsetupGate(self,gate_color):self.gate_sprites=pygame.sprite.Groupself.gate_sprites.add(Wall(282,242,42,2,gate_color))returnself.gate_sprites'''创建角色'''defsetupPlayers(self,hero_image_path,ghost_images_path):self.hero_sprites=pygame.sprite.Groupself.ghost_sprites=pygame.sprite.Groupself.hero_sprites.add(Player(287,439,hero_image_path))foreachinghost_images_path:role_name=each.split('/')[-1].split('.')[0]ifrole_name=='Blinky':player=Player(287,199,each)player.is_move=Trueplayer.tracks=[[0,-0.5,4],[0.5,0,9],[0,0.5,11],[0.5,0,3],[0,0.5,7],[-0.5,0,11],[0,0.5,3],[0.5,0,15],[0,-0.5,15],[0.5,0,3],[0,-0.5,11],[-0.5,0,3],[0,-0.5,11],[-0.5,0,3],[0,-0.5,3],[-0.5,0,7],[0,-0.5,3],[0.5,0,15],[0,0.5,15],[-0.5,0,3],[0,0.5,3],[-0.5,0,3],[0,-0.5,7],[-0.5,0,3],[0,0.5,7],[-0.5,0,11],[0,-0.5,7],[0.5,0,5]]self.ghost_sprites.add(player)elifrole_name=='Clyde':player=Player(319,259,each)player.is_move=Trueplayer.tracks=[[-1,0,2],[0,-0.5,4],[0.5,0,5],[0,0.5,7],[-0.5,0,11],[0,-0.5,7],[-0.5,0,3],[0,0.5,7],[-0.5,0,7],[0,0.5,15],[0.5,0,15],[0,-0.5,3],[-0.5,0,11],[0,-0.5,7],[0.5,0,3],[0,-0.5,11],[0.5,0,9]]self.ghost_sprites.add(player)elifrole_name=='Inky':player=Player(255,259,each)player.is_move=Trueplayer.tracks=[[1,0,2],[0,-0.5,4],[0.5,0,10],[0,0.5,7],[0.5,0,3],[0,-0.5,3],[0.5,0,3],[0,-0.5,15],[-0.5,0,15],[0,0.5,3],[0.5,0,15],[0,0.5,11],[-0.5,0,3],[0,-0.5,7],[-0.5,0,11],[0,0.5,3],[-0.5,0,11],[0,0.5,7],[-0.5,0,3],[0,-0.5,3],[-0.5,0,3],[0,-0.5,15],[0.5,0,15],[0,0.5,3],[-0.5,0,15],[0,0.5,11],[0.5,0,3],[0,-0.5,11],[0.5,0,11],[0,0.5,3],[0.5,0,1]]self.ghost_sprites.add(player)elifrole_name=='Pinky':player=Player(287,259,each)player.is_move=Trueplayer.tracks=[[0,-1,4],[0.5,0,9],[0,0.5,11],[-0.5,0,23],[0,0.5,7],[0.5,0,3],[0,-0.5,3],[0.5,0,19],[0,0.5,3],[0.5,0,3],[0,0.5,3],[0.5,0,3],[0,-0.5,15],[-0.5,0,7],[0,0.5,3],[-0.5,0,19],[0,-0.5,11],[0.5,0,9]]self.ghost_sprites.add(player)returnself.hero_sprites,self.ghost_sprites'''创建食物'''defsetupFood(self,food_color,bg_color):self.food_sprites=pygame.sprite.Groupforrowinrange(19):forcolinrange(19):if(row==7orrow==8)and(col==8orcol==9orcol==10):continueelse:food=Food(30*col+32,30*row+32,4,4,food_color,bg_color)is_collide=pygame.sprite.spritecollide(food,self.wall_sprites,False)ifis_collide:continueis_collide=pygame.sprite.spritecollide(food,self.hero_sprites,False)ifis_collide:continueself.food_sprites.add(food)returnself.food_sprites
3、游戏创建:
在通过关卡定义墙等位置后以及精灵自身属性怪物运动、食物定义等后 , 通过调用已经创建好的类达到搭建游戏的目的 。
具体如下可见:
importosimportsysimportpygameimportLevels'''定义一些必要的参数'''BLACK=(0,0,0)WHITE=(255,255,255)BLUE=(0,0,255)GREEN=(0,255,0)RED=(255,0,0)YELLOW=(255,255,0)PURPLE=(255,0,255)SKYBLUE=(0,191,255)BGMPATH=os.path.join(os.getcwd,'resources/sounds/bg.mp3')ICONPATH=os.path.join(os.getcwd,'resources/images/icon.png')FONTPATH=os.path.join(os.getcwd,'resources/font/ALGER.TTF')HEROPATH=os.path.join(os.getcwd,'resources/images/pacman.png')BlinkyPATH=os.path.join(os.getcwd,'resources/images/Blinky.png')ClydePATH=os.path.join(os.getcwd,'resources/images/Clyde.png')InkyPATH=os.path.join(os.getcwd,'resources/images/Inky.png')PinkyPATH=os.path.join(os.getcwd,'resources/images/Pinky.png')'''开始某一关游戏'''defstartLevelGame(level,screen,font):clock=pygame.time.ClockSCORE=0wall_sprites=level.setupWalls(SKYBLUE)gate_sprites=level.setupGate(WHITE)hero_sprites,ghost_sprites=level.setupPlayers(HEROPATH,[BlinkyPATH,ClydePATH,InkyPATH,PinkyPATH])food_sprites=level.setupFood(YELLOW,WHITE)is_clearance=FalsewhileTrue:foreventinpygame.event.get:ifevent.type==pygame.QUIT:sys.exit(-1)pygame.quitifevent.type==pygame.KEYDOWN:ifevent.key==pygame.K_LEFT:forheroinhero_sprites:hero.changeSpeed([-1,0])hero.is_move=Trueelifevent.key==pygame.K_RIGHT:forheroinhero_sprites:hero.changeSpeed([1,0])hero.is_move=Trueelifevent.key==pygame.K_UP:forheroinhero_sprites:hero.changeSpeed([0,-1])hero.is_move=Trueelifevent.key==pygame.K_DOWN:forheroinhero_sprites:hero.changeSpeed([0,1])hero.is_move=Trueifevent.type==pygame.KEYUP:if(event.key==pygame.K_LEFT)or(event.key==pygame.K_RIGHT)or(event.key==pygame.K_UP)or(event.key==pygame.K_DOWN):hero.is_move=Falsescreen.fill(BLACK)forheroinhero_sprites:hero.update(wall_sprites,gate_sprites)hero_sprites.draw(screen)forheroinhero_sprites:food_eaten=pygame.sprite.spritecollide(hero,food_sprites,True)SCORE+=len(food_eaten)wall_sprites.draw(screen)gate_sprites.draw(screen)food_sprites.draw(screen)forghostinghost_sprites:#幽灵随机运动(效果不好且有BUG)'''res=ghost.update(wall_sprites,None)whilenotres:ghost.changeSpeed(ghost.randomDirection)res=ghost.update(wall_sprites,None)'''#指定幽灵运动路径ifghost.tracks_loc[1]<ghost.tracks[ghost.tracks_loc[0]][2]:ghost.changeSpeed(ghost.tracks[ghost.tracks_loc[0]][0:2])ghost.tracks_loc[1]+=1else:ifghost.tracks_loc[0]<len(ghost.tracks)-1:ghost.tracks_loc[0]+=1elifghost.role_name=='Clyde':ghost.tracks_loc[0]=2else:ghost.tracks_loc[0]=0ghost.changeSpeed(ghost.tracks[ghost.tracks_loc[0]][0:2])ghost.tracks_loc[1]=0ifghost.tracks_loc[1]<ghost.tracks[ghost.tracks_loc[0]][2]:ghost.changeSpeed(ghost.tracks[ghost.tracks_loc[0]][0:2])else:ifghost.tracks_loc[0]<len(ghost.tracks)-1:loc0=ghost.tracks_loc[0]+1elifghost.role_name=='Clyde':loc0=2else:loc0=0ghost.changeSpeed(ghost.tracks[loc0][0:2])ghost.update(wall_sprites,None)ghost_sprites.draw(screen)score_text=font.render(''Score:%s''%SCORE,True,RED)screen.blit(score_text,[10,10])iflen(food_sprites)==0:is_clearance=Truebreakifpygame.sprite.groupcollide(hero_sprites,ghost_sprites,False,False):is_clearance=Falsebreakpygame.display.flipclock.tick(10)returnis_clearance'''显示文字'''defshowText(screen,font,is_clearance,flag=False):clock=pygame.time.Clockmsg='GameOver!'ifnotis_clearanceelse'Congratulations,youwon!'positions=[[235,233],[65,303],[170,333]]ifnotis_clearanceelse[[145,233],[65,303],[170,333]]surface=pygame.Surface((400,200))surface.set_alpha(10)surface.fill((128,128,128))screen.blit(surface,(100,200))texts=[font.render(msg,True,WHITE),font.render('PressENTERtocontinueorplayagain.',True,WHITE),font.render('PressESCAPEtoquit.',True,WHITE)]whileTrue:foreventinpygame.event.get:ifevent.type==pygame.QUIT:sys.exitpygame.quitifevent.type==pygame.KEYDOWN:ifevent.key==pygame.K_RETURN:ifis_clearance:ifnotflag:returnelse:main(initialize)else:main(initialize)elifevent.key==pygame.K_ESCAPE:sys.exitpygame.quitforidx,(text,position)inenumerate(zip(texts,positions)):screen.blit(text,position)pygame.display.flipclock.tick(10)'''初始化'''definitialize:pygame.initicon_image=pygame.image.load(ICONPATH)pygame.display.set_icon(icon_image)screen=pygame.display.set_mode([606,606])pygame.display.set_caption('吃豆人')returnscreen'''主函数'''defmain(screen):pygame.mixer.initpygame.mixer.music.load(BGMPATH)pygame.mixer.music.play(-1,0.0)pygame.font.initfont_small=pygame.font.Font(FONTPATH,18)font_big=pygame.font.Font(FONTPATH,24)fornum_levelinrange(1,Levels.NUMLEVELS+1):ifnum_level==1:level=Levels.Level1is_clearance=startLevelGame(level,screen,font_small)ifnum_level==Levels.NUMLEVELS:showText(screen,font_big,is_clearance,True)else:showText(screen,font_big,is_clearance)
最终运行程序结果如下:

文章图片
源码地址:
https://pan.baidu.com/s/128id8L-PDPgGOPuH-5uHDg
提取码:rj9f
作者简介:
李秋键 , CSDN博客专家 , CSDN达人课作者 。 硕士在读于中国矿业大学 , 开发有taptap竞赛获奖等等 。

文章图片
推荐阅读
- python深度学习:为什么要学习深度学习?
- Python|1. OpenCV概述与环境搭建
- 清晨,花儿悄悄绽放,鸟儿欢声歌唱,微风轻轻细语,白云低首浅笑
- 青年|一本书带你轻松入门OpenCV-面向Python
- Python|石头,纸,剪刀与Python
- |智慧交互,玩出双倍乐趣,华为智慧屏为《元气满满的哥哥》助力!
- 结构|《从Blockly可视化编程到Python编程》第三章 选择结构
- Python|这么火的Python,哪些领域能用?
- 中年|我帮公司财务写了个“群发工资条”的Python脚本
- Python Requests作者另一神作,Records通用而优雅的数据库访问库
