网易首页 > 网易号 > 正文 申请入驻

【蓝因子教育】用Python写个开心消消乐小游戏

0
分享至

提到开心消消乐这款小游戏,相信大家都不陌生,其曾在 2015 年获得过玩家最喜爱的移动单机游戏奖,受欢迎程度可见一斑,本文我们使用 Python 来做个简单的消消乐小游戏。

实现

消消乐的构成主要包括三部分:游戏主体、计分器、计时器,下面来看一下具体实现。

先来看一下游戏所需 Python 库。

import osimport sysimport timeimport pygameimport random

定义一些常量,比如:窗口宽高、网格行列数等,代码如下:

WIDTH = 400HEIGHT = 400NUMGRID = 8GRIDSIZE = 36XMARGIN = (WIDTH - GRIDSIZE * NUMGRID) // 2YMARGIN = (HEIGHT - GRIDSIZE * NUMGRID) // 2ROOTDIR = os.getcwd()FPS = 30

接着创建一个主窗口,代码如下:

pygame.init()screen = pygame.display.set_mode((WIDTH, HEIGHT))pygame.display.set_caption('消消乐')

看一下效果:



再接着在窗口中画一个 8 x 8 的网格,代码如下:

screen.fill((255, 255, 220))# 游戏界面的网格绘制def drawGrids(self): for x in range(NUMGRID): for y in range(NUMGRID): rect = pygame.Rect((XMARGIN+x*GRIDSIZE, YMARGIN+y*GRIDSIZE, GRIDSIZE, GRIDSIZE)) self.drawBlock(rect, color=(255, 165, 0), size=1# 画矩形 block 框def drawBlock(self, block, color=(255, 0, 0), size=2): pygame.draw.rect(self.screen, color, block, size)

看一下效果:



再接着在网格中随机放入各种拼图块,代码如下:

while True: self.all_gems = [] self.gems_group = pygame.sprite.Group() for x in range(NUMGRID): self.all_gems.append([]) for y in range(NUMGRID): gem = Puzzle(img_path=random.choice(self.gem_imgs), size=(GRIDSIZE, GRIDSIZE), position=[XMARGIN+x*GRIDSIZE, YMARGIN+y*GRIDSIZE-NUMGRID*GRIDSIZE], downlen=NUMGRID*GRIDSIZE) self.all_gems[x].append(gem) self.gems_group.add(gem) if self.isMatch()[0] == 0: break

看一下效果:



再接着加入计分器和计时器,代码如下:

# 显示得分def drawScore(self): score_render = self.font.render('分数:'+str(self.score), 1, (85, 65, 0)) rect = score_render.get_rect() rect.left, rect.top = (55, 15) self.screen.blit(score_render, rect)# 显示加分def drawAddScore(self, add_score): score_render = self.font.render('+'+str(add_score), 1, (255, 100, 100)) rect = score_render.get_rect() rect.left, rect.top = (250, 250) self.screen.blit(score_render, rect)# 显示剩余时间def showRemainingTime(self): remaining_time_render = self.font.render('倒计时: %ss' % str(self.remaining_time), 1, (85, 65, 0)) rect = remaining_time_render.get_rect() rect.left, rect.top = (WIDTH-190, 15) self.screen.blit(remaining_time_render, rect)

看一下效果:



当设置的游戏时间用尽时,我们可以生成一些提示信息,代码如下:

while True: for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() sys.exit() if event.type == pygame.KEYUP and event.key == pygame.K_r: flag = True if flag: break screen.fill((255, 255, 220)) text0 = '最终得分: %s' % score text1 = '按 R 键重新开始' y = 140 for idx, text in enumerate([text0, text1]): text_render = font.render(text, 1, (85, 65, 0)) rect = text_render.get_rect() if idx == 0: rect.left, rect.top = (100, y) elif idx == 1: rect.left, rect.top = (100, y) y += 60 screen.blit(text_render, rect) pygame.display.update()

看一下效果:



说完了游戏图形化界面相关的部分,我们再看一下游戏的主要处理逻辑。

我们通过鼠标来操纵拼图块,因此程序需要检查有无拼图块被选中,代码实现如下:

def checkSelected(self, position): for x in range(NUMGRID): for y in range(NUMGRID): if self.getGemByPos(x, y).rect.collidepoint(*position): return [x, y] return None

我们需要将鼠标连续选择的拼图块进行位置交换,代码实现如下:

