面向对象pygame2048小游戏+源码

1.2048介绍

2048是一款数字拼图游戏,游戏的目标是通过在方格中滑动相同数字的方块,使它们合并成更大的数字方块,最终达到2048这个数字。每次滑动都会导致所有的方块朝滑动的方向移动,没有空间移动或合并时游戏结束。这款游戏简单而富有挑战性,需要智力和策略来达到更高的分数。

游戏规则:

1. 在4乘4的方格上,每移动一步会随机在空位出现2或4;

2. 相同的数字碰撞可以合成两倍的数字;

3. 游戏的最终目的是合成2048这个数字。

话不多说直接上源码。(注意同级文件夹需要自己添加图片和字体然后才可以运行)

2.python源码

import sys

import pygame

import random

colors = {
    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, 97),
    512: (237, 200, 80),
    1024: (237, 197, 63),
    2048: (237, 194, 46),
}


class Util:
    """
    工具类
    """

    @staticmethod
    # 检测鼠标点击与精灵的碰撞,碰撞返回真,反之返回假
    def click_check(sprite):
        # 获得鼠标点击左键按下事件
        if pygame.mouse.get_pressed()[0]:
            # 判断精灵是否和鼠标左键碰撞
            if sprite.rect.collidepoint(pygame.mouse.get_pos()):
                return True
        return False


class BaseSprite(pygame.sprite.Sprite):
    """
    精灵父类
    """

    def __init__(self, name):
        """
        初始化精灵
        """
        super().__init__()
        self.image = pygame.image.load(name)
        self.rect = self.image.get_rect()


class NumSprite(pygame.sprite.Sprite):
    """
    数字精灵
    """

    def __init__(self, center):
        super().__init__()
        # 字体
        self.font = pygame.font.Font("font/simkai.ttf", 64)
        # 在字体随机显示2或4
        self.font_num = self.font.render(f"{random.choice([2, 4])}", True, (255, 255, 255))
        # surface类型获得一个矩形面
        self.image = pygame.Surface((80, 80))
        # 填充颜色
        self.image.fill((205, 193, 180))
        # 在矩形上绘制字体
        self.image.blit(self.font_num, (22, 10))
        # 获得矩形坐标
        self.rect = self.image.get_rect()
        self.rect.center = center


class NumManage:
    """
    数字管理类
    """

    def __init__(self, gm):
        self.gm = gm
        # 定义数字组
        self.num_group = pygame.sprite.Group()
        # 开始状态为空
        self.state = None
        # 字体
        self.font = pygame.font.SysFont(None, 40)

    # 绘制方块
    def draw_tile(self, x, y, value):
        color = colors.get(value, (255, 255, 255))
        coordinate_x = x + 15
        coordinate_y = y + 140
        pygame.draw.rect(self.gm.screen, color, (coordinate_x, coordinate_y, 80, 80))
        if value:
            text_surface = self.font.render(str(value), True, (0, 0, 0))
            text_rect = text_surface.get_rect(center=(coordinate_x + 80 / 2, coordinate_y + 80 / 2))
            self.gm.screen.blit(text_surface, text_rect)

    # 绘制游戏界面
    def draw_board(self, board):
        for y in range(len(board)):
            for x in range(len(board[0])):
                self.draw_tile(x * (80 + 10), y * (80 + 10), board[y][x])

    # 在空白位置生成一个新方块
    def spawn_tile(self, board):
        empty_tiles = []
        for y in range(len(board)):
            for x in range(len(board[0])):
                if board[y][x] == 0:
                    empty_tiles.append((y, x))
        if empty_tiles:
            y, x = random.choice(empty_tiles)
            board[y][x] = random.choice([2, 4])

    # 合并相同数字的方块
    def merge_tiles(self, board, direction):
        if direction == 'up':
            for x in range(len(board[0])):
                for y in range(len(board) - 1):
                    if board[y][x] == board[y + 1][x]:
                        board[y][x] *= 2
                        board[y + 1][x] = 0

        elif direction == 'down':
            for x in range(len(board[0])):
                for y in range(len(board) - 1, 0, -1):
                    if board[y][x] == board[y - 1][x]:
                        board[y][x] *= 2
                        board[y - 1][x] = 0

        elif direction == 'left':
            for y in range(len(board)):
                for x in range(len(board[0]) - 1):
                    if board[y][x] == board[y][x + 1]:
                        board[y][x] *= 2
                        board[y][x + 1] = 0

        elif direction == 'right':
            for y in range(len(board)):
                for x in range(len(board[0]) - 1, 0, -1):
                    if board[y][x] == board[y][x - 1]:
                        board[y][x] *= 2
                        board[y][x - 1] = 0

    # 移动方块
    def move_tiles(self, board, direction):
        if direction == 'down':
            for x in range(len(board[0])):
                for y in range(len(board) - 1, 0, -1):
                    if board[y][x] == 0:
                        for k in range(y - 1, -1, -1):
                            if board[k][x] != 0:
                                board[y][x] = board[k][x]
                                board[k][x] = 0
                                break



        elif direction == 'up':
            for x in range(len(board[0])):
                for y in range(len(board) - 1):
                    if board[y][x] == 0:
                        for k in range(y + 1, len(board)):
                            if board[k][x] != 0:
                                board[y][x] = board[k][x]
                                board[k][x] = 0
                                break

        elif direction == 'right':
            for y in range(len(board)):
                for x in range(len(board[0]) - 1, 0, -1):
                    if board[y][x] == 0:
                        for k in range(x - 1, -1, -1):
                            if board[y][k] != 0:
                                board[y][x] = board[y][k]
                                board[y][k] = 0
                                break

        elif direction == 'left':
            for y in range(len(board)):
                for x in range(len(board[0]) - 1):
                    if board[y][x] == 0:
                        for k in range(x + 1, len(board[0])):
                            if board[y][k] != 0:
                                board[y][x] = board[y][k]
                                board[y][k] = 0
                                break

    # 判断游戏是否结束
    def game_over(self, board):
        for y in range(len(board)):
            for x in range(len(board[0])):
                if board[y][x] == 0:
                    return False
                if x < len(board[0]) - 1 and board[y][x] == board[y][x + 1]:
                    return False
                if y < len(board) - 1 and board[y][x] == board[y + 1][x]:
                    return False
        return True


