跳至主要內容

Python 消消乐

周子力大约 9 分钟教学文档Python

Python 消消乐

1.游戏简介

很久很久以前,在神秘的阿瑞亚大陆上,有一个被遗忘了很久的小岛,人们称它为“失落之岛”。这个岛屿被茂密的覆盖,其中充满了各种奇异的动植物和神秘的宝藏。这个岛屿的居民们过着平静而和谐的生活,直到有一天,一场突如其来的灾难打破了这份宁静。

这个灾难源于一种被称为“黑暗元素”的神秘力量。黑暗元素侵蚀了失落之岛的深处,引发了一场无法控制的魔法风暴。风暴席卷了整个岛屿,摧毁了无数的家园,迫使岛上的居民们逃离家园。

在这个危难时刻,一位名叫艾瑞克的年轻探险家站了出来。他带领着一支由勇敢的村民们组成的队伍,决定寻找失落的神秘力量,以恢复失落之岛的和平。

在他们的冒险旅程中,艾瑞克和他的队伍发现了一个神奇的地图碎片,这个碎片记录着失落之岛过去的光辉岁月,也隐藏着打开魔法风暴的秘密。通过破解地图碎片上的谜题和挑战,艾瑞克和他的队伍找到了一个古老的神秘宝藏——星星之石。这块石头具有强大的光明力量,可以对抗黑暗元素。

他们通过收集星星之石并组成特定图案,释放出强大的魔法能量,成功地击退了魔法风暴。然而,胜利的代价是他们发现了一种更强大的黑暗力量正在复苏——一个名叫“黑暗魔君”的邪恶生物正在酝酿一场更大的灾难。

为了阻止黑暗魔君的野心,艾瑞克和他的队伍开始了新一轮的冒险。他们必须寻找更多的星星之石,组成更强大的消除图案,才能击败黑暗魔君。在这个过程中,他们遇到了各种挑战和困难,但他们从未放弃,一直坚持下去。

经过无数次的冒险和战斗,艾瑞克和他的队伍终于找到了所有剩余的星星之石,并组成了最强大的消除图案——三消四连。这个消除图案释放出了强大的光明能量,成功地击败了黑暗魔君。在胜利的那一刻,艾瑞克和他的队伍得到了众神的祝福,他们得到了守护失落之岛的力量。

从此以后,失落之岛恢复了往日的宁静与和平。艾瑞克和他的队伍成为了失落之岛的守护者,他们用智慧和勇气守护着这片土地上的生灵。而开心消消乐游戏也成为了失落之岛的传统,每个岛民都可以通过游戏锻炼自己的思维能力和手眼协调能力,同时也可以为失落之岛的和平做出一份贡献。

在游戏中,玩家需要利用各种道具和特效来组合相同颜色的方块,消除并收集尽可能多的星星。随着游戏的进展,玩家还将解锁更多有趣的关卡和角色,并参与到各种有趣的活动和中。这些活动和不仅可以让玩家享受到游戏的乐趣,还可以为失落之岛的繁荣做出贡献。

总的来说,开心消消乐游戏是一个充满冒险和挑战的故事。在这个故事中,玩家不仅可以享受到游戏的乐趣,还可以为失落之岛的和平做出一份贡献。同时,这个游戏也展现了友谊、勇气和智慧的力量,这些品质将一直激励着玩家在未来的生活中不断前行。

2.需求分析

picture 2
picture 2
picture 3
picture 3

2.1游戏界面

  • 大小
  • 标题
  • 钻石方格(大小,线宽,数量)
  • 分数显示
  • 时间显示
  • 游戏状态显示

2.2 钻石

2.2.1 属性

  • 种类
  • 大小
  • 坐标
  • 速度
  • 移动方向
  • 目标位置
  • 移动距离

2.2.2 动作

  • 移动
  • 获取位置
  • 位置赋值

2.3 控制

  • 拖动钻石
  • 钻石消失
  • 钻石补充

3.游戏设计