def swapGem(self, gem1_pos, gem2_pos): margin = gem1_pos[0] - gem2_pos[0] + gem1_pos[1] - gem2_pos[1] if abs(margin) != 1: return False gem1 = self.getGemByPos(*gem1_pos) gem2 = self.getGemByPos(*gem2_pos) if gem1_pos[0] - gem2_pos[0] == 1: gem1.direction = 'left' gem2.direction = 'right' elif gem1_pos[0] - gem2_pos[0] == -1: gem2.direction = 'left' gem1.direction = 'right' elif gem1_pos[1] - gem2_pos[1] == 1: gem1.direction = 'up' gem2.direction = 'down' elif gem1_pos[1] - gem2_pos[1] == -1: gem2.direction = 'up' gem1.direction = 'down' gem1.target_x = gem2.rect.left gem1.target_y = gem2.rect.top gem1.fixed = False gem2.target_x = gem1.rect.left gem2.target_y = gem1.rect.top gem2.fixed = False self.all_gems[gem2_pos[0]][gem2_pos[1]] = gem1 self.all_gems[gem1_pos[0]][gem1_pos[1]] = gem2 return True

每一次交换拼图块时,我们需要判断是否有连续一样的三个及以上拼图块,代码实现如下:

def isMatch(self): for x in range(NUMGRID): for y in range(NUMGRID): if x + 2 < NUMGRID: if self.getGemByPos(x, y).type == self.getGemByPos(x+1, y).type == self.getGemByPos(x+2, y).type: return [1, x, y] if y + 2 < NUMGRID: if self.getGemByPos(x, y).type == self.getGemByPos(x, y+1).type == self.getGemByPos(x, y+2).type: return [2, x, y] return [0, x, y]

当出现三个及以上拼图块时,需要将这些拼图块消除,代码实现如下:

def removeMatched(self, res_match): if res_match[0] > 0: self.generateNewGems(res_match) self.score += self.reward return self.reward return 0

将匹配的拼图块消除之后,我们还需要随机生成新的拼图块,代码实现如下:

def generateNewGems(self, res_match): if res_match[0] == 1: start = res_match[2] while start > -2: for each in [res_match[1], res_match[1]+1, res_match[1]+2]: gem = self.getGemByPos(*[each, start]) if start == res_match[2]: self.gems_group.remove(gem) self.all_gems[each][start] = None elif start >= 0: gem.target_y += GRIDSIZE gem.fixed = False gem.direction = 'down' self.all_gems[each][start+1] = gem else: gem = Puzzle(img_path=random.choice(self.gem_imgs), size=(GRIDSIZE, GRIDSIZE), position=[XMARGIN+each*GRIDSIZE, YMARGIN-GRIDSIZE], downlen=GRIDSIZE) self.gems_group.add(gem) self.all_gems[each][start+1] = gem start -= 1 elif res_match[0] == 2: start = res_match[2] while start > -4: if start == res_match[2]: for each in range(0, 3): gem = self.getGemByPos(*[res_match[1], start+each]) self.gems_group.remove(gem) self.all_gems[res_match[1]][start+each] = None elif start >= 0: gem = self.getGemByPos(*[res_match[1], start]) gem.target_y += GRIDSIZE * 3 gem.fixed = False gem.direction = 'down' self.all_gems[res_match[1]][start+3] = gem else: gem = Puzzle(img_path=random.choice(self.gem_imgs), size=(GRIDSIZE, GRIDSIZE), position=[XMARGIN+res_match[1]*GRIDSIZE, YMARGIN+start*GRIDSIZE], downlen=GRIDSIZE*3) self.gems_group.add(gem) self.all_gems[res_match[1]][start+3] = gem start -= 1

之后反复执行这个过程,直至耗尽游戏时间,游戏结束。

最后,我们动态看一下游戏效果。



特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
今日最佳梗图?周冠宇赛车受损后被同为绿色的吊车吊离赛道

今日最佳梗图?周冠宇赛车受损后被同为绿色的吊车吊离赛道

懂球帝
2024-06-08 06:08:47
打不透铁血防守,何冰娇0-2安洗莹!女单四强出炉,国羽半壁江山

打不透铁血防守,何冰娇0-2安洗莹!女单四强出炉,国羽半壁江山

钉钉陌上花开
2024-06-07 18:13:54
豫西农民小麦收成情况考察报告:一亩小麦净收入800左右

豫西农民小麦收成情况考察报告:一亩小麦净收入800左右

玛丽姬丝
2024-06-07 15:53:16
记者:尤文新赛季主场球衣可能没有赞助商,俱乐部将损失5000万欧

