前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >python连连看与记忆翻牌游戏(2)

python连连看与记忆翻牌游戏(2)

作者头像
叶子陪你玩
发布2022-05-22 15:04:16
1.2K0
发布2022-05-22 15:04:16
举报

上篇python连连看与记忆翻牌游戏(1)讲了连连看的核心判断实现。(最后的remove边界判断有点问题,没有先判断两者是否相等。感谢@井老师提醒)

原来的:

代码语言:javascript
复制
def remove(p1,p2):
    # p1 和 p2 都在边界,可以直接删除
    if (p1[0] == p2[0]) and (p1[0]==0 or p1[0]==len(array)-1):
        print('上下边界可以直接删除')
    elif (p1[1] == p2[1]) and (p1[1]==0 or p1[1]==len(array[0])-1):
        print('上下边界可以直接删除')

这里直接前面加一句判断是否是同一个点:

代码语言:javascript
复制
def remove(p1,p2):
    if p1[0]==p2[0] and p1[1]==p2[1]:
        return False
    # p1 和 p2 都在边界,可以直接删除
    if (p1[0] == p2[0]) and (p1[0]==0 or p1[0]==len(array)-1):
        print('上下边界可以直接删除')
    elif (p1[1] == p2[1]) and (p1[1]==0 or p1[1]==len(array[0])-1):
        print('上下边界可以直接删除')


今天我们主要用pygame实现连连看的界面以及基本的操作(实际连连看的消除下篇实现)。

视频效果(点击相同的两个可以消除):

步骤:

  1. 素材准备。
  2. 界面参数设置。(便于换素材,调整界面大小等)
  3. 界面分区(实现图片网格效果)
  4. 加载图片
  5. 判断逻辑实现

1.素材准备(我准备了两套):

resources

resources2

2.界面参数设置

代码语言:javascript
复制
class Config:
    ROW_COUNT = 7
    COLUMN_COUNT = 8
    WIDTH = 80
    HEIGHT = 80
    MARGIN = 5
    SCREEN_WIDTH = (WIDTH + MARGIN) * COLUMN_COUNT + MARGIN
    SCREEN_HEIGHT = (HEIGHT + MARGIN) * ROW_COUNT + MARGIN
    BG_COLOR = (200, 200, 200)
    RESOURCE_DIR = 'resources'

3.界面分区

pygame的界面是一个整体,这里人为通过左边给界面划分区域,实现每一格可以独立控制。

在之前的生成游戏地图文件文章中有写过,不理解的可以看看,实际项目融合了里面的部分代码。

4.加载图片

首先把每张图片看成一个独立的单元,这里通过类封装其数据以及方法。

代码语言:javascript
复制
class ImageButton:
    def __init__(self,screen,imgobj,x,y):
        self.checked = False
        self.checkable = True
        self.screen = screen
        self.imgobj = imgobj
        self.x = x
        self.y = y

    def draw(self):
        if self.checkable:
            if self.checked:
                pygame.draw.rect(self.imgobj, (255, 0, 0), [0, 0, Config.WIDTH, Config.HEIGHT], 4)
            else:
                pygame.draw.rect(self.imgobj, (0, 0, 0), [0, 0, Config.WIDTH, Config.HEIGHT], 4)
            self.screen.blit(self.imgobj, (self.x, self.y))

主逻辑中加载图片素材,同时将其变成按钮对象。

代码语言:javascript
复制
   class MyGame():
    def __init__(self):
      ...
    def load_imgs_obj(self):
        imgs = os.listdir(Config.RESOURCE_DIR)
        self.all_imgs = 4*imgs.copy() # 将图片复制4次
        random.shuffle(self.all_imgs)
        for img in self.all_imgs:
            img_obj = pygame.image.load(f'{Config.RESOURCE_DIR}/{img}')
            img_obj = pygame.transform.scale(img_obj, (Config.WIDTH, Config.HEIGHT))
            self.all_imgs_obj.append(img_obj)

    def init_imgs_obj(self):
        for row in range(Config.ROW_COUNT):
            for column in range(Config.COLUMN_COUNT):
                x = (Config.MARGIN + Config.WIDTH) * column + Config.MARGIN
                y = (Config.MARGIN + Config.HEIGHT) * row + Config.MARGIN
                obj = ImageButton(self.screen,self.all_imgs_obj[row * Config.COLUMN_COUNT + column],x,y)
                self.all_imgs_button.append(obj)

5.逻辑实现。

