python拼图游戏

        最开始的时候想做一个类似于现实中拼图的游戏,但是在网上看了一些,都是类似于华容道的移动型拼图游戏,而且之前就写过华容道。所以想做一个比较符合真实拼图的游戏。

        在现实中买的拼图,它们的每一个单元都有凹凸的效果。但对它们的凹凸分析一下可以知道,拼图的凹凸设计是为了实现拼图块的稳固,不是增加拼图的难度,甚至由于凹凸部分具有相邻凹凸块的特性还会降低拼图的难度,所以可以只做成方形的即可。当然,如果拼图单元想做成凹凸效果,由于图片的显示单元都是矩形,所以只能将几个矩形部分的图片打包成一个拼图凹凸单元,其凹凸的部分可以根据哈尔伯特空间曲线确认。

        第一步,我们准备一张图片,其宽高最好先处理好,以防不好分割。先得到一些关于图片的数据及分割之后的宽高、拼图块个数等。我找的是800*800的图片。

        这里最主要的是得到分割后的每一个拼图块的数据信息,其格式是[ [ left , top ] , [ right , bottom ] , rotate_count ] ,最后一个数据是拼图块的旋转角度,因为都是90的倍数,所以只需要枚举一系列整数即可。

#旋转角度标准枚举
class Rotate_count_stanfard(Enum):
    zero = 0
    one = 1
    two = 2
    three = 3
    neg_one = -1
    neg_two = -2
    neg_three = -3

#计算照片分割数
def divide_image_num(image_path : str,width_divide : int,height_divide: int):
    """得到图片能分割的数量

    :param image_path: str,图片地址
    :param width_divide: int,分割单元的宽
    :param height_divide: int,分割单元的高
    :returns: (width_num,height_num): tuple,(int,int)或者(bool,bool),(宽上的分割数,高上的分割数)或者(False,False)表示分割失败
    """
    #判断照片是否整数分割
    with Image.open(image_path) as img:

        if (img.width % width_divide == 0) & (img.height % height_divide == 0):
            #计算游戏窗口尺寸
            global width,height
            width = img.width + 300
            height = img.height
            #计算宽、高能分割出来的个数并返回
            width_num = int(img.width / width_divide)
            height_num = int(img.height / height_divide)
            return width_num,height_num

        else :
            print('您的图片不能整数分割,请先处理好您的图片')
            return False,False

#通过分割返回图片分割后的块个数和列表
def divide_image_list(image_path : str):
    """分割图片,并返回图片块个数和图片块左上角和右下角坐标列表

    :param image_path: str,图片地址
    :returns: (all_list_count,all_piece_list) : tuple,(int,list),
            (图片块个数,图片左上角和右下角坐标和旋转次数列表 [[[x0,y0],[x1,y1],0],[[x2,y2],[x3,y3],0]] 格式类型的)
    """
    # 先判断能不能整数分割,不能则强制退出
    global width_divide
    global height_divide
    width_num,height_num = divide_image_num(image_path,width_divide,height_divide)
    if (width_num== False) & (height_num == False):
        sys.exit()
    else:
        all_piece_list=[]   #设计具有三层,第一层索引是图片第几块;第二层索引 0 是图片的左上角坐标,1 是右下角坐标,2 是该块的旋转次数(角度=次数*90);第三层索引 0 是x坐标值,1 是y坐标值.
        all_list_count = 0
        for i in range(height_num):
            for j in range(width_num):
                all_piece_list.append([[width_divide * j,height_divide * i],[width_divide * (j+1),height_divide * (i+1)],0])
                all_list_count += 1
        return  all_list_count,all_piece_list

        第二步,在mian()中,开始游戏,当游戏开始时,给出一个开始提示界面。

