使用python+pygame开发消消乐游戏附完整源码


Posted in Python onJune 10, 2021

效果是这样的 ↓ ↓ ↓

使用python+pygame开发消消乐游戏附完整源码 

一、环境要求

windows系统,python3.6+ pip21+

开发环境搭建地址

一起来学pygame吧 游戏开发30例(开篇词)——环境搭建+游戏效果展示

安装游戏依赖模块
pip install pygame

二、游戏简介

消消乐应该大家都玩过,或者看过。这个花里胡哨的小游戏

用python的pygame来实现,很简单。

今天带大家,用Python来实现一下这个花里胡哨的小游戏。

三、完整开发流程

1、项目主结构

首先,先整理一下项目的主结构,其实看一下主结构,基本就清晰了

modules:相关定义的Python类位置
——game.py:主模块
 
res:存放引用到的图片、音频等等
——audios:音频资源
——imgs:图片资源
——fonts:字体
 
cfg.py:为主配置文件
 
xxls.py:主程序文件
 
requirements.txt:需要引入的python依赖包

使用python+pygame开发消消乐游戏附完整源码

2、详细配置

cfg.py

配置文件中,需要引入os模块,并且配置打开游戏的屏幕大小。

'''主配置文件'''
import os
 
'''屏幕设置大小'''
SCREENSIZE = (700, 700)
'''元素尺寸'''
NUMGRID = 8
GRIDSIZE = 64
XMARGIN = (SCREENSIZE[0] - GRIDSIZE * NUMGRID) // 2
YMARGIN = (SCREENSIZE[1] - GRIDSIZE * NUMGRID) // 2
'''获取根目录'''
ROOTDIR = os.getcwd()
'''FPS'''
FPS = 30

3、消消乐所有图形加载

game.py:第一部分

把整个项目放在一整个game.py模块下了,把这个代码文件拆开解读一下。

拼图精灵类:首先通过配置文件中,获取方块精灵的路径,加载到游戏里。

定义move()移动模块的函数,这个移动比较简单。模块之间,只有相邻的可以相互移动。

'''
Function:
    主游戏
'''
import sys
import time
import random
import pygame
 
 
'''拼图精灵类'''
class pacerSprite(pygame.sprite.Sprite):
    def __init__(self, img_path, size, position, downlen, **kwargs):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.image.load(img_path)
        self.image = pygame.transform.smoothscale(self.image, size)
        self.rect = self.image.get_rect()
        self.rect.left, self.rect.top = position
        self.downlen = downlen
        self.target_x = position[0]
        self.target_y = position[1] + downlen
        self.type = img_path.split('/')[-1].split('.')[0]
        self.fixed = False
        self.speed_x = 9
        self.speed_y = 9
        self.direction = 'down'
    def move(self):
                #下移
        if self.direction == 'down':
            self.rect.top = min(self.target_y, self.rect.top+self.speed_y)
            if self.target_y == self.rect.top:
                self.fixed = True
                #上移
        elif self.direction == 'up':
            self.rect.top = max(self.target_y, self.rect.top-self.speed_y)
            if self.target_y == self.rect.top:
                self.fixed = True
                #左移
        elif self.direction == 'left':
            self.rect.left = max(self.target_x, self.rect.left-self.speed_x)
            if self.target_x == self.rect.left:
                self.fixed = True
                #右移
        elif self.direction == 'right':
            self.rect.left = min(self.target_x, self.rect.left+self.speed_x)
            if self.target_x == self.rect.left:
                self.fixed = True
    '''获取当前坐标'''
    def getPosition(self):
        return self.rect.left, self.rect.top
    '''设置星星坐标'''
    def setPosition(self, position):
        self.rect.left, self.rect.top = position

4、随机生成初始布局、相邻消除、自动下落

game.py 第二部分

设置游戏主窗口启动的标题,设置启动游戏的主方法。