这里可以想象自己在玩这个游戏,首先游戏启动后,你会移动鼠标点击一张图片。然后找到和其一样的图片继续点击,相同图片就消失,不同图片则没有反应。

问题:

计算机如何知道你点击的是哪张图片,以及点击的前后顺序等?

解决:创建一个字典或者列表记录下来即可。

代码语言:javascript
复制
        #存储两个点击的图片
        self.match_img = {
            1: {
                "point": None,  # 表示被点图片坐标
                "pbtn_img": None  # 被点击按钮对应的图片名
            },
            2: {
                "point": None,
                "pbtn_img": None
            }
        }

怎么获取对应的图片?根据鼠标点击的坐标,计算出点击图片的行列值,然后根据索引得到图片名,并将结果保存到字典中

代码语言:javascript
复制
    def get_img(self,x,y):
        column = int(x // (Config.WIDTH + Config.MARGIN))
        row = int(y // (Config.HEIGHT + Config.MARGIN))
        if row < Config.ROW_COUNT and column < Config.COLUMN_COUNT:
            return (row, column)
代码语言:javascript
复制
  # 鼠标检测
  if event.type == pygame.MOUSEBUTTONDOWN:
      self.pos_x, self.pos_y = pygame.mouse.get_pos()
      if self.clicked_num <2:
          point = self.get_img(self.pos_x,self.pos_y)
          self.clicked_num += 1
          # 存储按钮对应的图片位置和图片
          self.match_img[self.clicked_num]["point"] = point
          self.match_img[self.clicked_num]["pbtn_img"] = self.all_imgs[point[0]*Config.COLUMN_COUNT+point[1]]

最后判断是不是相同的图片,且不在一个位置。

代码语言:javascript
复制
def judge(self):
    #判断图片是否配对
    if self.clicked_num == 2:
        #重置点击按钮次数
        self.clicked_num = 0
        #判断是否相同
        if self.match_img[1]["pbtn_img"] == self.match_img[2]["pbtn_img"] and self.match_img[1]['point'] != self.match_img[2]['point']:
            print('匹配成功')
            # 隐藏按钮图片 设置为不可点击
            self.all_imgs_button[self.match_img[1]["point"][0] * Config.COLUMN_COUNT + self.match_img[1]["point"][1]].checkable = False
            self.all_imgs_button[self.match_img[2]["point"][0] * Config.COLUMN_COUNT + self.match_img[2]["point"][1]].checkable = False
        else:
            #恢复图片原始状态
            print('不匹配')
            self.all_imgs_button[self.match_img[1]["point"][0] * Config.COLUMN_COUNT + self.match_img[1]["point"][1]].checked = False
            self.all_imgs_button[self.match_img[2]["point"][0] * Config.COLUMN_COUNT + self.match_img[2]["point"][1]].checked = False

        #清空已保存的两张图片按钮信息
        self.match_img[1]["point"] = self.match_img[2]["point"] = None
        self.match_img[1]["pbtn_img"] = self.match_img[2]["pbtn_img"] = None

完整代码:

代码语言:javascript
复制
import pygame
import os
import random

class Config:
    ROW_COUNT = 4
    COLUMN_COUNT = 8
    WIDTH = 80
    HEIGHT = 80
    MARGIN = 5
    SCREEN_WIDTH = (WIDTH + MARGIN) * COLUMN_COUNT + MARGIN
    SCREEN_HEIGHT = (HEIGHT + MARGIN) * ROW_COUNT + MARGIN
    BG_COLOR = (200, 200, 200)
    RESOURCE_DIR = 'resources2'

class ImageButton:
    def __init__(self,screen,imgobj,x,y):
        self.checked = False
        self.checkable = True
        self.screen = screen
        self.imgobj = imgobj
        self.x = x
        self.y = y

    def draw(self):
        if self.checkable:
            if self.checked:
                pygame.draw.rect(self.imgobj, (255, 0, 0), [0, 0, Config.WIDTH, Config.HEIGHT], 4)
            else:
                pygame.draw.rect(self.imgobj, (0, 0, 0), [0, 0, Config.WIDTH, Config.HEIGHT], 4)
            self.screen.blit(self.imgobj, (self.x, self.y))

class MyGame():
    def __init__(self):
        pygame.init()
        self.screen = pygame.display.set_mode([Config.SCREEN_WIDTH, Config.SCREEN_HEIGHT])
        self.clock = pygame.time.Clock()

        self.grid = [[0 for _column in range(Config.COLUMN_COUNT)] for _row in range(Config.ROW_COUNT)]

        #存储两个点击的图片
        self.match_img = {
            1: {
                "point": None,  # 表示被点图片坐标
                "pbtn_img": None  # 被点击按钮对应的图片名
            },
            2: {
                "point": None,
                "pbtn_img": None
            }
        }

        self.clicked_num = 0
        self.all_imgs = None
        self.all_imgs_obj = []
        self.all_imgs_button = []
        self.pos_x = -1
        self.pos_y = -1

        self.load_imgs_obj()
        self.init_imgs_obj()

    def load_imgs_obj(self):
        imgs = os.listdir(Config.RESOURCE_DIR)
        self.all_imgs = 4*imgs.copy()
        random.shuffle(self.all_imgs)
        for img in self.all_imgs:
            img_obj = pygame.image.load(f'{Config.RESOURCE_DIR}/{img}')
            img_obj = pygame.transform.scale(img_obj, (Config.WIDTH, Config.HEIGHT))
            self.all_imgs_obj.append(img_obj)

    def init_imgs_obj(self):
        for row in range(Config.ROW_COUNT):
            for column in range(Config.COLUMN_COUNT):
                x = (Config.MARGIN + Config.WIDTH) * column + Config.MARGIN
                y = (Config.MARGIN + Config.HEIGHT) * row + Config.MARGIN
                obj = ImageButton(self.screen,self.all_imgs_obj[row * Config.COLUMN_COUNT + column],x,y)
                self.all_imgs_button.append(obj)

    def get_img(self,x,y):
        column = int(x // (Config.WIDTH + Config.MARGIN))
        row = int(y // (Config.HEIGHT + Config.MARGIN))
        if row < Config.ROW_COUNT and column < Config.COLUMN_COUNT:
            return (row, column)

    def process_event(self):
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                exit()
            # 鼠标左键检测
            if event.type == pygame.MOUSEBUTTONDOWN:
                self.pos_x, self.pos_y = pygame.mouse.get_pos()
                if self.clicked_num <2:
                    point = self.get_img(self.pos_x,self.pos_y)
                    self.clicked_num += 1
                    # 存储按钮对应的图片位置和图片
                    self.match_img[self.clicked_num]["point"] = point
                    self.match_img[self.clicked_num]["pbtn_img"] = self.all_imgs[point[0]*Config.COLUMN_COUNT+point[1]]

                    self.all_imgs_button[self.match_img[1]["point"][0] * Config.COLUMN_COUNT + self.match_img[1]["point"][1]].checked = True

    def judge(self):
        #判断图片是否配对
        if self.clicked_num == 2:
            #重置点击按钮次数
            self.clicked_num = 0
            #判断是否相同
            if self.match_img[1]["pbtn_img"] == self.match_img[2]["pbtn_img"] and self.match_img[1]['point'] != self.match_img[2]['point']:
                print('匹配成功')
                # 隐藏按钮图片 设置为不可点击
                self.all_imgs_button[self.match_img[1]["point"][0] * Config.COLUMN_COUNT + self.match_img[1]["point"][1]].checkable = False
                self.all_imgs_button[self.match_img[2]["point"][0] * Config.COLUMN_COUNT + self.match_img[2]["point"][1]].checkable = False
            else:
                #恢复图片原始状态
                print('不匹配')
                self.all_imgs_button[self.match_img[1]["point"][0] * Config.COLUMN_COUNT + self.match_img[1]["point"][1]].checked = False
                self.all_imgs_button[self.match_img[2]["point"][0] * Config.COLUMN_COUNT + self.match_img[2]["point"][1]].checked = False

            #清空已保存的两张图片按钮信息
            self.match_img[1]["point"] = self.match_img[2]["point"] = None
            self.match_img[1]["pbtn_img"] = self.match_img[2]["pbtn_img"] = None

    def on_draw(self):
        self.screen.fill(Config.BG_COLOR)
        for imgbtn in self.all_imgs_button:
            imgbtn.draw()

    def on_update(self):
        self.judge()
        pygame.display.update()
        self.clock.tick(30)

    def run(self):
        while True:
            self.process_event()
            self.on_draw()
            self.on_update()

if __name__ == '__main__':
    game = MyGame()
    game.run()

上面的代码改改,可以变成记忆翻牌的游戏,加个遮挡即可。

下篇预告:将本篇的代码结合上一篇的连连看核心代码,实现完整可玩的连连看的游戏。

代码语言:javascript
复制
(全文完)
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2022-05-14,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 叶子陪你玩编程 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档