回到首页 返回首页
回到顶部 回到顶部
返回上一页 返回上一页

【Mind+Python】奥运冠军—连连看 简单

头像 乡村之子 2021.08.09 353 0

38金32银18铜,中国代表团以完美表现结束东京奥运会征程,追平境外奥运会最好战绩!

project-image
project-image
project-image
project-image
project-image
project-image
project-image
project-image
project-image
project-image
project-image
project-image
project-image
project-image
project-image
project-image
project-image
project-image
project-image
project-image
project-image

步骤1 游戏开始界面:

project-image

步骤2 游戏完成界面:

project-image
代码
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import sys, time
import math, random
import pygame
from pygame.locals import *

#全局的设置类
class Settings:
    def __init__(self):
        # 定义游戏窗口大小
        self.screen_size = (self.screen_width, self.screen_height) = (800, 500)
        self.game_size = (self.game_row, self.game_col) = (5, 8)
        self.map_total = self.game_row * self.game_col
        self.element_num = 20
        self.bg_color = (251,229,214)
        self.title = '奥运冠军—连连看'
        self.win_image = './images/you_win.png'
        self.grid_size = 100
        self.scale_size = (96, 96)
        self.points = []

# 实例化设置对象
settings = Settings()

# 图像列表映射
map_list = []
image_list = []

# 图片按钮
class ImageBtn:

    __checkable = True
    __checked = False

    def __init__(self, screen, image_path, x, y, number, element):
        self.x = x
        self.y = y
        self.element = element
        self.number = number
        self.screen = screen
        self.image = pygame.image.load(image_path)
        self.image = pygame.transform.scale(self.image, settings.scale_size)

    def __del__(self):
        pass

    def display(self):
     
        if self.__checked:
            pygame.draw.rect(self.image, (0,255,0), (0,0,self.image.get_width()-1,self.image.get_height()-1), 2)
        else:
            pygame.draw.rect(self.image, (251,229,214), (0,0,self.image.get_width()-1,self.image.get_height()-1), 2)

        self.screen.blit(self.image, (self.x, self.y))

    def hide(self):
        self.__checked = False
        self.__checkable = False
        self.image.fill((255, 255,255))

    def is_checkable(self):
        return self.__checkable

    def click(self):
        self.__checked = not self.__checked
        return self.__checked

    def reset(self):
        self.__checked = False

    def get_geometry(self):
        return (int(self.x), int(self.y), settings.scale_size[0], settings.scale_size[1])

def horizontal_scan(points):
    
    column = settings.game_col
    p1_x = int(points[0].number % column)
    p1_y = int(points[0].number / column)
    p2_x = int(points[1].number % column)
    p2_y = int(points[1].number / column)

    if p1_y == p2_y:
        return False

    if p1_y < p2_y:
        hLine1 = p1_y
        hLine2 = p2_y
    else:
        hLine1 = p2_y
        hLine2 = p1_y

    # 初始化左、右边界线为 0
    leftLimit = 0;
    rightLimit = column-1

    # 寻找左边界线
    i = p1_x
    while i > 0:
        # 判断左边点是否为空
        if map_list[p1_y * column+ i - 1] != 0:
            break
        # 当左边点为空时会继续扫面下一个左边点
        i -= 1
    leftLimit = i;

    i = p2_x
    while i > 0:
        if map_list[p2_y * column + i - 1] != 0:
            break
        i -= 1

    # leftLimit 记录左边界线,该界线所在的点为空或p1、p2本身
    if i > leftLimit:
        leftLimit = i

    # 如果 leftLimit 为 0,说明p1、p2已经在外界接通了,直接返回
    if leftLimit == 0:
        return True

    # 寻找右边界线
    i = p1_x
    while i < column-1:
        if map_list[p1_y * column + i + 1] != 0:
            break;
        i += 1
    rightLimit = i

    i = p2_x
    while i < column-1:
        if map_list[p2_y * column + i + 1] != 0:
            break
        i += 1

    if i < rightLimit:
        rightLimit = i

    if rightLimit == column-1:
        return True    # Bug

    # 判断 leftLimit 和 rightLimit
    if leftLimit > rightLimit:
        return False
    else:
        # 从左往右扫描
        for i in range(leftLimit, rightLimit+1):

            j = hLine1 + 1
            for j in range(hLine1+1, hLine2):

                if map_list[j * column + i] != 0:
                    break
                j += 1
            if j == hLine2:
                return True

        return False;