'''主游戏类'''
class pacerGame():
    def __init__(self, screen, sounds, font, pacer_imgs, cfg, **kwargs):
        self.info = 'pacer'
        self.screen = screen
        self.sounds = sounds
        self.font = font
        self.pacer_imgs = pacer_imgs
        self.cfg = cfg
        self.reset()
    '''开始游戏'''
    def start(self):
        clock = pygame.time.Clock()
        # 遍历整个游戏界面更新位置
        overall_moving = True
        # 指定某些对象个体更新位置
        individual_moving = False
        # 定义一些必要的变量
        pacer_selected_xy = None
        pacer_selected_xy2 = None
        swap_again = False
        add_score = 0
        add_score_showtimes = 10
        time_pre = int(time.time())
        # 游戏主循环
        while True:
            for event in pygame.event.get():
                if event.type == pygame.QUIT or (event.type == pygame.KEYUP and event.key == pygame.K_ESCAPE):
                    pygame.quit()
                    sys.exit()
                elif event.type == pygame.MOUSEBUTTONUP:
                    if (not overall_moving) and (not individual_moving) and (not add_score):
                        position = pygame.mouse.get_pos()
                        if pacer_selected_xy is None:
                            pacer_selected_xy = self.checkSelected(position)
                        else:
                            pacer_selected_xy2 = self.checkSelected(position)
                            if pacer_selected_xy2:
                                if self.swappacer(pacer_selected_xy, pacer_selected_xy2):
                                    individual_moving = True
                                    swap_again = False
                                else:
                                    pacer_selected_xy = None
            if overall_moving:
                overall_moving = not self.droppacers(0, 0)
                # 移动一次可能可以拼出多个3连块
                if not overall_moving:
                    res_match = self.isMatch()
                    add_score = self.removeMatched(res_match)
                    if add_score > 0:
                        overall_moving = True
            if individual_moving:
                pacer1 = self.getpacerByPos(*pacer_selected_xy)
                pacer2 = self.getpacerByPos(*pacer_selected_xy2)
                pacer1.move()
                pacer2.move()
                if pacer1.fixed and pacer2.fixed:
                    res_match = self.isMatch()
                    if res_match[0] == 0 and not swap_again:
                        swap_again = True
                        self.swappacer(pacer_selected_xy, pacer_selected_xy2)
                        self.sounds['mismatch'].play()
                    else:
                        add_score = self.removeMatched(res_match)
                        overall_moving = True
                        individual_moving = False
                        pacer_selected_xy = None
                        pacer_selected_xy2 = None
            self.screen.fill((135, 206, 235))
            self.drawGrids()
            self.pacers_group.draw(self.screen)
            if pacer_selected_xy:
                self.drawBlock(self.getpacerByPos(*pacer_selected_xy).rect)
            if add_score:
                if add_score_showtimes == 10:
                    random.choice(self.sounds['match']).play()
                self.drawAddScore(add_score)
                add_score_showtimes -= 1
                if add_score_showtimes < 1:
                    add_score_showtimes = 10
                    add_score = 0
            self.remaining_time -= (int(time.time()) - time_pre)
            time_pre = int(time.time())
            self.showRemainingTime()
            self.drawScore()
            if self.remaining_time <= 0:
                return self.score
            pygame.display.update()
            clock.tick(self.cfg.FPS)

5、随机初始化消消乐的主图内容

game.py 第三部分

详细注释,都写在代码里了。大家一定要看一遍,不要跑起来,就不管了哦