class UISprite(BaseSprite):
    """
    界面精灵类
    """

    def __init__(self, name, center):
        super().__init__(name)
        self.rect.center = center


class UIManage:
    """
    界面管理类
    """

    def __init__(self, gm):
        self.gm = gm
        # UI字体
        self.font1 = pygame.font.Font("font/font.ttf", 25)
        self.font2 = pygame.font.Font("font/simkai.ttf", 70)
        self.font3 = pygame.font.Font("font/simkai.ttf", 14)
        self.font4 = pygame.font.Font("font/font.ttf", 20)
        self.font5 = pygame.font.Font("font/simkai.ttf", 70)

        # 开始前UI元素,一个ready_group精灵组
        self.ready_group = pygame.sprite.Group()
        # 开始按钮
        self.begin_btn = UISprite("start.jpg", (190, 250))
        self.begin_btn.add(self.ready_group)

        # 游戏结束UI元素
        self.end_group = pygame.sprite.Group()
        # 重新开始按钮
        self.replay_btn = UISprite("button3.jpg", (190, 250))
        self.replay_btn.add(self.end_group)

        # new_game按钮
        self.new_game_group = pygame.sprite.Group()
        self.new_game_btn = UISprite("button31.jpg", (315, 100))
        self.new_game_btn.add(self.new_game_group)

        # 分数
        self.score_surface1 = self.font4.render(f"Score:{0}", True, (0, 0, 0))
        self.score_surface2 = self.font1.render(f"Score:{0}", True, (0, 0, 0))
        # 2048文字
        self.num_surface = self.font2.render("2048", True, (0, 0, 0))
        self.num_surface1 = self.font3.render("合并数字到达2048!", True, (0, 0, 0))
        # 结束显示文字
        self.over_surface = self.font5.render("GAME OVER!", True, (255, 255, 255))

    # 游戏状态gaming视图
    def gaming_view(self):
        self.gm.num_manage.draw_board(self.gm.board)
        # 绘制分数
        self.score_surface1 = self.font4.render(f"Score:{self.gm.score}", True, (0, 0, 0))
        self.gm.screen.blit(self.score_surface1, (150, 85))
        # 绘制最大分数
        self.score_surface2 = self.font1.render(f"MaxScore:{self.gm.high_score}", True, (0, 0, 0))
        self.gm.screen.blit(self.score_surface2, (200, 30))
        # 绘制2048
        self.gm.screen.blit(self.num_surface, (10, 0))
        self.gm.screen.blit(self.num_surface1, (5, 80))

        # new_game按钮绘制
        self.new_game_group.draw(self.gm.screen)
        if Util.click_check(self.new_game_btn):
            self.gm.count_score()
            self.check_score()
            self.gm.board = [[0] * 4 for _ in range(4)]
            self.gm.state = "gaming"

    # 游戏状态的判定
    def update(self):
        if self.gm.state == "ready":
            self.gm.board = [[0] * 4 for _ in range(4)]
            self.ready_group.draw(self.gm.screen)
            if Util.click_check(self.begin_btn):
                self.gm.state = "gaming"

        elif self.gm.state == "gaming":
            self.gaming_view()

        elif self.gm.state == "end":
            self.check_score()
            self.end_group.draw(self.gm.screen)

            self.gm.screen.blit(self.over_surface, (20, 100))

            self.gm.board = [[0] * 4 for _ in range(4)]
            self.gm.score = 0
            if Util.click_check(self.replay_btn):
                self.gm.state = "gaming"

    # 检查分数,最大值返回给high_score
    def check_score(self):
        temp_score = self.gm.score
        if temp_score > self.gm.high_score:
            self.gm.high_score = temp_score