def vertical_scan(points):

    row = settings.game_row
    column = settings.game_col
    p1_x = int(points[0].number % column)
    p1_y = int(points[0].number / column)
    p2_x = int(points[1].number % column)
    p2_y = int(points[1].number / column)

    # 如果 p1 和 p2 在同一列,则不符合要求
    if p1_x == p2_x:
        return False

    # 记录两条垂直基准线
    if p1_x < p2_x:
        vLine1 = p1_x # 左垂直线
        vLine2 = p2_x # 右垂直线
    else:
        vLine1 = p2_x
        vLine2 = p1_x

    # 初始化上、下边界线
    topLimit = 0
    bottomLimit = row-1

    # 寻找上边界线
    i = p1_y
    while i > 0:
        if map_list[p1_x + (i-1) * column] != 0:
            break # 判断上边点是否为空
        i -= 1 # 当上边点为空时会继续扫面下一个上边点
    topLimit = i

    i = p2_y
    while i > 0:
        if map_list[p2_x + (i-1) * column] != 0:
            break
        i -= 1

    if i > topLimit:
        topLimit = i

    if topLimit == 0:
        return True

    # 寻找下边界线
    i = p1_y
    while i < row-1:
        if map_list[p1_x + (i+1) * column] != 0:
            break
        i += 1
    bottomLimit = i

    i = p2_y
    while i < row-1:
        if map_list[p2_x + (i+1) * column] != 0:
            break
        i += 1

    if i < bottomLimit:
        bottomLimit = i


    if bottomLimit == row-1:
        return True

    # 判断 topLimit 和 bottomLimit
    if topLimit > bottomLimit:
        return False
    else:
        # 从上往下扫描
        for i in range(topLimit, bottomLimit+1):

            j = vLine1 + 1
            for j in range(vLine1+1, vLine2):

                if map_list[i * column + j] != 0:
                    break
                j += 1
            if j == vLine2:

                return True

        return False


# 判断能否消除
def can_clear(points):

    if points[0].element != points[1].element:
        return False
    else:
        if vertical_scan(points) or horizontal_scan(points):
            return True
        else:
            return False


def check_event(btn_list):

    for event in pygame.event.get():
        if event.type == QUIT:
            print("exit...")
            sys.exit()

        if event.type == MOUSEBUTTONDOWN:
            pos = pygame.mouse.get_pos()

            for btn in btn_list:
                geo = btn.get_geometry()
                x = geo[0]; y = geo[1]; w = geo[2]; h = geo[3]
                # 判断是否在图片块范围内
                if pos[0] > x and pos[0] < x+w and pos[1] > y and pos[1] < y+h:

                    if btn.is_checkable():

                        if not btn.click():
                            settings.points.clear()
                            break

                        if settings.points != []:
                            settings.points.append(btn)
                            if can_clear(settings.points):
                                for point in settings.points:
                                    map_list[point.number] = 0
                                    point.number = 0
                                    point.hide()
                            else:
                                for point in settings.points:
                                    point.reset()
                            # 这次判断完毕,清除记录的点
                            settings.points.clear()

                        else:
                            # 记录第一个点
                            settings.points.append(btn)

# 构建游戏布局地图
def build_map():

    t_list = []
    m_list = []

    # 构建成对数据
    for i in range(0, settings.map_total, 2):
        e = math.ceil(random.random()*settings.element_num)
        t_list.append(e)
        t_list.append(e)

    # 打乱数据
    for i in range(0, settings.map_total, 1):
        index = int(random.random()*(settings.map_total-i))
        m_list.append(t_list[index])
        t_list.pop(index)
    return m_list

# 检查是否全部消除
def is_over():

    for each in map_list:
        if each > 0:
            return False
    return True

def main():

    pygame.init()
    screen = pygame.display.set_mode(settings.screen_size, 0, 0)
    pygame.display.set_caption(settings.title)

    global map_list
    map_list = build_map()
    nc = 0
    for m in map_list:
        nc += 1

    # 创建图片列表
    for i in range(0, settings.map_total):
        x = int(i%settings.game_col) * settings.grid_size + (settings.grid_size -settings.scale_size[0])/2
        y = int(i/settings.game_col) * settings.grid_size + (settings.grid_size -settings.scale_size[0])/2
        element = './images/element_'+str(map_list[i])+'.jpg'
        image_list.append(ImageBtn(screen, element, x, y, i, map_list[i]))

    play = True
    i = 0

    while True:
        screen.fill(settings.bg_color)
        if play:

            if is_over():
                play = False

            for im in image_list:
                im.display()

            pygame.display.update()

        else:
            youwin = pygame.image.load(settings.win_image)
            screen.blit(youwin, ((settings.screen_width-youwin.get_width())/2,(settings.screen_height-youwin.get_height())/2))
            pygame.display.update()

        # 检查按键事件
        check_event(image_list)
        time.sleep(0.04)

if __name__ == '__main__':
    main()

评论

user-avatar