'''初始化'''
    def reset(self):
        # 随机生成各个块(即初始化游戏地图各个元素)
        while True:
            self.all_pacers = []
            self.pacers_group = pygame.sprite.Group()
            for x in range(self.cfg.NUMGRID):
                self.all_pacers.append([])
                for y in range(self.cfg.NUMGRID):
                    pacer = pacerSprite(img_path=random.choice(self.pacer_imgs), size=(self.cfg.GRIDSIZE, self.cfg.GRIDSIZE), position=[self.cfg.XMARGIN+x*self.cfg.GRIDSIZE, self.cfg.YMARGIN+y*self.cfg.GRIDSIZE-self.cfg.NUMGRID*self.cfg.GRIDSIZE], downlen=self.cfg.NUMGRID*self.cfg.GRIDSIZE)
                    self.all_pacers[x].append(pacer)
                    self.pacers_group.add(pacer)
            if self.isMatch()[0] == 0:
                break
        # 得分
        self.score = 0
        # 拼出一个的奖励
        self.reward = 10
        # 时间
        self.remaining_time = 300
    '''显示剩余时间'''
    def showRemainingTime(self):
        remaining_time_render = self.font.render('CountDown: %ss' % str(self.remaining_time), 1, (85, 65, 0))
        rect = remaining_time_render.get_rect()
        rect.left, rect.top = (self.cfg.SCREENSIZE[0]-201, 6)
        self.screen.blit(remaining_time_render, rect)
    '''显示得分'''
    def drawScore(self):
        score_render = self.font.render('SCORE:'+str(self.score), 1, (85, 65, 0))
        rect = score_render.get_rect()
        rect.left, rect.top = (10, 6)
        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 generateNewpacers(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]:
                    pacer = self.getpacerByPos(*[each, start])
                    if start == res_match[2]:
                        self.pacers_group.remove(pacer)
                        self.all_pacers[each][start] = None
                    elif start >= 0:
                        pacer.target_y += self.cfg.GRIDSIZE
                        pacer.fixed = False
                        pacer.direction = 'down'
                        self.all_pacers[each][start+1] = pacer
                    else:
                        pacer = pacerSprite(img_path=random.choice(self.pacer_imgs), size=(self.cfg.GRIDSIZE, self.cfg.GRIDSIZE), position=[self.cfg.XMARGIN+each*self.cfg.GRIDSIZE, self.cfg.YMARGIN-self.cfg.GRIDSIZE], downlen=self.cfg.GRIDSIZE)
                        self.pacers_group.add(pacer)
                        self.all_pacers[each][start+1] = pacer
                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):
                        pacer = self.getpacerByPos(*[res_match[1], start+each])
                        self.pacers_group.remove(pacer)
                        self.all_pacers[res_match[1]][start+each] = None
                elif start >= 0:
                    pacer = self.getpacerByPos(*[res_match[1], start])
                    pacer.target_y += self.cfg.GRIDSIZE * 3
                    pacer.fixed = False
                    pacer.direction = 'down'
                    self.all_pacers[res_match[1]][start+3] = pacer
                else:
                    pacer = pacerSprite(img_path=random.choice(self.pacer_imgs), size=(self.cfg.GRIDSIZE, self.cfg.GRIDSIZE), position=[self.cfg.XMARGIN+res_match[1]*self.cfg.GRIDSIZE, self.cfg.YMARGIN+start*self.cfg.GRIDSIZE], downlen=self.cfg.GRIDSIZE*3)
                    self.pacers_group.add(pacer)
                    self.all_pacers[res_match[1]][start+3] = pacer
                start -= 1
    '''移除匹配的pacer'''
    def removeMatched(self, res_match):
        if res_match[0] > 0:
            self.generateNewpacers(res_match)
            self.score += self.reward
            return self.reward
        return 0
    '''游戏界面的网格绘制'''
    def drawGrids(self):
        for x in range(self.cfg.NUMGRID):
            for y in range(self.cfg.NUMGRID):
                rect = pygame.Rect((self.cfg.XMARGIN+x*self.cfg.GRIDSIZE, self.cfg.YMARGIN+y*self.cfg.GRIDSIZE, self.cfg.GRIDSIZE, self.cfg.GRIDSIZE))
                self.drawBlock(rect, color=(0, 0, 255), size=1)
    '''画矩形block框'''
    def drawBlock(self, block, color=(255, 0, 255), size=4):
        pygame.draw.rect(self.screen, color, block, size)
    '''下落特效'''
    def droppacers(self, x, y):
        if not self.getpacerByPos(x, y).fixed:
            self.getpacerByPos(x, y).move()
        if x < self.cfg.NUMGRID - 1:
            x += 1
            return self.droppacers(x, y)
        elif y < self.cfg.NUMGRID - 1:
            x = 0
            y += 1
            return self.droppacers(x, y)
        else:
            return self.isFull()
    '''是否每个位置都有拼图块了'''
    def isFull(self):
        for x in range(self.cfg.NUMGRID):
            for y in range(self.cfg.NUMGRID):
                if not self.getpacerByPos(x, y).fixed:
                    return False
        return True
    '''检查有无拼图块被选中'''
    def checkSelected(self, position):
        for x in range(self.cfg.NUMGRID):
            for y in range(self.cfg.NUMGRID):
                if self.getpacerByPos(x, y).rect.collidepoint(*position):
                    return [x, y]
        return None
    '''是否有连续一样的三个块(无--返回0/水平--返回1/竖直--返回2)'''
    def isMatch(self):
        for x in range(self.cfg.NUMGRID):
            for y in range(self.cfg.NUMGRID):
                if x + 2 < self.cfg.NUMGRID:
                    if self.getpacerByPos(x, y).type == self.getpacerByPos(x+1, y).type == self.getpacerByPos(x+2, y).type:
                        return [1, x, y]
                if y + 2 < self.cfg.NUMGRID:
                    if self.getpacerByPos(x, y).type == self.getpacerByPos(x, y+1).type == self.getpacerByPos(x, y+2).type:
                        return [2, x, y]
        return [0, x, y]
    '''根据坐标获取对应位置的拼图对象'''
    def getpacerByPos(self, x, y):
        return self.all_pacers[x][y]
    '''交换拼图'''
    def swappacer(self, pacer1_pos, pacer2_pos):
        margin = pacer1_pos[0] - pacer2_pos[0] + pacer1_pos[1] - pacer2_pos[1]
        if abs(margin) != 1:
            return False
        pacer1 = self.getpacerByPos(*pacer1_pos)
        pacer2 = self.getpacerByPos(*pacer2_pos)
        if pacer1_pos[0] - pacer2_pos[0] == 1:
            pacer1.direction = 'left'
            pacer2.direction = 'right'
        elif pacer1_pos[0] - pacer2_pos[0] == -1:
            pacer2.direction = 'left'
            pacer1.direction = 'right'
        elif pacer1_pos[1] - pacer2_pos[1] == 1:
            pacer1.direction = 'up'
            pacer2.direction = 'down'
        elif pacer1_pos[1] - pacer2_pos[1] == -1:
            pacer2.direction = 'up'
            pacer1.direction = 'down'
        pacer1.target_x = pacer2.rect.left
        pacer1.target_y = pacer2.rect.top
        pacer1.fixed = False
        pacer2.target_x = pacer1.rect.left
        pacer2.target_y = pacer1.rect.top
        pacer2.fixed = False
        self.all_pacers[pacer2_pos[0]][pacer2_pos[1]] = pacer1
        self.all_pacers[pacer1_pos[0]][pacer1_pos[1]] = pacer2
        return True
    '''信息显示'''
    def __repr__(self):
        return self.info

