pygame交换式拼图设计

运行截图

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

完成时候的截图
在这里插入图片描述

游戏设计思想

在600*600的屏幕上,进行拼图划分。(可以是N * M不一定是N * N)
利用鼠标来操作拼图移动

游戏设计

制作一个类:PartPicture用来保存分块图片的信息(分块图像,位置x,y,以及每个图片的id)

class PartPicture:
    # 初始化一个图片分块,保存图像和图像的位置, id代表原图第几块的位置
    def __init__(self, img, x, y, id):
        self.img = img
        self.x = x
        self.y = y
        self.id = id
	# get和set方法
    def getX(self):
        return self.x;
    def getY(self):
        return self.y
    # 获取图片坐标
    def getXY(self):
        return self.x, self.y
    # 修改图片坐标
    def setXY(self,x, y):
        self.x = x
        self.y = y
    # 获取id
    def getId(self):
        return self.id

现在这个类还没有完善,等下我们再完善它

pygame游戏的初始信息

设置默认的游戏屏幕大小,拼图划分的数量,以及每块拼图的大小,firstClickCell用来记录以后第一次点击的图片,successFlag用来保存是否游戏成功

SCREEN_WIDTH = 600
SCREEN_HEIGHT = 600
ROW = 0
COL = 0
CELL_WIDTH = 0#SCREEN_WIDTH / COL
CELL_HEIGHT = 0#SCREEN_HEIGHT / ROW
firstClickCell = None
successFlag = False

设置pygame的初始参数

pygame.init()  # 初始化pygame
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))  # 创建了一个窗口 大小是(宽,高)
pygame.display.set_caption('交换式拼图')  # 设置窗口标题

制作开始界面

设置颜色RGB以及设置相关字体

GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
RED = (255, 0, 0)
myfont = pygame.font.Font(None, 70)
textImage1 = myfont.render("simple", True , GREEN)
textImage2 = myfont.render("difficult", True , BLUE)
textImage3 = myfont.render("bow!!!", True , RED)
setInit = False

开始界面选择拼图难度,setInit用来保存是否初始化设置,点击相关难度,然后开始进行初始化设置(拼图的各个大小块,可以是N*M比如3 * 4或者4 * 3)也就是ROW和COL的值

setInit = False
while True:
    if setInit:
        break
    for event in pygame.event.get():
        if event.type == QUIT:
            exit()  # 接收到退出事件后退出程序
        elif event.type == MOUSEBUTTONDOWN:
            b1, b2, b3 = pygame.mouse.get_pressed()
            if b1 == 1:
                point_x, point_y = pygame.mouse.get_pos()  # 返回鼠标当前坐标
                if 100 < point_y < 250:
                    ROW = 4
                    COL = 4
                    setInit = True
                elif 250 < point_y < 400:
                    ROW = 10
                    COL = 10
                    setInit = True
                elif 400 < point_y < 550:
                    ROW = 100
                    COL = 100
                    setInit = True
    screen.fill((0,0,0))
    screen.blit(textImage1, (200, 100))
    screen.blit(textImage2, (200, 250))
    screen.blit(textImage3, (200, 400))
    pygame.display.update()
CELL_WIDTH = SCREEN_WIDTH / COL
CELL_HEIGHT = SCREEN_HEIGHT / ROW

载入图片和图片分割

imgSrc = pygame.image.load('src.jpg').convert()  # 原图 提高 blit 的速度 convert_alpha相对于convert,保留了图像的Alpha 通道信息,可以认为是保留了透明的部分,实现了透明转换
PictureList = devide(imgSrc)

图片分割的核心代码

# 图片分块的方法
def devide(imgSrc):
    # 切割原来的图片
    pictures = []
    ScPictures = []
    id = 0 # 给每个分块的图片设置下标
    for i in range(ROW):
        for j in range(COL):
            # 提取部分图片
            partOfPicutre = imgSrc.subsurface(j * CELL_WIDTH, i * CELL_HEIGHT, CELL_WIDTH, CELL_HEIGHT)
            # 保存第一组图片
            tempPicture = PartPicture(partOfPicutre, j * CELL_WIDTH, i * CELL_HEIGHT, id)
            pictures.append(tempPicture)
            # 保存第二组图片
            tempPicture = PartPicture(partOfPicutre, j * CELL_WIDTH, i * CELL_HEIGHT, id)
            ScPictures.append(tempPicture)
            id += 1
    random.shuffle(pictures)
    # 开始利用第二组图片来打乱原来的图片
    for i in range(len(pictures)):
        pictures[i].setXY(ScPictures[i].getX(), ScPictures[i].getY())
    return pictures # 把打乱的图片返回

我们完善PartPicture类

我们让这个类来操作图片的移动,isPressed()我们需要判断鼠标点击的第一个图片,并且利用isOver()方法来锁定我们选择的图片。保存好第一个图片以后,firstClickCell就有值了,当我们再次点击的时候,我们就把第一个图片和第二次选择的图片交换(可以是自己),交换完毕后我们再把firstClickCell复原。其中每次操作我们都需要判断是否完成拼图,完成拼图判断是否拼图在原来的位置,我们可以利用id属性获取行和列的块的位置,然后计算出相关坐标,如果有一个不符合拼图就没有完成