#游戏未开始时的提示界面
def game_prompt_interface(screen):
    """
    :param screen: pygame的display中的 Surface 对象
    """
    screen.fill((255, 255, 255))  # 白色背景
    font = pygame.font.SysFont('宋体', 40)
    text = font.render('Left mouse button to start the game', True, (0, 0, 0))  # 黑色字体
    text_rect = text.get_rect(center=screen.get_rect().center)
    screen.blit(text, text_rect) 
    pygame.display.flip()
    pygame.time.Clock().tick(20)  # 提示期间控制帧率为20

        输出画面就是这样的。

        第三步,通过鼠标左键键入进入游戏,以及需要的未开始期间的退出判断。其中 running 是一个标志位,作进入游戏开始判断。

    while running:

        # 鼠标左键按下开始游戏
        events = pygame.event.get()
        for event in events:
            if event.type == QUIT:  # 当用户关闭窗口时,Pygame会生成一个QUIT事件
                running = False
            elif event.type == MOUSEBUTTONDOWN and event.button == 1:  # 1 为鼠标左键按下事件
                game_started = True


    pygame.quit()
    sys.exit()

        第四步,我们得设计一下游戏窗口。

        进入游戏,我们要看到一张图片才能开始呀,所以第一件事就是在预备区内刷新一张图片。刷新采用的最简单的random来随机刷新。将还没有进入过预备区的块存入piece_not_do列表内,这样就可以通过列表是不是空的来判断预备区放置是否结束。其中,ready_state是用来判断预备区是否存在块的。

                if not (len(piece_not_do) == 0):  # 先判断预备区是否用完
                    # 预备区不存在块时随机取一个
                    if ready_state == False:
                        # 确定预备区块
                        ready_num = random.choice(piece_not_do)
                        piece_not_do.remove(ready_num)      #随机取一张为放下去的块并删除piece_not_do的记录
                        ready_piece_rotate = random.choice(rotate_random)
                        ready_piece_list[0] = all_piece_list[ready_num]
                        ready_piece_list[0][2] = ready_piece_rotate
                        ready_piece_list[1] = ready_num
                        # 将随机块显示在窗口右侧预备区
                        piece_list_to_surface(screen,ready_piece_list[0],      #将预备区块转换为图片放在画幕上
                                              (width_num * width_divide + 50, height / 2 - height_divide / 2))
                        ready_state = True

        由于我们的游戏都是通过鼠标进行操作的,所以就需要通过判断鼠标的事件类型来决定下一步该怎么做,所以游戏的结构就是根据判断到的鼠标事件的不同,运行对应的不同段落的代码。这样做还有一个原因,就是pygame的pygame.event.get() 会获取并处理所有的事件,例如处理退出事件。然而,第二次调用 pygame.event.get() 时,由于事件队列已经被第一次调用清空了,所以再次使用将是一个空列表。任何在两次调用之间发生的事件将会被丢失,不能被处理。

        下面是代码,包括图片块的旋转、预备区放入棋盘区、棋盘区图片块的交换这几种操作。

                # 对event对下一步进行判断
                events = pygame.event.get()
                for event_nd in events:
                    if event_nd.type == QUIT:
                        sys.exit()
                    if (event_nd.type == pygame.MOUSEBUTTONDOWN) and (event_nd.button == 1):
                        mouse_x, mouse_y = pygame.mouse.get_pos() # 获取鼠标坐标
                        mouse_down_time = pygame.time.get_ticks()  # 记录左键按下时的时间(距离游戏初始化开始时间)
                        put_state = True
                        swap_piece_down = True
                        break
                    if (event_nd.type == pygame.MOUSEBUTTONDOWN) and \
                            ((event_nd.button == 4) or (event_nd.button == 5)): #滚轮向上和向下
                        mouse_x, mouse_y = pygame.mouse.get_pos()
                        piece_rotate_state = True
                        rotate_button = event_nd.button
                        break
                    if (event_nd.type == pygame.MOUSEBUTTONUP) and (event_nd.button == 1):  # 鼠标左键释放事件
                        mouse_x, mouse_y = pygame.mouse.get_pos()
                        swap_piece_down = False
                        swap_piece_up =  True
                        break

                # 从预备区放置到棋盘上
                if put_state == True:  # 判断放置状态标志
                    put_state = False  
                    # 如果棋盘状态未放置,则放置下去,并将预备区覆盖为黑色
                    if (mouse_x < (width - width_divide - 100)) and (mouse_y < height):  # 判断是否在棋盘区
                        board_x, board_y = get_board_dest(mouse_x, mouse_y)
                        if board_piece[board_y * width_num + board_x] == -1:  # 判断该处没有块
                            #各类数据更新
                            all_board_piece_list[board_y * width_num + board_x] = ready_piece_list[:]
                            board_piece = [i[1] for i in all_board_piece_list]
                            board_rotate_state = [i[0][2] for i in all_board_piece_list]
                            #增加棋盘更新列表
                            board_update_order.append([board_x,board_y])
                            # 将预备区黑化
                            rect = pygame.Rect(width - width_divide - 50,height / 2 - height_divide / 2,
                                               width_divide,height_divide)  # (x, y, width, height)
                            pygame.draw.rect(screen, (0, 0, 0), rect)
                            # 预备区标志置零
                            ready_state = False


                # 旋转块的角度:1、预备区的角度 2、已经放下去的块的角度
                if piece_rotate_state == True:
                    # 旋转标志位置零
                    piece_rotate_state = False
                    # 预备区旋转
                    if (mouse_x > (width_divide * width_num)):   #首先确认鼠标在窗口右侧的预备区
                        if ready_state == True:
                            if rotate_button == 4:
                                ready_piece_list[0][2] = rotate_up(ready_piece_list[0][2]) #更改预备块list内的角度数据

                            elif rotate_button == 5:
                                ready_piece_list[0][2] = rotate_down(ready_piece_list[0][2])
                            piece_list_to_surface(screen, ready_piece_list[0],      # 更新预备区
                                                  (width_num * width_divide + 50, height / 2 - height_divide / 2))
                    #棋盘区旋转
                    if (mouse_x < (width_divide * width_num)): #判断在棋盘内
                        board_x,board_y = get_board_dest(mouse_x,mouse_y)
                        order = board_y * width_num + board_x
                        if board_piece[order] != -1: #先判断鼠标所指棋盘位置是否存在块
                            if rotate_button == 4:
                                # 增加棋盘更新列表
                                board_update_order.append([board_x, board_y])
                                # 更新棋盘数据
                                all_board_piece_list[order][0][2] = rotate_up(all_board_piece_list[order][0][2])
                                board_rotate_state = [i[0][2] for i in all_board_piece_list]
                            elif rotate_button == 5:
                                # 增加棋盘更新列表
                                board_update_order.append([board_x, board_y])
                                # 更新棋盘数据
                                all_board_piece_list[order][0][2] = rotate_down(all_board_piece_list[order][0][2])
                                board_rotate_state = [i[0][2] for i in all_board_piece_list]


                #棋盘区交换
                #按下确定 from 点
                if swap_piece_down == True:
                    current_time = pygame.time.get_ticks()
                    if current_time - mouse_down_time >= max_down_time: #在左键长按达到一定时间才触发
                        if (mouse_x < (width - width_divide - 100)) and (mouse_y < height):  # 判断是否在棋盘区
                            swap_piece_down = False
                            swap_state = True
                            #得到交换 from 的棋盘块信息
                            board_x, board_y = get_board_dest(mouse_x, mouse_y)
                            swap_from_order = [board_x, board_y]
                            swap_from_num  = board_y * width_num + board_x
                #释放确定 to 点
                if swap_piece_up == True:
                    swap_piece_up = False
                    if swap_state == True:  #防止其它非延时型左键释放的意外触发
                        swap_state = False
                        if (mouse_x < (width - width_divide - 100)) and (mouse_y < height):  # 判断是否在棋盘区
                            # 得到交换 to 的棋盘块信息
                            board_x, board_y = get_board_dest(mouse_x, mouse_y)
                            swap_to_order = [board_x, board_y]
                            swap_to_num = board_y * width_num + board_x
                            #更新棋盘信息
                            all_board_piece_list[swap_from_num],all_board_piece_list[swap_to_num] = \
                                swap_data(all_board_piece_list[swap_from_num],all_board_piece_list[swap_to_num])
                            board_piece = [i[1] for i in all_board_piece_list]
                            board_rotate_state = [i[0][2] for i in all_board_piece_list]
                            #增加棋盘更新列表
                            board_update_order.append(swap_from_order)
                            board_update_order.append(swap_to_order)

        这样就可以根据鼠标动作做出行动。

        这个游戏打开后点击左键既能进入游戏,可以通过将鼠标放在图片块上再转动滚轮来旋转图片块,通过左键棋盘区空白部分来放置图片块,通过左键按在图片块上长按一段时间将鼠标移至交换位置再松开鼠标来交换棋盘区的图片块。

        新手,请批评指正,谢谢各位。