3.1 游戏映射

  • 背景映射(背景通常不变,一些数据可以用常数来表示,而这些常数可以放在一个文件里面。
    • 界面宽,高 用常量表示
    • 界面颜色,用元组表示
    • 钻子格式大小与数量,用常量表示
    • 分数,时间等数字显示通过是变量来表示
  • 钻石映射
    • 钻石可以看作精灵,可以创建精灵类,类属性对应钻石的特征
    • 钻石方格可以用矩阵来对应,即用二维数据来表示
    • 钻石是否可以消除,以及钻石的消失都可以对二组数组进行操作。

3.2配置文件

  • 配置文件config.py
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
  • 钻石精灵类 gemmodel.py
import pygame

class gemSprite(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) #把钻石图谱的大小进行转换,转换成size大小,有长有宽,是个元组
        self.rect = self.image.get_rect() #获取钻石片的边框信息
        self.rect.left,self.rect.top=position #钻石的左上坐标赋值,用于定位图片
        self.target_x = position[0]
        self.target_y = position[1]+downlen #是钻石要达到的位置
        self.downlen = downlen #下落的距离
        self.type = img_path.split('/')[-1].split('.')[0] #获取钻石样式
        self.fixed = False #钻石是否可以游戏的标志
        self.speed_x = 10
        self.speed_y = 10 #钻石移动的速度,包括x和y方向的速度。
        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


  • 游戏控制文件 game.py
import random
import sys
from gemmodel import *
class gemGame():
    #构造函数
    def __init__(self,screen,font,gem_images,cfg,**kwargs):
        self.screen = screen
        self.font = font
        self.gem_images = gem_images
        self.cfg = cfg
        self.reset()

    #游戏开始时的初始化过程
    def reset(self):
        while True:
            self.all_gems = []
            self.gem_group =pygame.sprite.Group()
            for x in range(self.cfg.NUMGRID):
                self.all_gems.append([])
                for y in range(self.cfg.NUMGRID):
                    gem = gemSprite(img_path=random.choice(self.gem_images),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_gems[x].append(gem)
                    self.gem_group.add(gem)
            if self.isMatch()[0] == 0:
                break
        # 得分
        self.score = 0
        # 拼出一个的奖励
        self.reward = 10
        # 时间
        self.remaining_time = 300

    #游戏主函数
    def run(self):
        clock = pygame.time.Clock()
        #对整个游戏界面中的钻石的位置进行更新的标志
        overall_moving = True
        #指定某些对象个体更新位置
        individual_moving =False

        #点击第一个钻石时,获取的坐标
        gem_selected_xy1 =None

        #点击第二个钻石时,获取的坐标
        gem_selected_xy2 = None

        swap_again = False

        #增加分数时的动作刷新
        add_score = 0


        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):
                        postion = pygame.mouse.get_pos()
                        if gem_selected_xy1 is None:
                            gem_selected_xy1 = self.checkSelected(postion)
                        else:
                            gem_selected_xy2 = self.checkSelected(postion)
                            if gem_selected_xy2:
                                if self.swapGem(gem_selected_xy1, gem_selected_xy2):
                                    individual_moving = True
                                    swap_again = False
                                else:
                                    gem_selected_xy1 = None

            if overall_moving :
                overall_moving = not self.dropGems(0,0)
                if not overall_moving:
                    res_match = self.isMatch()
                    add_score = self.removeMatched(res_match)
                    if add_score>0:
                        overall_moving = True


            if individual_moving:
                gem1 = self.getgemByPos(*gem_selected_xy1)
                gem2 = self.getgemByPos(*gem_selected_xy2)
                gem1.move()
                gem2.move()
                if gem1.fixed and gem2.fixed:
                    res_match = self.isMatch()

                    if res_match[0] == 0 and not swap_again:
                        swap_again = True
                        self.swapGem(gem_selected_xy1,gem_selected_xy2)
                    else:
                        add_score = self.removeMatched(res_match)
                        overall_moving = True
                        individual_moving = False
                        gem_selected_xy1 = None
                        gem_selected_xy2 = None




            self.screen.fill((135, 206, 235))
            self.drawGrid()
            self.gem_group.draw(self.screen)
            if gem_selected_xy1:
                self.drawBlock(self.getgemByPos(*gem_selected_xy1).rect)
            pygame.display.update()
            clock.tick(self.cfg.FPS)

    #画钻石方格
    def drawGrid(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))
                pygame.draw.rect(self.screen,(0,0,255),rect,1 )

    #返回选中的钻石的坐标
    def checkSelected(self,postion):
        for x in range(self.cfg.NUMGRID):
            for y in range(self.cfg.NUMGRID):
                if self.getgemByPos(x,y).rect.collidepoint(*postion):
                    return [x,y]
        return None

    #根据坐标,返回钻石精灵
    def getgemByPos(self,x,y):
        return self.all_gems[x][y]

    #查看是否有三个连在一起的钻石,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.getgemByPos(x,y).type == self.getgemByPos(x+1,y).type == self.getgemByPos(x+2,y).type:
                        return [1,x,y]
                if y+2 < self.cfg.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 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'

        if gem1_pos[0]-gem2_pos[0] == -1:
            gem1.direction = 'right'
            gem2.direction = 'left'

        if gem1_pos[1]-gem2_pos[1] == 1:
            gem1.direction = 'up'
            gem2.direction = 'down'

        if gem1_pos[1]-gem2_pos[1] == -1:
            gem1.direction = 'down'
            gem2.direction = 'up'

        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[gem1_pos[0]][gem1_pos[1]]=gem2
        self.all_gems[gem2_pos[0]][gem2_pos[1]]=gem1
        return True

    #画方框,用于标识选中的钻石
    def drawBlock(self, block, color=(255, 0, 255), size=4):
        pygame.draw.rect(self.screen, color, block, size)

    #钻石下落
    def dropGems(self,x,y):
        if not self.getgemByPos(x,y).fixed:
            self.getgemByPos(x,y).move()
        if x<self.cfg.NUMGRID -1:
            x+=1
            return self.dropGems(x,y)
        elif y<self.cfg.NUMGRID -1:
            x=0
            y+=1
            return self.dropGems(x,y)
        else:
            return self.isFull()

    #检查是不是方程里面全是fixed的钻石,如果是,返回True
    def isFull(self):
        for x in range(self.cfg.NUMGRID):
            for y in range(self.cfg.NUMGRID):
                if not self.getgemByPos(x, y).fixed:
                    return False
        return True

    #移除匹配的钻石,并赋与分数
    def removeMatched(self,res_match):
        if res_match[0]>0:
            self.genNewGem(res_match)
            self.score += self.reward
            return self.reward
        return 0

    #当三个连在一起的时候,消除钻石,将上面的钻石下落,并产生新的钻石。
    def genNewGem(self,res_match):
        if res_match[0] == 1:
            start = res_match[2]
            while start > -2:

                for e in [res_match[1],res_match[1]+1,res_match[1]+2]:
                    gem = self.getgemByPos(*[e,start])
                    if start == res_match[2]:
                        self.gem_group.remove(gem)
                        self.all_gems[e][start]=None
                    elif start >=0:
                        gem.target_y+=self.cfg.GRIDSIZE
                        gem.fixed = False
                        gem.direction = 'down'
                        self.all_gems[e][start+1] = gem
                    else:
                        gem = gemSprite(img_path=random.choice(self.gem_images),
                                        size=(self.cfg.GRIDSIZE,self.cfg.GRIDSIZE),
                                        position=[self.cfg.XMARGIN + e * self.cfg.GRIDSIZE,
                                                      self.cfg.YMARGIN - self.cfg.GRIDSIZE],
                                        downlen=self.cfg.GRIDSIZE)
                        self.gem_group.add(gem)
                        self.all_gems[e][start+1] = gem

                start-=1

        elif res_match[0] == 2:
            start = res_match[2]
            while start>-4:
                if start==res_match[2]:
                    for e in range(0,3):
                        gem = self.getgemByPos(*[res_match[1],start+e])
                        self.gem_group.remove(gem)
                        self.all_gems[res_match[1]][start+e]=None
                elif start >= 0:
                    gem = self.getgemByPos(*[res_match[1],start])
                    gem.target_y+=self.cfg.GRIDSIZE*3
                    gem.fixed = False
                    gem.direction = 'down'
                    self.all_gems[res_match[1]][start+3]=gem
                else:
                    gem = gemSprite(img_path=random.choice(self.gem_images),
                                    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.gem_group.add(gem)
                    self.all_gems[res_match[1]][start+3] = gem
                start -= 1
  • 主文件 main.py
import os
import config as cfg
from game import *


def main():
    pygame.init()
    screen = pygame.display.set_mode(cfg.SCREENSIZE)
    pygame.display.set_caption('网安消消乐')
    font = pygame.font.Font('freesansbold.ttf')

    gem_images = []
    for i in range(1,8):
        gem_images.append(os.path.join(cfg.ROOTDIR, 'imgs\gem%s.png' % i))
    gem_game = gemGame(screen, font, gem_images, cfg)
    gem_game.run()

if __name__ == '__main__':
    main()

上次编辑于:
贡献者: zilizhou,unknown