class GameManage:
    """
    游戏管理类
    """

    def __init__(self, name):
        pygame.init()
        img_load = pygame.image.load("head.jpg")
        pygame.display.set_icon(img_load)
        # 初始化游戏状态
        self.state = "ready"
        # 初始化帧率
        self.clock = pygame.time.Clock()
        # 初始化屏幕
        self.screen = pygame.display.set_mode((380, 500))
        pygame.display.set_caption(name)
        # 实例调用类UIManage传入gm
        self.ui_manage = UIManage(self)
        # 实例调用类NumManage传入gm
        self.num_manage = NumManage(self)
        # 4*4都为零的列表
        self.board = [[0] * 4 for _ in range(4)]
        self.score = 0
        self.high_score = 0

    # 统计显示所有数字的和作为分数
    def count_score(self):
        score = 0
        for i in self.board:
            for j in i:
                score += j
        self.score = score

    # 读取文件获得最大值
    def read_data(self):
        with open("high_score.txt", "r") as f:
            high = int(f.read())
            return high

    # 写入文件,写入最大值
    def write_data(self):
        with open("high_score.txt", "w") as f:
            f.write(str(self.high_score))

    # 事件检测
    def check_event(self):
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()
            # 空格一键结束
            if event.type == pygame.KEYUP:
                # 一键结束游戏
                if event.key == pygame.K_SPACE:
                    self.state = "end"
                self.count_score()

            if event.type == pygame.KEYUP:
                # 捕捉左建事件
                if event.key == pygame.K_LEFT:
                    self.num_manage.move_tiles(self.board, "left")
                    self.num_manage.merge_tiles(self.board, "left")
                    self.num_manage.move_tiles(self.board, "left")
                    self.num_manage.spawn_tile(self.board)

                # 捕捉上建事件
                elif event.key == pygame.K_UP:
                    self.num_manage.move_tiles(self.board, "up")
                    self.num_manage.merge_tiles(self.board, "up")
                    self.num_manage.move_tiles(self.board, "up")
                    self.num_manage.spawn_tile(self.board)

                # 捕捉右建事件
                elif event.key == pygame.K_RIGHT:
                    self.num_manage.move_tiles(self.board, "right")
                    self.num_manage.merge_tiles(self.board, "right")
                    self.num_manage.move_tiles(self.board, "right")
                    self.num_manage.spawn_tile(self.board)

                # # 捕捉下建事件
                elif event.key == pygame.K_DOWN:
                    self.num_manage.move_tiles(self.board, "down")
                    self.num_manage.merge_tiles(self.board, "down")
                    self.num_manage.move_tiles(self.board, "down")
                    self.num_manage.spawn_tile(self.board)
                # 判断游戏是否结束
                if self.num_manage.game_over(self.board):
                    self.state = "end"

    def run(self):
        while True:
            # 修改帧率
            self.clock.tick(24)
            self.check_event()
            # 屏幕填充颜色
            self.screen.fill((127, 127, 127))
            self.ui_manage.update()
            # 判断游戏状态
            if self.state == "gaming":
                self.num_manage.num_group.draw(self.screen)
                self.num_manage.num_group.update()
            # 一直刷新屏幕
            pygame.display.flip()


gm = GameManage("2048")
gm.run()

3.编码思路

1、先来个游戏管理类GameManage用来管理其他类,先创建一个举行窗口。

2、精灵父类,创建ui精灵类继承父类和ui管理类,设置游戏的三种状态,replay,gaming,end。根据游戏的不同状态在屏幕上显示不同的界面

3、一个工具静态类,用来检测鼠标点击事件。

4、数字类,需要在屏幕上绘制方格,在每个格子上绘制数字。4乘4的列表中默认都是零,在屏幕上不显示,当获得键盘事事件(上下左右),在新建临时列表追加原来表中的零,再重临时列表中随机一个零进行2或4的显示,并绘制到屏幕上。每次获得键盘事件都对原有的表格进行遍历,位置移动,相同数字碰撞叠加。

效果图:

感谢观看点个赞呗!!!!

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值