"""
可优化点:
    1.将Image读取图片换成pygame
    2.处理交换时拖拽渲染
    3.设计一个拼图缓冲区,用来放着还不确定位置的一些块
    4.设计右键预确认功能,像扫雷里面的右键插旗确认一样
"""

import pygame
from PIL import Image
import sys
from enum import Enum
from pygame.locals import *
import random

#旋转角度标准枚举
class Rotate_count_stanfard(Enum):
    """作为图片块旋转的标准次数枚举"""
    zero = 0
    one = 1
    two = 2
    three = 3
    neg_one = -1
    neg_two = -2
    neg_three = -3

#计算照片分割数
def divide_image_num(image_path : str,width_divide : int,height_divide: int):
    """得到图片能分割的数量

    :param image_path: str,图片地址
    :param width_divide: int,分割单元的宽
    :param height_divide: int,分割单元的高
    :returns: (width_num,height_num): tuple,(int,int)或者(bool,bool),(宽上的分割数,高上的分割数)或者(False,False)表示分割失败
    """
    #判断照片是否整数分割
    with Image.open(image_path) as img:

        if (img.width % width_divide == 0) & (img.height % height_divide == 0):
            #计算游戏窗口尺寸
            global width,height
            width = img.width + 300          
            height = img.height
            #计算宽、高能分割出来的个数并返回
            width_num = int(img.width / width_divide)
            height_num = int(img.height / height_divide)
            return width_num,height_num

        else :
            print('您的图片不能整数分割,请先处理好您的图片')
            return False,False

