使用Pygame制作2048小游戏

Posted 哈拉泽空

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用Pygame制作2048小游戏相关的知识,希望对你有一定的参考价值。

好久没有写文章了,暑假一直没有怎么学习计算机方面的相关知识,不过倒是坚持背了一个多月的单词红宝书,看了汤神的基础课。真的没想到自己居然也能有毅力背了150多页的单词,还写完了一本正反面的字帖这些事以前从来没坚持下来过,可能就是长大了懂事了吧,hhh。还练了科三。后天第三次考了,希望这次能考过。
吃完晚饭闲来无事,准备回归从前写写小文章。现在先来分享一下我的python课两个期末大作业之一——Pygame开发的2048

这个2048项目主干部分是我在基于Python的PyGame库实现的2048小游戏上找的,自己加了音乐,主菜单,界面,重开本关,回到上一步,记录最高得分

游戏完整代码在第三部分,不想看讲解的可以直接拉到Part3

一、游戏效果展示

1.运行程序,出现欢迎界面。点击鼠标左键后,出现主菜单界面。          
                                          

2.分别点击“玩法介绍”和“游戏技巧”,进入查看相应的界面。

                                          

3.点击“开始游戏”按钮,进入游戏。操纵上下左右不断合并方块来提高分数。

                                        

4.当走错了步骤时,按一下空格间。可以回到上一步。

                                        

5.当游戏失败后,点击“New Game”按钮进行一局新的游戏。

                                        

6.当游戏进行不下去或者认为没有操作好的时候,系统自动判定失败。此时还可以点击NewGame重新进行一局游戏。                  

                                                      

7.右上角存在记分牌,可以记录玩家本机最高得分。

二、功能模块开发详细介绍

下面我将从七个部分讲解各个部分的功能,设计思想。可能会有点多,看不懂很正常,多思考多运行多体会。毕竟想要一下弄懂别人花了两周心血写的大作业可不是一件容易的事情呀。当时我打算题目写2048的时候也没着急着先写,就先去网上玩了一周的2048^ ^。对我这种手残党还是有很大帮助的。

1.欢迎界面和主菜单

这个部分是纯属为了凑代码行数加的,当时我第一遍写完了只有300行左右,谁知道老师晚上上课专门说了码量起码500+,当时直接我晕!咱就写个简单的2048么,又不像琪哥睿哥写什么高级的超级玛丽和连连看,剩下那200行怎么凑,而且这都写完了,莫不是天要亡我?后来苦思冥想,加了个主菜单,做了个游戏说明故意打了很多行汉字来凑数,加了个播放音乐的功能,哈哈哈,机智如我,不过就是被井大爷批的很惨,/(ㄒoㄒ)/~~