记者:尤文新赛季主场球衣可能没有赞助商,俱乐部将损失5000万欧

直播吧
2024-06-08 06:40:07
中国股市又爆猛料,下周A股或将惊天巨浪,万千散户持有还是逃跑

中国股市又爆猛料,下周A股或将惊天巨浪,万千散户持有还是逃跑

静守时光落日
2024-06-08 01:24:21
当广州地铁允许个人投放广告,网友整活笑疯了

当广州地铁允许个人投放广告,网友整活笑疯了

4A广告网
2024-06-07 10:29:20
广汽集团:5月汽车销量同比下降25.33%

广汽集团:5月汽车销量同比下降25.33%

每日经济新闻
2024-06-07 17:40:04
克莱对勇士高管很生气!追梦言论也令他不满 魔术成下家头号热门

克莱对勇士高管很生气!追梦言论也令他不满 魔术成下家头号热门

罗说NBA
2024-06-08 08:59:10
海牙法院对俄罗斯宣传人员发出逮捕令

海牙法院对俄罗斯宣传人员发出逮捕令

亡海中的彼岸花
2024-06-07 08:59:52
高考通知引发众怒,过犹不及:要不让地球停转三天为高考让路?

高考通知引发众怒,过犹不及:要不让地球停转三天为高考让路?

六目先生
2024-06-06 09:25:48
“一丝不挂”新舞蹈?惹争议,被摸下体更不害臊,金星质疑是对的

“一丝不挂”新舞蹈?惹争议,被摸下体更不害臊,金星质疑是对的

吃鱼思故渊
2024-05-16 21:48:21
浙江一大师专给富婆算命,3年赚1800万,背后真相你绝对想不到!

浙江一大师专给富婆算命,3年赚1800万,背后真相你绝对想不到!

古今档案
2024-05-21 22:38:50
深圳楼市:买一送一,购房者傻眼了

深圳楼市:买一送一,购房者傻眼了

楼市诸葛
2024-06-08 07:00:03
知名港星移居奥地利,没工作只能吃老本,学两年外语仍难以交流

知名港星移居奥地利,没工作只能吃老本,学两年外语仍难以交流

八卦先生
2024-06-05 23:08:46
闹大了!红领巾的新系法是什么鬼?说没有内鬼我是不信的!

闹大了!红领巾的新系法是什么鬼?说没有内鬼我是不信的!

文雅笔墨
2024-06-05 18:24:32
谁能料到!那些年扎堆干金融的高考状元,如今全都凉凉了……

谁能料到!那些年扎堆干金融的高考状元,如今全都凉凉了……

毯叔盘钱
2024-06-07 15:53:21
日本女优的一天:14小时赶三场,幕后内情让人唏嘘

日本女优的一天:14小时赶三场,幕后内情让人唏嘘

听风听你
2024-06-05 22:06:06
大陆中止让利后,台当局突然迎来外援,赖清德总算抓到救命稻草?

大陆中止让利后,台当局突然迎来外援,赖清德总算抓到救命稻草?

莫将离
2024-06-06 22:43:33
闹大了!2024第一季度 华为与小米营收差距拉大1029亿 利润创新高

闹大了!2024第一季度 华为与小米营收差距拉大1029亿 利润创新高

沿路捡贝壳
2024-06-07 14:47:47
这可能是华为Pura 70败得最惨的一次

这可能是华为Pura 70败得最惨的一次

天才引路星
2024-06-07 23:10:58
2024-06-08 09:34:44
原画在线课堂vv
原画在线课堂vv
一家有温度的原画教育机构
378文章数 0关注度
往期回顾 全部

科技要闻

6家大模型抢答高考作文,谁是你心中的Top1

头条要闻

牛弹琴:普京积极出招 向美国后院派出最危险核潜艇

头条要闻

牛弹琴:普京积极出招 向美国后院派出最危险核潜艇

体育要闻

优势在我?中国足球有自己的节奏

娱乐要闻

汤唯抵达巴黎将担任奥运火炬手

财经要闻

身陷退市股的投资者:我的钱瞬间没了

汽车要闻

2.0T混动售20.98万元起 福特蒙迪欧运动版上市

态度原创

游戏
时尚
家居
本地
健康

《血源卡丁车》全平台下载量破20万:新补丁已发布

接下来几个月,比看赛事更有意思的是......

家居要闻

柔和婉转 让阳光洒满空间

本地新闻

我和我的家乡|踏浪营口,心动不止一夏!

晚餐不吃or吃七分饱,哪种更减肥?

无障碍浏览 进入关怀版