#通过分割返回图片分割后的块个数和列表
def divide_image_list(image_path : str):
    """分割图片,并返回图片块个数和图片块左上角和右下角坐标列表

    :param image_path: str,图片地址
    :returns: (all_list_count,all_piece_list) : tuple,(int,list),
            (图片块个数,图片左上角和右下角坐标和旋转次数列表 [[[x0,y0],[x1,y1],0],[[x2,y2],[x3,y3],0]] 格式类型的)
    """
    # 先判断能不能整数分割,不能则强制退出
    global width_divide
    global height_divide
    width_num,height_num = divide_image_num(image_path,width_divide,height_divide)
    if (width_num== False) & (height_num == False):
        sys.exit()
    else:
        all_piece_list=[]   #设计具有三层,第一层索引是图片第几块;第二层索引 0 是图片的左上角坐标,1 是右下角坐标,2 是该块的旋转次数(角度=次数*90);第三层索引 0 是x坐标值,1 是y坐标值.
        all_list_count = 0
        for i in range(height_num):
            for j in range(width_num):
                all_piece_list.append([[width_divide * j,height_divide * i],[width_divide * (j+1),height_divide * (i+1)],0])
                all_list_count += 1
        return  all_list_count,all_piece_list

#通过图片块列表坐标将图片块从图片中取出来
class Image_piece:
    """图片块会有一系列操作,创建一个图片块的类

    :param piece_list:[[x0,y0],[x1,y1],0]类型的列表
    """

    def __init__(self,piece_list : list):
        self.left_top = piece_list[0]
        self.right_bottom = piece_list[1]
        self.rotate_count = piece_list[2]
        self.left = self.left_top[0]
        self.top = self.left_top[1]
        self.right = self.right_bottom[0]
        self.bottom = self.right_bottom[1]

    def get_piece(self):
        """
        得到图片块相对应的图片对象

        :return: cropped_image: 一个 PIL.Image.Image 对象
        """
        global image_path
        with Image.open(image_path) as image :
            # 通过对角线两点坐标截取图像,并通过旋转次数旋转图片
            cropped_image = image.crop((self.left, self.top, self.right, self.bottom))
            cropped_image = cropped_image.rotate(90 * self.rotate_count,expand = True)  # 正方向是逆时针
            return cropped_image

    def piece_rotate(self,rotate_count : Rotate_count_stanfard):
        """计算图片块旋转后其左上角和右下角坐标在原图中的坐标

        :note : 旋转后的坐标左上角坐标可能会大于右下角坐标,导致在get_piece时image.crop方法出错,所以这个方法只是用来计算,不返回self

        :returns: 返回旋转后左上角和右上角x、y坐标
        """
        #先确定四个角的坐标
        x_0 = self.left ; y_0 = self.top
        x_1 = self.left ; y_1 = self.bottom
        x_2 = self.right; y_2 = self.bottom
        x_3 = self.right; y_3 = self.top
        #现将rotate_count变为正数
        if rotate_count < 0:
            rotate_count = 4 - abs(rotate_count) % 4
        #根据旋转次数旋转
        if rotate_count >= 0:
            for i in range(rotate_count):
                temp_x_0 = x_0 ;temp_y_0 = y_0
                x_0 = x_3 ; y_0 = y_3
                x_3 = x_2 ; y_3 = y_2
                x_2 = x_1 ; y_2 = y_1
                x_1 = temp_x_0 ; y_1 = temp_y_0
        #self.top = y_0, self.left = x_0
        #self.bottom = y_2,self.right = x_2
        return [[x_0,y_0],[x_2,y_2]]

