最开始的时候想做一个类似于现实中拼图的游戏,但是在网上看了一些,都是类似于华容道的移动型拼图游戏,而且之前就写过华容道。所以想做一个比较符合真实拼图的游戏。
在现实中买的拼图,它们的每一个单元都有凹凸的效果。但对它们的凹凸分析一下可以知道,拼图的凹凸设计是为了实现拼图块的稳固,不是增加拼图的难度,甚至由于凹凸部分具有相邻凹凸块的特性还会降低拼图的难度,所以可以只做成方形的即可。当然,如果拼图单元想做成凹凸效果,由于图片的显示单元都是矩形,所以只能将几个矩形部分的图片打包成一个拼图凹凸单元,其凹凸的部分可以根据哈尔伯特空间曲线确认。
第一步,我们准备一张图片,其宽高最好先处理好,以防不好分割。先得到一些关于图片的数据及分割之后的宽高、拼图块个数等。我找的是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()