def game_view_page0():#游戏欢迎界面,这里实现了一个动画功能:两排大小颜色不同的“2048小游戏”绕屏幕中心进行旋转
    FPS = 5
    BLACK = (0, 0, 0)
    BROWN = (187, 173, 160)
    WHITE = (255, 255, 255)
    BGCOLOR = BROWN
    titleFont = pygame.font.Font(r'C:\\Windows\\Fonts\\simkai.ttf', 100)
    titleSurf1 = titleFont.render('2048小游戏', True, BLACK)
    titleSurf2 = titleFont.render('2048小游戏', True, WHITE)
    degrees1 = 0
    degrees2 = 0
    while True:
        for event in pygame.event.get():
            if event.type == QUIT:
                pygame.quit()
                exit()
            elif event.type == pygame.MOUSEBUTTONDOWN or event.type == KEYUP:
                return
        screen.fill(BGCOLOR)
        rotatedSurf1 = pygame.transform.rotate(titleSurf1, degrees1)
        rotatedRect1 = rotatedSurf1.get_rect()
        rotatedRect1.center = (screen_width / 2, screen_height / 2 - 50)
        screen.blit(rotatedSurf1, rotatedRect1)
        rotatedSurf2 = pygame.transform.rotate(titleSurf2, degrees2)
        rotatedRect2 = rotatedSurf2.get_rect()
        rotatedRect2.center = (screen_width / 2, screen_height / 2 - 50)
        screen.blit(rotatedSurf2, rotatedRect2)
        screen.blit(write("点击鼠标左键进入游戏", height=30, color=(255, 255, 255)),
                    (left_of_screen + 60, left_of_screen // 2 + 450))
        pygame.display.update()
        FPSCLOCK.tick(10)
        degrees1 += 3
        degrees2 += 5

都是一些Pygame的基本操作,game_view_page0()函数用于绘制一个开始的欢迎界面,界面中有两行以窗口中心为轴进行旋转的文字“2048”,点击鼠标左键进入主菜单。

2.玩法介绍和高分技巧介绍

同1部分,为了凑行数= =

def game_start_page():#游戏开始界面
    #加载背景图片
    screen.blit(background, (0, 0))
    #创建几个自定义的按钮
    button4 = Button((left_of_screen + 110, 150), b4, 200, 80)
    button5 = Button((left_of_screen + 110, 270), b5, 200, 80)
    button6 = Button((left_of_screen + 110, 390), b6, 200, 80)
    while True:
        for event in pygame.event.get():
            if event.type == QUIT or (event.type == KEYUP and event.key == K_ESCAPE):
                pygame.quit()
                exit()
            elif event.type == pygame.MOUSEBUTTONDOWN:
                if button4.isOver() == True:#如果按下的是button4,即开始游戏
                    return
                elif button5.isOver() == True:#如果按下的是button5,即游戏玩法介绍
                    game_introduce()
                    screen.blit(background, (0, 0))
                    button4 = Button((left_of_screen + 110, 150), b4, 200, 80)
                    button5 = Button((left_of_screen + 110, 270), b5, 200, 80)
                    button6 = Button((left_of_screen + 110, 390), b6, 200, 80)
                elif button6.isOver() == True:#如果按下的是button6,即游戏技巧介绍
                    game_skill()
                    screen.blit(background, (0, 0))
                    button4 = Button((left_of_screen + 110, 150), b4, 200, 80)
                    button5 = Button((left_of_screen + 110, 270), b5, 200, 80)
                    button6 = Button((left_of_screen + 110, 390), b6, 200, 80)
            screen.blit(write("2048", height=100, color=(119, 110, 101)),
                        (left_of_screen + 110, left_of_screen // 2))
            pygame.display.update()

game_start_page()函数用于绘制一个游戏主菜单,玩家可在主菜单中选择自己下一步将要进行的步骤。

欢迎界面中首先需要设置游戏首页旋转文字的字体大小和文字内容,然后以文字的中心点,设置文字摆放位置,刷新频率FPS设置为10时流畅度比较符合要求。将其放在while True死循环中即可绘制出欢迎界面。

主菜单放置了三个能导向不同界面的自定义按钮组件Button,Button中的is_Over()函数可以判断用户是否将鼠标放在按钮上进行了点击;Button的样子用不同的的图片加载。

class Button(object):#此类是一个自定义好的按钮类,用在游戏中出现的各种按钮
    def __init__(self, position, fileName, sizex, sizey):#初始化该按钮,包括加载图片,初始位置,按钮大小
        self.imageUp = pygame.image.load(fileName).convert_alpha()
        self.position = position
        self.imageUp = pygame.transform.scale(self.imageUp, (sizex, sizey))
        screen.blit(self.imageUp, self.position)

    def isOver(self):#判断鼠标是否放在该按钮上
        point_x, point_y = pygame.mouse.get_pos()
        x, y = self.position
        w, h = self.imageUp.get_size()

        in_x = x < point_x < x + w
        in_y = y < point_y < y + h
        return in_x and in_y

    def render(self):#判断是否要重新开始一局游戏
        global score
        w, h = self.imageUp.get_size()
        x, y = self.position
        if self.isOver() == True:
            score = 0
            draw_box(0)
            init_board()

图片文件夹截图:

                                       

game_introduce()用于显示游戏玩法介绍界面。

game_skill()用于显示游戏技巧介绍界面。

设置好要加载的文字和位置,然后调用screen.blit函数将他们加载到屏幕上。

3.方块的移动与合并(重难点)

其实这部分我也是网上copy的,这一部分的逻辑比较强,是方块合并移动的原理部分。

combinate()函数用来执行相同方块的合并操作。

up()函数用来对应游戏中用户按下“上”键后,对应向上合并方块的操作。

down()函数用来对应用游戏中户按下“下”键后,对应向下合并方块的操作。

left()用来对应游戏中用户按下“左”键后,对应向左合并方块的操作。

right()用来对应游戏中用户按下“右”键后,对应向右合并方块的操作。

combinate()合并运算设计思想:

要执行一行中相同方块的合并,首先从左到右将这一行的数字们存入一个新的列表ans中:

(1)当ans中有两个数字时,直接将他们相加合并。把相加后的新的一行返回。score加上相应的得分。

(2)当ans中有三个数字时,我们首先判断ans[0]和ans[1]是否相等,相等合并二者;否则判断and[1]和ans[2]。共两种可能合并的情况。再把score加上相应的的得分。

(3)当ans中有四个数字时同理,需要判断ans[0]和ans[1],ans[1]和ans[2],ans[2]和ans[3],有三种可能合并的情况。

向左合并时从上到下一行一行的进行combinate()运算;向右合并时将每一行左右逆序即可;向上合并时从左到右一列一列进行combinate()运算;向下合并时与向上上下逆序即可。

感觉说了这么多啊,= =其实你只要拿张纸画画,分三种情况,好像也不是太难?

def combinate(L):#此函数的功能是进行方块的合并原理,是本程序的重难点所在
    global score
    ans = [0, 0, 0, 0]
    num = []
    for i in L:
        if i != 0:#把本行中所有的数字放到列表num中去
            num.append(i)
    length = len(num)
    if length == 4:#本行中有4个数字
        if num[0] == num[1]:#case1
            ans[0] = num[0] + num[1]
            score += ans[0]
            if num[2] == num[3]:
                ans[1] = num[2] + num[3]
                score += ans[1]
            else:
                ans[1] = num[2]
                ans[2] = num[3]
        elif num[1] == num[2]:#case2
            ans[0] = num[0]
            ans[1] = num[1] + num[2]
            ans[2] = num[3]
            score += ans[1]
        elif num[2] == num[3]:#case3
            ans[0] = num[0]
            ans[1] = num[1]
            ans[2] = num[2] + num[3]
            score += ans[2]
        else:#case4 没有能合并的数字
            for i in range(length):
                ans[i] = num[i]
    elif length == 3:#本行中有3个数字
        if num[0] == num[1]:#case 1
            ans[0] = num[0] + num[1]
            ans[1] = num[2]
            score += ans[0]
        elif num[1] == num[2]:#case 2
            ans[0] = num[0]
            ans[1] = num[1] + num[2]
            score += ans[1]
        else:#case 3 没有能合并的数字
            for i in range(length):
                ans[i] = num[i]
    elif length == 2:#本行中有2个数字
        if num[0] == num[1]:#case 1
            ans[0] = num[0] + num[1]
            score += ans[0]
        else:#case 2 没有能合并的数字
            for i in range(length):
                ans[i] = num[i]
    elif length == 1:
        ans[0] = num[0]
    else:
        pass
    return ans


def left():#用户按下左键进行的移动
    for i in range(4):
        temp = combinate(board[i])
        for j in range(4):
            board[i][j] = temp[j]


def right():#用户按下右键进行的移动
    for i in range(4):
        temp = combinate(board[i][::-1])
        for j in range(4):
            board[i][3 - j] = temp[j]


def up():#用户按下上键进行的移动
    for i in range(4):
        to_comb = []
        for j in range(4):
            to_comb.append(board[j][i])
        temp = combinate(to_comb)
        for k in range(4):
            board[k][i] = temp[k]


def down():#用户按下下键进行的移动
    for i in range(4):
        to_comb = []
        for j in range(4):
            to_comb.append(board[3 - j][i])
        temp = combinate(to_comb)
        for k in range(4):
            board[3 - k][i] = temp[k]

4.“重新开始”功能

当用户点击重新开始按钮时,重新加载一局游戏。

设置一个Button类接受用户的点击,通过self.is_Over()函数判断用户当前的鼠标位置和按钮位置是否重叠。当用户点击按钮时,调用self.render()函数,对score分数,board游戏面板进行初始化。

5.记录得分和最高分

记录本机的最高得分并显示在high score处。

用txt文件存储本机最高得分,每一局失败时判断当前得分是否高于最高得分,with open覆盖写入模式打开文件,将分数写入txt文件进行保存。每次运行时读取模式读出最高得分,调用screen.blit显示在high score部分处。

6.“回到上一步"功能

用户走错时可以点击空格键回到上一步。

设置一个tmpScore和列表b存储上一步的分数和游戏情况。按下空格键后将上一步的状态赋值给当前的状态,刷新界面就可以实现回退的功能。

7.判负和判胜

判断用户本局游戏失败或胜利。

循环遍历二位列表board中元素。当列表board中没有空格,即没有0元素时,本局游戏失败;当列表board中出现数字2048时,本局游戏成功。将信息打印到屏幕上对用户进行相应的提示。

def win():#判断当前是否胜利
    for i in range(4):
        for j in range(4):
            if board[i][j] == 2048:#有2048,肯定是胜利了
                return True
    return False


def is_over():#判断当前是否失败
    for i in range(4):
        for j in range(4):
            if board[i][j] == 0:#有0,还有空白处,肯定不算失败
                return False
    for i in range(4):
        for j in range(3):
            if board[i][j] == board[i][j + 1]:#左右有相同的字母,还能够合并,肯定不算失败
                return False
    for i in range(3):
        for j in range(4):
            if board[i][j] == board[i + 1][j]:#上下有相同的字母,还能够合并,肯定不算失败
                return False
    return True#失败了

三、完整程序代码

#本程序用到的一些库
import os
import random
import pygame
from sys import exit
from copy import deepcopy
from pygame.locals import *

pygame.init()
FPS = 5
b4 = "button4.jpg"
b5 = "button5.jpg"
b6 = "button6.jpg"
folder = r'C:\\Users\\longlong\\Music'
musics = [folder + '\\\\' + music for music in os.listdir(folder)
          if music.endswith('.mp3')]
total = len(musics)
pygame.mixer.init()

board = [[0, 0, 0, 0],
         [0, 0, 0, 0],
         [0, 0, 0, 0],
         [0, 0, 0, 0]]

box_size = 100  # 每个小方格
box_gap = 5  # 每个小方格与每个小方格之间的间距
top_of_screen = 100  # 格子到窗口顶端的距离
bottom_of_screen = 20  # 格子到窗口底端的距离
left_of_screen = 50  # 格子到窗口左端的距离
screen_width = 520  # 游戏界面的宽
screen_height = 600  # 游戏界面的高度
screen = pygame.display.set_mode((screen_width, screen_height), 0, 32)  # 初始化一个准备显示的窗口或屏幕
pygame.display.set_caption("My2048")  # 设置游戏窗口标题
background = pygame.image.load('background3.jpg').convert()  # 设置游戏背景图
high_score_name = "high_score.txt"
score = 0  # 得分
tmpScore = 0
high_score = 0


def play_music():#此函数的功能是播放音乐
    if not pygame.mixer.music.get_busy():
        nextMusic = random.choice(musics)
        pygame.mixer.music.load(nextMusic)
        pygame.mixer.music.play(1)
    else:
        time.sleep(1)


class Button(object):#此类是一个自定义好的按钮类,用在游戏中出现的各种按钮
    def __init__(self, position, fileName, sizex, sizey):#初始化该按钮,包括加载图片,初始位置,按钮大小
        self.imageUp = pygame.image.load(fileName).convert_alpha()
        self.position = position
        self.imageUp = pygame.transform.scale(self.imageUp, (sizex, sizey))
        screen.blit(self.imageUp, self.position)

    def isOver(self):#判断鼠标是否放在该按钮上
        point_x, point_y = pygame.mouse.get_pos()
        x, y = self.position
        w, h = self.imageUp.get_size()

        in_x = x < point_x < x + w
        in_y = y < point_y < y + h
        return in_x and in_y

    def render(self):#判断是否要重新开始一局游戏
        global score
        w, h = self.imageUp.get_size()
        x, y = self.position
        if self.isOver() == True:
            score = 0
            draw_box(0)
            init_board()


class Box:
    def __init__(self, topleft, text, color):
        self.topleft = topleft
        self.text = text
        self.color = color

    def render(self, surface):
        x, y = self.topleft
        pygame.draw.rect(surface, self.color, (x, y, box_size, box_size), 0)
        text_height = 35
        font_obj = pygame.font.SysFont("arial", text_height)
        text_surface = font_obj.render(self.text, True, (0, 0, 0))
        text_rect = text_surface.get_rect()
        text_rect.center = (x + 50, y + 50)
        surface.blit(text_surface, text_rect)


def load_data():#读取本地txt文件中的本机最高得分
    with open(high_score_name, "r") as f:
        high = int(f.read())
        return high


def draw_box(type):#绘制游戏棋盘界面,用一个4x4的列表表示
    global board
    if type == 0:
        board = [[0, 0, 0, 0],
                 [0, 0, 0, 0],
                 [0, 0, 0, 0],
                 [0, 0, 0, 0]]
    colors = #各种不同的RGB色彩混合,完全按照原版2048仿制
        0: (205, 193, 180),
        2: (238, 228, 218),
        4: (237, 224, 200),
        8: (242, 177, 121),
        16: (245, 149, 99),
        32: (246, 124, 95),
        64: (246, 94, 59),
        128: (237, 207, 114),
        256: (237, 204, 98),
        512: (237, 200, 80),
        1024: (237, 197, 63),
        2048: (225, 187, 0)
    
    x, y = left_of_screen, top_of_screen
    size = 425
    pygame.draw.rect(screen, (187, 173, 160), (x, y, size, size))
    x, y = x + box_gap, y + box_gap
    for i in range(4):
        for j in range(4):
            idx = board[i][j]
            if idx == 0:
                text = ""
            else:
                text = str(idx)
            if idx > 2048:
                idx = 2048
            color = colors[idx]
            box = Box((x, y), text, color)
            box.render(screen)
            x += box_size + box_gap
        x = left_of_screen + box_gap
        y += top_of_screen + box_gap


def set_random_number():#此函数的功能是用户每移动一步后在数字0处随机产生一个2或4
    num = []
    for i in range(4):
        for j in range(4):
            if board[i][j] == 0:
                num.append((i, j))
    m = random.choice(num)
    num.remove(m)
    value = random.uniform(0, 1)
    if value < 0.1:#产生4的概率要小一点
        value = 4
    else:
        value = 2
    board[m[0]][m[1]] = value


def init_board():#游戏开始时初始化棋盘:随机产生两个2/4
    for i in range(2):
        set_random_number()


def combinate(L):#此函数的功能是进行方块的合并原理,是本程序的重难点所在
    global score
    ans = [0, 0, 0, 0]
    num = []
    for i in L:
        if i != 0:#把本行中所有的数字放到列表num中去
            num.append(i)
    length = len(num)
    if length == 4:#本行中有4个数字
        if num[0] == num[1]:#case1
            ans[0] = num[0] + num[1]
            score += ans[0]
            if num[2] == num[3]:
                ans[1] = num[2] + num[3]
                score += ans[1]
            else:
                ans[1] = num[2]
                ans[2] = num[3]
        elif num[1] == num[2]:#case2
            ans[0] = num[0]
            ans[1] = num[1] + num[2]
            ans[2] = num[3]
            score += ans[1]
        elif num[2] == num[3]:#case3
            ans[0] = num[0]
            ans[1] = num[1]
            ans[2] = num[2] + num[3]
            score += ans[2]
        else:#case4 没有能合并的数字
            for i in range(length):
                ans[i] = num[i]
    elif length == 3:#本行中有3个数字
        if num[0] == num[1]:#case 1
            ans[0] = num[0] + num[1]
            ans[1] = num[2]
            score += ans[0]
        elif num[1] == num[2]:#case 2
            ans[0] = num[0]
            ans[1] = num[1] + num[2]
            score += ans[1]
        else:#case 3 没有能合并的数字
            for i in range(length):
                ans[i] = num[i]
    elif length == 2:#本行中有2个数字
        if num[0] == num[1]:#case 1
            ans[0] = num[0] + num[1]
            score += ans[0]
        else:#case 2 没有能合并的数字
            for i in range(length):
                ans[i] = num[i]
    elif length == 1:
        ans[0] = num[0]
    else:
        pass
    return ans


def left():#用户按下左键进行的移动
    for i in range(4):
        temp = combinate(board[i])
        for j in range(4):
            board[i][j] = temp[j]


def right():#用户按下右键进行的移动
    for i in range(4):
        temp = combinate(board[i][::-1])
        for j in range(4):
            board[i][3 - j] = temp[j]


def up():#用户按下上键进行的移动
    for i in range(4):
        to_comb = []
        for j in range(4):
            to_comb.append(board[j][i])
        temp = combinate(to_comb)
        for k in range(4):
            board[k][i] = temp[k]


def down():#用户按下下键进行的移动
    for i in range(4):
        to_comb = []
        for j in range(4):
            to_comb.append(board[3 - j][i])
        temp = combinate(to_comb)
        for k in range(4):
            board[3 - k][i] = temp[k]


def write(msg="Winning!!!", color=(255, 255, 0), height=14):#在屏幕上打印字体
    path = 'C:/Windows/Fonts/simhei.ttf'
    myfont = pygame.font.SysFont("simsunnsimsun", height)
    mytext = myfont.render(msg, True, color)
    mytext = mytext.convert_alpha()
    return mytext


def win():#判断当前是否胜利
    for i in range(4):
        for j in range(4):
            if board[i][j] == 2048:#有2048,肯定是胜利了
                return True
    return False


def is_over():#判断当前是否失败
    for i in range(4):
        for j in range(4):
            if board[i][j] == 0:#有0,还有空白处,肯定不算失败
                return False
    for i in range(4):
        for j in range(3):
            if board[i][j] == board[i][j + 1]:#左右有相同的字母,还能够合并,肯定不算失败
                return False
    for i in range(3):
        for j in range(4):
            if board[i][j] == board[i + 1][j]:#上下有相同的字母,还能够合并,肯定不算失败
                return False
    return True#失败了


def game_skill():#游戏技巧介绍
    button_back = Button((left_of_screen + 140, 480), "button_back.jpg", 130, 50)
    screen.blit(background, (0, 0))
    while True:
        for event in pygame.event.get():
            if event.type == QUIT or (event.type == KEYUP and event.key == K_ESCAPE):
                pygame.quit()
                exit()
            elif event.type == pygame.MOUSEBUTTONDOWN:
                if button_back.isOver() == True:
                    return
            pygame.display.update()
            rect = pygame.draw.rect(screen, (251, 248, 241), (10, 10, 500, 580))
            screen.blit(write("1、简单点来说就是尽量不要向上。", height=30, color=(119, 110, 101)), (30, 165))
            screen.blit(write("滑动就可以了,尽量用左下右三个", height=30, color=(119, 110, 101)), (30, 195))
            screen.blit(write("键游戏,让大的方块尽量沉在底部", height=30, color=(119, 110, 101)), (30, 225))
            screen.blit(write("2、数越来越大以后,较大的数要", height=30, color=(119, 110, 101)), (30, 255))
            screen.blit(write("依次靠着这个。让一行中数字顺序", height=30, color=(119, 110, 101)), (30, 285))
            screen.blit(write("紧邻排列。不要总是急于清理桌面。", height=30, color=(119, 110, 101)), (30, 315))
            screen.blit(write("3、因为尽量不向上滑动,所以大的", height=30, color=(119, 110, 101)), (30, 345))
            screen.blit(write("数必然在底下。然后就是不要图快。", height=30, color=(119, 110, 101)), (30, 375))
            screen.blit(write("4、当游戏进行不下去时,NewGame", height=30, color=(119, 110, 101)), (30, 405))
            screen.blit(write("键点击重新开始,祝你玩的愉快。", height=30, color=(119, 110, 101)), (30, 435))
            button_back = Button((left_of_screen + 140, 480), "button_back.jpg", 130, 50)
            screen.blit(write("2048", height=100, color=(119, 110, 101)),
                        (left_of_screen + 110, left_of_screen // 2))

def game_introduce():#游戏玩法介绍
    button_back = Button((left_of_screen + 140, 480), "button_back.jpg", 130, 50)
    screen.blit(background, (0, 0))
    while True:
        for event in pygame.event.get():
            if event.type == QUIT or (event.type == KEYUP and event.key == K_ESCAPE):
                pygame.quit()
                exit()
            elif event.type == pygame.MOUSEBUTTONDOWN:
                if button_back.isOver() == True:
                    return
            pygame.display.update()
            rect = pygame.draw.rect(screen, (251, 248, 241), (10, 10, 500, 580))
            screen.blit(write("游戏的规则很简单", height=30, color=(119, 110, 101)), (135, 165))
            screen.blit(write("需要控制所有方块", height=30, color=(119, 110, 101)), (135, 195))
            screen.blit(write("向同一个方向运动", height=30, color=(119, 110, 101)), (135, 225))
            screen.blit(write("两个相同数字方块", height=30, color=(119, 110, 101)), (135, 255))
            screen.blit(write("撞在一起之后会合", height=30, color=(119, 110, 101)), (135, 285))
            screen.blit(write("并成为他们的加和", height=30, color=(119, 110, 101)), (135, 315))
            screen.blit(write("之后会新产生一个", height=30, color=(119, 110, 101)), (135, 345))
            screen.blit(write("2或4当拼凑得到了", height=30, color=(119, 110, 101)), (135, 375))
            screen.blit(write("2048游戏就算胜利", height=30, color=(119, 110, 101)), (135, 405))
            button_back = Button((left_of_screen + 140, 480), "button_back.jpg", 130, 50)
            screen.blit(write("2048", height=100, color=(119, 110, 101)),
                        (left_of_screen + 110, left_of_screen // 2))


def game_view_page0():#游戏欢迎界面,这里实现了一个动画功能:两排大小颜色不同的“2048小游戏”绕屏幕中心进行旋转
    FPS = 5
    BLACK = (0, 0, 0)
    BROWN = (187, 173, 160)
    WHITE = (255, 255, 255)
    BGCOLOR = BROWN
    titleFont = pygame.font.Font(r'C:\\Windows\\Fonts\\simkai.ttf', 100)
    titleSurf1 = titleFont.render('2048小游戏', True, BLACK)
    titleSurf2 = titleFont.render('2048小游戏', True, WHITE)
    degrees1 = 0
    degrees2 = 0
    while True:
        for event in pygame.event.get():
            if event.type == QUIT:
                pygame.quit()
                exit()
            elif event.type == pygame.MOUSEBUTTONDOWN or event.type == KEYUP:
                return
        screen.fill(BGCOLOR)
        rotatedSurf1 = pygame.transform.rotate(titleSurf1, degrees1)
        rotatedRect1 = rotatedSurf1.get_rect()
        rotatedRect1.center = (screen_width / 2, screen_height / 2 - 50)
        screen.blit(rotatedSurf1, rotatedRect1)
        rotatedSurf2 = pygame.transform.rotate(titleSurf2, degrees2)
        rotatedRect2 = rotatedSurf2.get_rect()
        rotatedRect2.center = (screen_width / 2, screen_height / 2 - 50)
        screen.blit(rotatedSurf2, rotatedRect2)
        screen.blit(write("点击鼠标左键进入游戏", height=30, color=(255, 255, 255)),
                    (left_of_screen + 60, left_of_screen // 2 + 450))
        pygame.display.update()
        FPSCLOCK.tick(10)
        degrees1 += 3
        degrees2 += 5


def game_start_page():#游戏开始界面
    #加载背景图片
    screen.blit(background, (0, 0))
    #创建几个自定义的按钮
    button4 = Button((left_of_screen + 110, 150), b4, 200, 80)
    button5 = Button((left_of_screen + 110, 270), b5, 200, 80)
    button6 = Button((left_of_screen + 110, 390), b6, 200, 80)
    while True:
        for event in pygame.event.get():
            if event.type == QUIT or (event.type == KEYUP and event.key == K_ESCAPE):
                pygame.quit()
                exit()
            elif event.type == pygame.MOUSEBUTTONDOWN:
                if button4.isOver() == True:#如果按下的是button4,即开始游戏
                    return
                elif button5.isOver() == True:#如果按下的是button5,即游戏玩法介绍
                    game_introduce()
                    screen.blit(background, (0, 0))
                    button4 = Button((left_of_screen + 110, 150), b4, 200, 80)
                    button5 = Button((left_of_screen + 110, 270), b5, 200, 80)
                    button6 = Button((left_of_screen + 110, 390), b6, 200, 80)
                elif button6.isOver() == True:#如果按下的是button6,即游戏技巧介绍
                    game_skill()
                    screen.blit(background, (0, 0))
                    button4 = Button((left_of_screen + 110, 150), b4, 200, 80)
                    button5 = Button((left_of_screen + 110, 270), b5, 200, 80)
                    button6 = Button((left_of_screen + 110, 390), b6, 200, 80)
            screen.blit(write("2048", height=100, color=(119, 110, 101)),
                        (left_of_screen + 110, left_of_screen // 2))
            pygame.display.update()


def main():
    # play_music()注释掉了,播放音乐会导致游戏很卡
    global FPSCLOCK, score, high_score, tmpScore, board
    flag = False
    flag2 = False
    FPSCLOCK = pygame.time.Clock()
    game_view_page0()#游戏欢迎界面
    game_start_page()#游戏主菜单界面
    b = [[0, 0, 0, 0],#b是用来记录每次用户移动前一步的棋盘状态的,可以用于实现“回到上一步”功能
         [0, 0, 0, 0],
         [0, 0, 0, 0],
         [0, 0, 0, 0]]
    screen.blit(background, (0, 0))
    init_board()
    newboard = deepcopy(board)
    gameover = is_over()
    draw_box(1)
    button = Button((left_of_screen + 210, left_of_screen // 2 + 5), "button3.jpg", 100, 60)
    screen.blit(write("2048", height=60, color=(119, 110, 101)),
                (left_of_screen, left_of_screen // 2))
    high_score = load_data()

    while True:
        for event in pygame.event.get():
            if event.type == QUIT or (event.type == KEYUP and event.key == K_ESCAPE):#用户如果按了ESC,退出
                pygame.quit()
                exit()
            elif not gameover:#如果当前游戏还没有失败(棋盘上还有空格,即数字0)
                if win() == True:#如果当前赢了(拼出来了数字2048)
                    screen.blit(write("You win!", height=40, color=(119, 110, 101)),#屏幕上打印“You win!”
                                (left_of_screen + 160, screen_height // 2 - 30))
                elif event.type == KEYUP and event.key == K_UP:#用户按了 up 键
                    tmpScore = score
                    flag = False
                    up()
                elif event.type == KEYUP and event.key == K_DOWN:#用户按了 down 键
                    tmpScore = score
                    flag = False
                    down()
                elif event.type == KEYUP and event.key == K_LEFT:#用户按了 left 键
                    tmpScore = score
                    flag = False
                    left()
                elif event.type == KEYUP and event.key == K_RIGHT:#用户按了 right 键
                    tmpScore = score
                    flag = False
                    right()
                elif event.type == pygame.MOUSEBUTTONDOWN:#用户点击了鼠标,也就是用户按下了重新开始的按钮
                    button.render()#重新开始一局游戏
                    flag = False#初始化各个数值
                    flag2 = True
                elif event.type == KEYUP and event.key == K_SPACE:#用户按了 space 打算回到上一步
                    if flag == False:
                        board = deepcopy(b)
                        score = tmpScore
                        flag = True
                if newboard != board:
                    b = deepcopy(newboard)
                    if flag == False and flag2 == False:
                        set_random_number()
                    flag2 = False
                    newboard = deepcopy(board)
                    draw_box(1)
                gameover = is_over()
            else:#否则判定用户本局游戏失败
                screen.blit(write("Game over!", height=40, color=(119, 110, 101)),#打印失败信息
                            (left_of_screen + 140, screen_height // 2 - 40))
                if score > high_score:#如果用户的分数比本机最高得分高
                    screen.blit(write("New record!", height=40, color=(119, 110, 101)),#提示用户刷新了记录
                                (left_of_screen + 140, screen_height // 2 + 10))
                    high_score = score
                    with open(high_score_name, "w") as f:
                        f.write(str(high_score))#用新的得分覆盖原有的最高得分
                if event.type == pygame.MOUSEBUTTONDOWN:#用户点击了鼠标,也就是用户按下了重新开始的按钮
                    gameover = False
                    score = 0
                    tmpScore = 0#初始化各个数值
                    button.render()#重新开始一局游戏
                    flag2 = True

        pygame.display.update()
        rect1 = pygame.draw.rect(screen, (187, 173, 160),
                                 (left_of_screen + 120, left_of_screen // 2 + 5, 80, 60))
        rect2 = pygame.draw.rect(screen, (187, 173, 160),
                                 (left_of_screen + 320, left_of_screen // 2 + 5, 105, 60))
        screen.blit(write("score:", height=28, color=(255, 255, 255)),
                    (left_of_screen + 125, left_of_screen // 2 + 5))
        screen.blit(write("best:", height=30, color=(255, 255, 255)),
                    (left_of_screen + 340, left_of_screen // 2 + 5))
        text1 = write(str(score), height=30, color=(255, 255, 255))
        text2 = write(str(high_score), height=30, color=(255, 255, 255))
        text_rect = text1.get_rect()
        text_rect2 = text2.get_rect()
        text_rect.center = (left_of_screen + 160, left_of_screen // 2 + 50)
        text_rect2.center = (left_of_screen + 370, left_of_screen // 2 + 50)
        screen.blit(text1, text_rect)
        screen.blit(text2, text_rect2)


if __name__ == "__main__":
    main()

直接复制源代码是不可以运行的,缺少了图片素材等本地文件。我把这些东西都放在我的GitHub上,需要的同学可去下载。

Pygame-2048

记得顺便给个star~OvO

另外小小博主还有一篇C语言制作的推箱子,感兴趣的同学可以去看看。学完C语言能干啥?先来做个推箱子吧~(有图片呦)

That's all, thanks for watching~

以上是关于使用Pygame制作2048小游戏的主要内容,如果未能解决你的问题,请参考以下文章

2048 游戏 - AI 的平均得分不能超过 256

Pygame实战:升级后的2048小游戏—解锁新花样!根本停不下来!附源码

pygame应用---射击外星人游戏

Pygame小游戏练习五

使用pygame制作贪吃蛇小游戏

python Python 3端口和PEP8兼容版本的David Sousa的2048游戏,用python 3运行安装最新版本的pygame:https:// bitb