使用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实现压缩与解压gzip大文件的方法
Sep 18 Python
python opencv 二值化 计算白色像素点的实例
Jul 03 Python
Django中如何使用sass的方法步骤
Jul 09 Python
Django 开发环境与生产环境的区分详解
Jul 26 Python
PyTorch和Keras计算模型参数的例子
Jan 02 Python
python 解决tqdm模块不能单行显示的问题
Feb 19 Python
Python应用实现双指数函数及拟合代码实例
Jun 19 Python
PyTorch中model.zero_grad()和optimizer.zero_grad()用法
Jun 24 Python
Pycharm快捷键配置详细整理
Oct 13 Python
pygame面向对象的飞行小鸟实现(Flappy bird)
Apr 01 Python
Python操作CSV格式文件的方法大全
Jul 15 Python
利用Python脚本写端口扫描器socket,python-nmap
Jul 23 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函数array_merge用法一例(合并同类数组)
2013/02/03 PHP
php设计模式之单例、多例设计模式的应用分析
2013/06/30 PHP
JS 日期验证正则附asp日期格式化函数
2009/09/11 Javascript
IE事件对象(The Internet Explorer Event Object)
2012/06/27 Javascript
chrome不支持form.submit的解决方案
2015/04/28 Javascript
javascript实现完美拖拽效果
2015/05/06 Javascript
js实现动态加载脚本的方法实例汇总
2015/11/02 Javascript
JS实现网页上随机产生超链接地址的方法
2015/11/09 Javascript
Node.js的npm包管理器基础使用教程
2016/05/26 Javascript
微信小程序开发探究
2016/12/27 Javascript
通过BootStrap-select插件 js jQuery控制select属性变化
2017/01/03 Javascript
关于不同页面之间实现参数传递的几种方式讨论
2017/02/13 Javascript
使用travis-ci如何持续部署node.js应用详解
2017/07/30 Javascript
vue2中使用less简易教程
2018/03/27 Javascript
基于Vue的侧边目录组件的实现
2020/02/05 Javascript
[05:17]DOTA2誓师:今天我们在这里 明天TI4等我!
2014/03/26 DOTA
在Python中处理XML的教程
2015/04/29 Python
python中argparse模块用法实例详解
2015/06/03 Python
Python温度转换实例分析
2018/01/17 Python
python笔记_将循环内容在一行输出的方法
2019/08/08 Python
Python一行代码解决矩阵旋转的问题
2019/11/30 Python
python和pywin32实现窗口查找、遍历和点击的示例代码
2020/04/01 Python
Python坐标轴操作及设置代码实例
2020/06/04 Python
Python sqlalchemy时间戳及密码管理实现代码详解
2020/08/01 Python
CSS3 background-image颜色渐变的实现代码
2018/09/13 HTML / CSS
HTML5实现移动端弹幕动画效果
2019/08/01 HTML / CSS
HTML5去掉输入框type为number时的上下箭头的实现方法
2020/01/03 HTML / CSS
关于Java String的一道面试题
2013/09/29 面试题
综合测评自我鉴定
2013/10/08 职场文书
餐饮业会计岗位职责
2013/12/19 职场文书
文明和谐家庭事迹材料
2014/05/18 职场文书
家庭教育的心得体会
2014/09/01 职场文书
商铺租房协议书范本
2014/12/04 职场文书
英文慰问信范文
2015/03/24 职场文书
施工安全保证书
2015/05/09 职场文书
赞助商致辞
2015/07/30 职场文书