class PartPicture:
    # 初始化一个图片分块,保存图像和图像的位置, id代表原图第几块的位置
    def __init__(self, img, x, y, id):
        self.img = img
        self.x = x
        self.y = y
        self.id = id
    # 判断是否在图片内
    def isOver(self):
        w, h = self.img.get_size()
        point_x, point_y = pygame.mouse.get_pos()  # 返回鼠标当前坐标
        in_x = self.x < point_x < self.x + w
        in_y = self.y < point_y < self.y + h
        #('id,x,y', self.id,':' ,self.getX(), ',',self.getY())
        #print('id', self.id, in_x, in_y)
        return in_x and in_y
    # 检测移动
    def isPressed(self, pictureList):
        # print('is_pressed')
        if self.isOver():
            b1, b2, b3 = pygame.mouse.get_pressed()
            if b1 == 1:
                global firstClickCell
                global successFlag

                if firstClickCell is None:
                    firstClickCell = self
                    print('id为{}的块被点击'.format(firstClickCell.getId()))
                else:
                    print('交换{}与{}的坐标'.format(firstClickCell.getId(), self.getId()))
                    self.pictureSwitch(firstClickCell, self)
                    if self.isFinish(pictureList):
                        print('成功!')
                        successFlag = True
                    else:
                        successFlag = False
                    firstClickCell = None
                return True
        return False
    # 判断拼图完成
    def isFinish(self, pictureList):
        for cell in  pictureList:
            nowp_x, nowp_y = cell.getXY()
            p_x = cell.getId() % COL * CELL_WIDTH
            p_y = (cell.getId() // COL) * CELL_HEIGHT
            print("id{} nowx{}与nowy{}的坐标 本来的坐标x{}y{}".format(cell.getId(), nowp_x, nowp_y, p_x, p_y))
            if nowp_x != p_x or nowp_y != p_y:
                return False
        return True

    def pictureSwitch(self, cell1, cell2):
        tempX = cell1.getX()
        tempY = cell1.getY()
        cell1.setXY(cell2.getX(), cell2.getY())
        cell2.setXY(tempX, tempY)
    def render(self, screen):
        screen.blit(self.img, (self.x, self.y))

真正的游戏循环

while True:  # 游戏主循环
    for event in pygame.event.get():
        if event.type == QUIT:
            exit()  # 接收到退出事件后退出程序
        elif event.type == MOUSEBUTTONDOWN:
            for cell in PictureList:
                # 检测按键按下,并且交换图片位置
                if cell.isPressed(PictureList):
                    break
    for partPicture in PictureList:
        partPicture.render(screen)
    if not successFlag:
        # # Sta 绘制分割线
        for i in range(1, COL):
            pygame.draw.lines(screen, GREEN, 0, [(i * SCREEN_WIDTH // COL, 0), (i * SCREEN_WIDTH // COL, SCREEN_HEIGHT)], 1)
        for i in range(1, ROW):
            pygame.draw.lines(screen, GREEN, 0, [(0, i * SCREEN_HEIGHT // ROW), (SCREEN_WIDTH, i * SCREEN_HEIGHT // ROW)], 1)
        # End 绘制分割线
    pygame.display.update()  # 刷新一下画面

完整代码

图像为src,600*600大小

import random
from sys import exit  # 使用sys模块的exit函数来退出游戏
import pygame
from pygame.locals import *  # 导入一些常用的函数和常量

SCREEN_WIDTH = 600
SCREEN_HEIGHT = 600
ROW = 100
COL = 100
CELL_WIDTH = 0#SCREEN_WIDTH / COL
CELL_HEIGHT = 0#SCREEN_HEIGHT / ROW
firstClickCell = None

class PartPicture:
    # 初始化一个图片分块,保存图像和图像的位置, id代表原图第几块的位置
    def __init__(self, img, x, y, id):
        self.img = img
        self.x = x
        self.y = y
        self.id = id
    # 判断是否在图片内
    def isOver(self):
        w, h = self.img.get_size()
        point_x, point_y = pygame.mouse.get_pos()  # 返回鼠标当前坐标
        in_x = self.x < point_x < self.x + w
        in_y = self.y < point_y < self.y + h
        #('id,x,y', self.id,':' ,self.getX(), ',',self.getY())
        #print('id', self.id, in_x, in_y)
        return in_x and in_y
    # 检测移动
    def isPressed(self, pictureList):
        # print('is_pressed')
        if self.isOver():
            b1, b2, b3 = pygame.mouse.get_pressed()
            if b1 == 1:
                global firstClickCell
                global successFlag

                if firstClickCell is None:
                    firstClickCell = self
                    print('id为{}的块被点击'.format(firstClickCell.getId()))
                else:
                    print('交换{}与{}的坐标'.format(firstClickCell.getId(), self.getId()))
                    self.pictureSwitch(firstClickCell, self)
                    if self.isFinish(pictureList):
                        print('成功!')
                        successFlag = True
                    else:
                        successFlag = False
                    firstClickCell = None
                return True
        return False
    # 判断拼图完成
    def isFinish(self, pictureList):
        for cell in  pictureList:
            nowp_x, nowp_y = cell.getXY()
            p_x = cell.getId() % COL * CELL_WIDTH
            p_y = (cell.getId() // COL) * CELL_HEIGHT
            print("id{} nowx{}与nowy{}的坐标 本来的坐标x{}y{}".format(cell.getId(), nowp_x, nowp_y, p_x, p_y))
            if nowp_x != p_x or nowp_y != p_y:
                return False
        return True

    def pictureSwitch(self, cell1, cell2):
        tempX = cell1.getX()
        tempY = cell1.getY()
        cell1.setXY(cell2.getX(), cell2.getY())
        cell2.setXY(tempX, tempY)
    def render(self, screen):
        screen.blit(self.img, (self.x, self.y))
    # get和set方法
    def getX(self):
        return self.x;
    def getY(self):
        return self.y
    # 获取图片坐标
    def getXY(self):
        return self.x, self.y
    # 修改图片坐标
    def setXY(self,x, y):
        self.x = x
        self.y = y
    # 获取id
    def getId(self):
        return self.id
# 图片分块的方法
def devide(imgSrc):
    # 切割原来的图片
    pictures = []
    ScPictures = []
    id = 0 # 给每个分块的图片设置下标
    for i in range(ROW):
        for j in range(COL):
            # 提取部分图片
            partOfPicutre = imgSrc.subsurface(j * CELL_WIDTH, i * CELL_HEIGHT, CELL_WIDTH, CELL_HEIGHT)
            # 保存第一组图片
            tempPicture = PartPicture(partOfPicutre, j * CELL_WIDTH, i * CELL_HEIGHT, id)
            pictures.append(tempPicture)
            # 保存第二组图片
            tempPicture = PartPicture(partOfPicutre, j * CELL_WIDTH, i * CELL_HEIGHT, id)
            ScPictures.append(tempPicture)
            id += 1
    random.shuffle(pictures)
    # 开始利用第二组图片来打乱原来的图片
    for i in range(len(pictures)):
        pictures[i].setXY(ScPictures[i].getX(), ScPictures[i].getY())
    return pictures # 把打乱的图片返回

pygame.init()  # 初始化pygame
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))  # 创建了一个窗口 大小是(宽,高)
pygame.display.set_caption('交换式拼图')  # 设置窗口标题
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
RED = (255, 0, 0)
myfont = pygame.font.Font(None, 70)
textImage1 = myfont.render("simple", True , GREEN)
textImage2 = myfont.render("difficult", True , BLUE)
textImage3 = myfont.render("bow!!!", True , RED)
setInit = False
while True:
    if setInit:
        break
    for event in pygame.event.get():
        if event.type == QUIT:
            exit()  # 接收到退出事件后退出程序
        elif event.type == MOUSEBUTTONDOWN:
            b1, b2, b3 = pygame.mouse.get_pressed()
            if b1 == 1:
                point_x, point_y = pygame.mouse.get_pos()  # 返回鼠标当前坐标
                if 100 < point_y < 250:
                    ROW = 4
                    COL = 4
                    setInit = True
                elif 250 < point_y < 400:
                    ROW = 10
                    COL = 10
                    setInit = True
                elif 400 < point_y < 550:
                    ROW = 100
                    COL = 100
                    setInit = True
    screen.fill((0,0,0))
    screen.blit(textImage1, (200, 100))
    screen.blit(textImage2, (200, 250))
    screen.blit(textImage3, (200, 400))
    pygame.display.update()
CELL_WIDTH = SCREEN_WIDTH / COL
CELL_HEIGHT = SCREEN_HEIGHT / ROW
imgSrc = pygame.image.load('src.jpg').convert()  # 原图 提高 blit 的速度 convert_alpha相对于convert,保留了图像的Alpha 通道信息,可以认为是保留了透明的部分,实现了透明转换
PictureList = devide(imgSrc)

# 标记是否游戏成功
successFlag = False

while True:  # 游戏主循环
    for event in pygame.event.get():
        if event.type == QUIT:
            exit()  # 接收到退出事件后退出程序
        elif event.type == MOUSEBUTTONDOWN:
            for cell in PictureList:
                # 检测按键按下,并且交换图片位置
                if cell.isPressed(PictureList):
                    break
    for partPicture in PictureList:
        partPicture.render(screen)
    if not successFlag:
        # # Sta 绘制分割线
        for i in range(1, COL):
            pygame.draw.lines(screen, GREEN, 0, [(i * SCREEN_WIDTH // COL, 0), (i * SCREEN_WIDTH // COL, SCREEN_HEIGHT)], 1)
        for i in range(1, ROW):
            pygame.draw.lines(screen, GREEN, 0, [(0, i * SCREEN_HEIGHT // ROW), (SCREEN_WIDTH, i * SCREEN_HEIGHT // ROW)], 1)
        # End 绘制分割线
    pygame.display.update()  # 刷新一下画面

附图片附图片

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值