#游戏未开始时的提示界面
def game_prompt_interface(screen):
    """
    :param screen: pygame的display中的 Surface 对象
    """
    screen.fill((255, 255, 255))  # 白色背景
    font = pygame.font.SysFont('宋体', 40)
    text = font.render('Left mouse button to start the game', True, (0, 0, 0))  # 黑色字体
    text_rect = text.get_rect(center=screen.get_rect().center)
    screen.blit(text, text_rect)  # blit() 方法用于将一个图像绘制在另一个图像上,这里将文本图像 text 绘制在屏幕上的指定位置 text_rect
    pygame.display.flip()
    pygame.time.Clock().tick(20)  # 提示期间控制帧率为20

#旋转参数增加方法
def rotate_up(x : int):
    if x == 3:
        x = 0
    elif x < 3:
        x += 1
    return x

#旋转参数减小方法
def rotate_down(x : int):
    if x == -3:
        x = 0
    elif x > -3:
        x -= 1
    return x

#通过 piece_list[] 更新 pygame 的 display 画面
def piece_list_to_surface(screen,piece_list,dest : tuple):
    """
    通过piece_list[]数据得到可以再pygame显示的syrface对象并更新screen

    :param screen: 作为显示的屏幕最底层Surface对象
    :param piece_list: 需要显示的 piece数据
    :param dest: tuple,显示的左上角坐标,是一个二元元组
    """
    global image_path
    piece = Image_piece(piece_list)
    piece_Image = piece.get_piece()  # 得到图片(包括旋转后的)
    # 将 Image 图片转换为 Pygame Surface对象
    piece_Surface = pygame.image.fromstring(piece_Image.tobytes(), piece_Image.size,
                                                  piece_Image.mode)
    # 在屏幕上显示图片
    screen.blit(piece_Surface, dest)

#交换数据函数
def swap_data(a,b):
    return b,a

#得到棋盘格子坐标
def get_board_dest(mouse_x,mouse_y):
    global width_divide
    global height_divide
    board_x = int(mouse_x / width_divide)
    board_y = int(mouse_y / height_divide)
    return  board_x,board_y

#棋盘区块的更新显示函数
def board_update(screen,board_update_order : list,all_board_piece_list):
    global width_num,width_divide,height_divide
    for update_order in board_update_order:
        board_x = update_order[0]
        board_y = update_order[1]
        order = board_y * width_num + board_x
        if all_board_piece_list[order][1] != -1:
            piece_list_to_surface(screen,all_board_piece_list[order][0],(board_x * width_divide, board_y * height_divide))
        elif all_board_piece_list[order][1] == -1:
            rect = pygame.Rect(board_x * width_divide, board_y * height_divide,
                               width_divide, height_divide)  # (x, y, width, height)
            pygame.draw.rect(screen, (0, 0, 0), rect)
    board_update_order.clear()