5、资源相关

包括游戏背景音频、图片和字体设计

res主资源目录

audios:加载游戏背景音乐

fonts:记分牌相关字体

imgs:这里存放的是我们的各种小星星的图形,是关键了的哦。如果这个加载不了,

我们的消消乐 就没有任何图形了

6、启动主程序

xxls.py

在主程序中,通过读取配置文件,引入项目资源:包括图片、音频等,并从我们的modules里引入所有我们的模块。

'''
Function:
    消消乐
'''
import os
import sys
import cfg
import pygame
from modules import *
 
 
'''主程序'''
def main():
    pygame.init()
    screen = pygame.display.set_mode(cfg.SCREENSIZE)
    pygame.display.set_caption('hacklex')
    # 加载背景音乐
    pygame.mixer.init()
    pygame.mixer.music.load(os.path.join(cfg.ROOTDIR, "res/audios/bg.mp3"))
    pygame.mixer.music.set_volume(0.6)
    pygame.mixer.music.play(-1)
    # 加载音效
    sounds = {}
    sounds['mismatch'] = pygame.mixer.Sound(os.path.join(cfg.ROOTDIR, 'res/audios/badswap.wav'))
    sounds['match'] = []
    for i in range(6):
        sounds['match'].append(pygame.mixer.Sound(os.path.join(cfg.ROOTDIR, 'res/audios/match%s.wav' % i)))
 
    # 字体显示
    font = pygame.font.Font(os.path.join(cfg.ROOTDIR, 'res/font/font.TTF'), 25)
    # 星星
    pacer_imgs = []
    for i in range(1, 8):
        pacer_imgs.append(os.path.join(cfg.ROOTDIR, 'res/imgs/pacer%s.png' % i))
    # 循环
    game = pacerGame(screen, sounds, font, pacer_imgs, cfg)
    while True:
        score = game.start()
        flag = False
        # 给出选择,玩家选择重玩或者退出
        while True:
            for event in pygame.event.get():
                if event.type == pygame.QUIT or (event.type == pygame.KEYUP and event.key == pygame.K_ESCAPE):
                    pygame.quit()
                    sys.exit()
                elif event.type == pygame.KEYUP and event.key == pygame.K_r:
                    flag = True
            if flag:
                break
            screen.fill((136, 207, 236))
            text0 = 'Final score: %s' % score
            text1 = 'Press <R> to restart the game.'
            text2 = 'Press <Esc> to quit the game.'
            y = 150
            for idx, text in enumerate([text0, text1, text2]):
                text_render = font.render(text, 1, (85, 65, 0))
                rect = text_render.get_rect()
                if idx == 0:
                    rect.left, rect.top = (223, y)
                elif idx == 1:
                    rect.left, rect.top = (133.5, y)
                else:
                    rect.left, rect.top = (126.5, y)
                y += 99
                screen.blit(text_render, rect)
            pygame.display.update()
        game.reset()
 
 
'''游戏运行'''
if __name__ == '__main__':
    main()