#主函数
def main():
    global screen
    global width_num, height_num
    global all_list_count, all_piece_list

    print('all_piece_list: ',all_piece_list)

    #程序一些标志位和初始值
    running = True  # 程序开始标志
    game_started = False  # 游戏开始标志
    ready_state = False  # 预备区存在标志
    swap_piece_down  = False  # 交换块的按下鼠标标志
    swap_piece_up = False  # 交换块的释放鼠标标志
    put_state = False  # 是否可以从预备区放置标志
    piece_rotate_state = False  # 块是否旋转标志位
    swap_state = False #真的开始交换标志位,避免其它不必要的左键释放造成误判
    #swap_motion = False  #交换拖拽标志位
    ready_num = 0  # 先预先初始化一个预备值,防止出现错误
    ready_piece_rotate = 0  # 先预先初始化一个预备值,防止出现错误
    max_down_time = 500 #用来识别左键时候被长按,单位ms

    # 程序中间使用的列表
    # 预备区处理列表
    ready_piece_list = [[[0,0],[0,0],0],-1]       #用来存放预备区的 piece_list 数据[[坐标左上,右下,旋转],在原图片中的第几块]
    piece_not_do = [i for i in range(all_list_count)]  # 存放还没放下去的块
    rotate_random = [0, 1, 2, 3, -1, -2, -3]  # 旋转的随机可能列表
    # 棋盘区处理列表,下面的这三个要同时更新
    all_board_piece_list = [[[[0,0],[0,0],4],-1] for _ in range(all_list_count)]  # 索引是棋盘格子位,用来存放棋盘区的 piece_list 数据,-1是初始未放置编号
    board_piece = [i[1] for i in all_board_piece_list] # 索引为在棋盘上的格子位,存放棋盘上放置的块的编号,该列表判断棋盘上块是否都正确放置
    board_rotate_state = [i[0][2] for i in all_board_piece_list]  # 索引为在棋盘上的格子位,存储棋盘上已经放置块位置上的旋转角度,判断角度是否正确
    board_update_order = [] #用来存储本次循环改变的棋盘格,元素是棋盘格子位


    while running:

        # 鼠标左键按下开始游戏
        events = pygame.event.get()
        for event in events:
            if event.type == QUIT:  # 当用户关闭窗口时,Pygame会生成一个QUIT事件
                running = False
            elif event.type == MOUSEBUTTONDOWN and event.button == 1:  # 1 为鼠标左键按下事件
                game_started = True

        if game_started:
            # 游戏黑色背景
            screen.fill((0, 0, 0))
            # 游戏内容开始
            while not (board_piece == [i for i in range(all_list_count)]) \
                    or not (all(x == 0 for x in board_rotate_state)):  # 判断棋盘内块位置及角度是否正确

                # 预备区上块
                if not (len(piece_not_do) == 0):  # 先判断预备区是否用完
                    # 预备区不存在块时随机取一个
                    if ready_state == False:
                        # 确定预备区块
                        ready_num = random.choice(piece_not_do)
                        piece_not_do.remove(ready_num)      #随机取一张为放下去的块并删除piece_not_do的记录
                        ready_piece_rotate = random.choice(rotate_random)
                        ready_piece_list[0] = all_piece_list[ready_num]
                        ready_piece_list[0][2] = ready_piece_rotate
                        ready_piece_list[1] = ready_num
                        # 将随机块显示在窗口右侧预备区
                        piece_list_to_surface(screen,ready_piece_list[0],      #将预备区块转换为图片放在画幕上
                                              (width_num * width_divide + 50, height / 2 - height_divide / 2))
                        ready_state = True


                # 利用左键确定鼠标落点,并对event对下一步进行判断
                events = pygame.event.get()
                for event_nd in events:
                    if event_nd.type == QUIT:  # 当用户关闭窗口时,Pygame会生成一个QUIT事件
                        sys.exit()
                    if (event_nd.type == pygame.MOUSEBUTTONDOWN) and (event_nd.button == 1):  # 1 表示鼠标左键
                        mouse_x, mouse_y = pygame.mouse.get_pos() # 获取鼠标坐标
                        mouse_down_time = pygame.time.get_ticks()  # 记录左键按下时的时间(距离游戏初始化开始时间)
                        put_state = True
                        swap_piece_down = True
                        break
                    if (event_nd.type == pygame.MOUSEBUTTONDOWN) and \
                            ((event_nd.button == 4) or (event_nd.button == 5)): #滚轮向上和向下
                        mouse_x, mouse_y = pygame.mouse.get_pos()
                        piece_rotate_state = True
                        rotate_button = event_nd.button
                        break
                    if (event_nd.type == pygame.MOUSEBUTTONUP) and (event_nd.button == 1):  # 鼠标左键释放事件
                        mouse_x, mouse_y = pygame.mouse.get_pos()
                        swap_piece_down = False
                        swap_piece_up =  True
                        break
                    # if event_nd.type == pygame.MOUSEMOTION:        # 处理鼠标移动事件
                    #     if swap_state == True:
                    #         swap_motion = True
                    #         mouse_x, mouse_y = event.pos


                # 从预备区放置到棋盘上
                if put_state == True:  # 判断放置状态标志
                    put_state = False  # 及时归零
                    # 如果棋盘状态未放置,则放置下去,并将预备区覆盖为黑色
                    if (mouse_x < (width - width_divide - 100)) and (mouse_y < height):  # 判断是否在棋盘区
                        board_x, board_y = get_board_dest(mouse_x, mouse_y)
                        if board_piece[board_y * width_num + board_x] == -1:  # 判断该处没有块
                            #各类数据更新
                            all_board_piece_list[board_y * width_num + board_x] = ready_piece_list[:] #在修改容器元素时,最好不要直接指向
                            board_piece = [i[1] for i in all_board_piece_list]
                            board_rotate_state = [i[0][2] for i in all_board_piece_list]
                            #增加棋盘更新列表
                            board_update_order.append([board_x,board_y])
                            # 将预备区黑化
                            rect = pygame.Rect(width - width_divide - 50,height / 2 - height_divide / 2,
                                               width_divide,height_divide)  # (x, y, width, height)
                            pygame.draw.rect(screen, (0, 0, 0), rect)
                            # 预备区标志置零
                            ready_state = False


                # 旋转块的角度:1、预备区的角度 2、已经放下去的块的角度
                if piece_rotate_state == True:
                    # 旋转标志位置零
                    piece_rotate_state = False
                    # 预备区旋转
                    if (mouse_x > (width_divide * width_num)):   #首先确认鼠标在窗口右侧的预备区
                        if ready_state == True:
                            if rotate_button == 4:  # 滚轮向上
                                ready_piece_list[0][2] = rotate_up(ready_piece_list[0][2]) #更改预备块list内的角度数据

                            elif rotate_button == 5:  # 滚轮向下
                                ready_piece_list[0][2] = rotate_down(ready_piece_list[0][2])
                            piece_list_to_surface(screen, ready_piece_list[0],      # 更新预备区画幕
                                                  (width_num * width_divide + 50, height / 2 - height_divide / 2))
                    #棋盘区旋转
                    if (mouse_x < (width_divide * width_num)): #判断在棋盘内
                        board_x,board_y = get_board_dest(mouse_x,mouse_y)
                        order = board_y * width_num + board_x
                        if board_piece[order] != -1: #先判断鼠标所指棋盘位置是否存在块
                            if rotate_button == 4:
                                # 增加棋盘更新列表
                                board_update_order.append([board_x, board_y])
                                # 更新棋盘数据
                                all_board_piece_list[order][0][2] = rotate_up(all_board_piece_list[order][0][2])
                                board_rotate_state = [i[0][2] for i in all_board_piece_list]
                            elif rotate_button == 5:
                                # 增加棋盘更新列表
                                board_update_order.append([board_x, board_y])
                                # 更新棋盘数据
                                all_board_piece_list[order][0][2] = rotate_down(all_board_piece_list[order][0][2])
                                board_rotate_state = [i[0][2] for i in all_board_piece_list]


                #棋盘区交换
                #按下确定 from 点
                if swap_piece_down == True:
                    current_time = pygame.time.get_ticks()
                    if current_time - mouse_down_time >= max_down_time: #在左键长按达到一定时间才触发
                        if (mouse_x < (width - width_divide - 100)) and (mouse_y < height):  # 判断是否在棋盘区
                            swap_piece_down = False
                            swap_state = True
                            #得到交换 from 的棋盘块信息
                            board_x, board_y = get_board_dest(mouse_x, mouse_y)
                            swap_from_order = [board_x, board_y]
                            swap_from_num  = board_y * width_num + board_x
                #释放确定 to 点
                if swap_piece_up == True:
                    swap_piece_up = False
                    if swap_state == True:  #防止其它非延时型左键释放的意外触发
                        swap_state = False
                        if (mouse_x < (width - width_divide - 100)) and (mouse_y < height):  # 判断是否在棋盘区
                            # 得到交换 to 的棋盘块信息
                            board_x, board_y = get_board_dest(mouse_x, mouse_y)
                            swap_to_order = [board_x, board_y]
                            swap_to_num = board_y * width_num + board_x
                            #更新棋盘信息
                            all_board_piece_list[swap_from_num],all_board_piece_list[swap_to_num] = \
                                swap_data(all_board_piece_list[swap_from_num],all_board_piece_list[swap_to_num])
                            board_piece = [i[1] for i in all_board_piece_list]
                            board_rotate_state = [i[0][2] for i in all_board_piece_list]
                            #增加棋盘更新列表
                            board_update_order.append(swap_from_order)
                            board_update_order.append(swap_to_order)


                #统一根据更改的棋盘点更新棋盘显示的图片
                if board_update_order != [] :
                    board_update(screen,board_update_order,all_board_piece_list)
                # 更新显示
                pygame.display.flip()
                pygame.time.Clock().tick(10)  # 游戏期间控制帧率为10


            # 游戏成功
            if (board_piece == [i for i in range(all_list_count)]) and (
                                all(x == 0 for x in board_rotate_state)):
                print('位置和角度都正确')
                running = False  # 游戏结束

        # 如果游戏还未开始,绘制开始游戏的提示信息
        else:
            game_prompt_interface(screen)

    pygame.quit()
    sys.exit()


if __name__ == "__main__":
    #标定宽、高的分割单位
    width_divide = 200      #测试完成功后改为200
    height_divide = 200
    #游戏窗口大小
    width = 0
    height = 0
    #初始图片地址
    image_path = 'img800.jpg'
    # 切割图片并得到一些数据
    width_num, height_num = divide_image_num(image_path, width_divide, height_divide)
    all_list_count, all_piece_list = divide_image_list(image_path)  # all_piece_list保留初始所有块的信息
    # 根据尺寸画出窗口
    size = [width, height]
    pygame.init()  # 初始化各种 pygame 模块
    screen = pygame.display.set_mode(size)

    main()

### 回答1: Python是一个先进的编程语言,拥有强大的功能和广泛的应用范围。在这其中,Python拼图游戏算是一个比较常见的应用。拼图游戏是一种经典的娱乐方式,它的难度和挑战性非常高。使用Python可以轻松地实现一个拼图游戏,让用户可以享受到高质量、高度定制化的拼图体验。 使用Python来实现拼图游戏,首先需要明确游戏规则和玩家界面。玩家可以通过拖动和旋转拼图块来完成游戏Python可以通过图形化界面库,如Tkinter、PyQt等来创建游戏界面。同时,Python还具有大量的算法和数学库,如numpy、scipy等,可以用于实现拼图的逻辑运算和难度控制,提升游戏的可玩性和挑战性。 此外,Python还可以在游戏中加入一些其他的功能,比如计时器、步数限制、难度等级、多样化的拼图形式等等,来增加游戏的趣味性和挑战性,让玩家不断尝试和挑战自己的极限。总之,Python拼图游戏是一种非常有趣和有挑战性的游戏,它的实现方法简单易懂,而且代码量不大,可以很快地让玩家体验到高质量的拼图游戏乐趣。 ### 回答2: Python拼图游戏可以是一个很有趣的项目,这个游戏目的是将一幅图像分成多个碎片,然后通过重新排列碎片还原原图像。这需要用到一些基础的编程知识,比如图像处理和GUI编程。 要开始这个项目,首先需要导入Python图形库,如pygame或Tkinter,并创建一个GUI窗口。接着,可以使用Python图像库(如Pillow)将原始图像加载到程序中,然后将它分割成若干个碎片。 一些Python库,如numpy和random,可以被用来随机排列图片碎片,使得用户可以通过点击和拖动无序的碎片来还原图像。如果用户完成了任务,可以使拼图解锁某些奖励(如一个隐藏关卡或一幅新的图像)以鼓励玩家。 为了增加游戏的趣味性和挑战性,可以考虑增加游戏难度,比如增加碎片数量或减少碎片大小,使得玩家需要投入更多的精力和耐心来完成任务。 总之,Python拼图游戏是一个有趣的项目,需要用到一些编程基础知识,但可以通过不断的尝试和练习来提高编程能力。 ### 回答3: Python拼图游戏是一款使用Python语言编写的益智游戏,玩家需要通过调换不同图片的位置,来恢复一张完整的图片。这款游戏操作简单,但需要一定的思维能力和耐心。 在游戏中,玩家可以自由选择不同难度等级的拼图,从简单的3×3的拼图开始,到最复杂的9×9的拼图。每个难度等级的图片都是从某一主题中选择的。 为了保证游戏的趣味性,程序会随机打乱图片的顺序。玩家可通过鼠标点击来调整不同图片的位置,当所有图片的位置都调整正确,即形成一张完整的图片时,游戏就会提示玩家拼图成功。 Python拼图游戏的开发不仅提高了玩家的动手能力和思维能力,也锻炼了程序员的编程技能和团队协作能力。同时,由于Python语言简单易懂,该游戏的代码逻辑也十分清晰,对于学习Python编程的初学者来说,也是一款很好的练手项目。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值