四、如何启动游戏呢?

1、使用开发工具IDE启动

如果的开发工具IDE的环境

例如:VScode、sublimeText、notepad+

pycharm什么的配置了Python环境

可以直接在工具中,运行该游戏。

2、命令行启动

如下图所示

使用python+pygame开发消消乐游戏附完整源码

以上就是使用python开发消消乐游戏流程分析 附完整源码的详细内容,更多关于python消消乐游戏的资料请关注三水点靠木其它相关文章!

Python 相关文章推荐
Python+微信接口实现运维报警
Aug 27 Python
python模块简介之有序字典(OrderedDict)
Dec 01 Python
python 根据正则表达式提取指定的内容实例详解
Dec 04 Python
Python使用win32com实现的模拟浏览器功能示例
Jul 13 Python
利用Python实现在同一网络中的本地文件共享方法
Jun 04 Python
python实现简易数码时钟
Feb 19 Python
Python使用pandas对数据进行差分运算的方法
Dec 22 Python
在Python文件中指定Python解释器的方法
Feb 18 Python
Pandas中resample方法详解
Jul 02 Python
Django接收照片储存文件的实例代码
Mar 07 Python
python框架Django实战商城项目之工程搭建过程图文详解
Mar 09 Python
解决Jupyter-notebook不弹出默认浏览器的问题
Mar 30 Python
Python数据可视化之基于pyecharts实现的地理图表的绘制
python使用PySimpleGUI设置进度条及控件使用
python3+PyQt5+Qt Designer实现界面可视化
Django使用echarts进行可视化展示的实践
教你如何使用Python Tkinter库制作记事本
Jun 10 #Python
Python中常见的反爬机制及其破解方法总结
Jun 10 #Python
Pytorch可视化的几种实现方法
You might like
php递归创建和删除文件夹的代码小结
2012/04/13 PHP
分享PHP header函数使用教程
2013/09/05 PHP
PHP 抽象方法与抽象类abstract关键字介绍及应用
2014/10/16 PHP
百度工程师讲PHP函数的实现原理及性能分析(一)
2015/05/13 PHP
深入剖析PHP中printf()函数格式化使用
2016/05/23 PHP
PHP基于mcript扩展实现对称加密功能示例
2019/02/21 PHP
尽可能写&quot;友好&quot;的&quot;Javascript&quot;代码
2007/01/09 Javascript
Jquery 滑入滑出效果实现代码
2010/03/27 Javascript
juqery 学习之五 文档处理 包裹、替换、删除、复制
2011/02/11 Javascript
js实现无需数据库的县级以上联动行政区域下拉控件
2013/08/14 Javascript
js获取或设置当前窗口url参数的小例子
2013/10/14 Javascript
javascript获取xml节点的最大值(实现代码)
2013/12/11 Javascript
jquery自定义函数的多种方法
2014/01/09 Javascript
JavaScript的jQuery库中ready方法的学习教程
2015/08/14 Javascript
JavaScript验证知识整理
2017/03/24 Javascript
vue 实现图片懒加载功能
2020/12/31 Vue.js
[45:25]OG vs EG 2019国际邀请赛淘汰赛 胜者组 BO3 第一场 8.22
2019/09/05 DOTA
介绍Python的@property装饰器的用法
2015/04/28 Python
Python实现控制台进度条功能
2016/01/04 Python
python实现根据文件关键字进行切分为多个文件的示例
2018/12/10 Python
python交易记录整合交易类详解
2019/07/03 Python
DataFrame.groupby()所见的各种用法详解
2020/06/14 Python
The Hut美国/加拿大:英国领先的豪华在线百货商店
2019/03/26 全球购物
鞋类设计与工艺专业销售求职信
2013/11/01 职场文书
董事长职责范文
2013/11/08 职场文书
DIY手工制作经营店创业计划书
2014/02/01 职场文书
优秀志愿者事迹材料
2014/02/03 职场文书
青年文明号创建承诺
2014/03/31 职场文书
2014年合同管理工作总结
2014/12/02 职场文书
乡镇法制宣传日活动总结
2015/05/05 职场文书
单位政审意见范文
2015/06/04 职场文书
2015入党自传格式范文
2015/06/26 职场文书
python开发实时可视化仪表盘的示例
2021/05/07 Python
pytorch中的numel函数用法说明
2021/05/13 Python
Redis高级数据类型Hyperloglog、Bitmap的使用
2021/05/24 Redis
ES6 解构赋值的原理及运用
2021/05/25 Javascript