面向对象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
    评论
以下是一个简单的 Pygame 小游戏的源代码。这个游戏是一个简单的打飞机游戏,玩家控制一个小飞机,躲避敌机的攻击并射击它们。你可以用这个源代码作为学习 Pygame 编程的参考。 ```python import pygame import random # 初始化 Pygame pygame.init() # 定义一些常量 SCREEN_WIDTH = 480 SCREEN_HEIGHT = 800 ENEMY_COUNT = 5 FPS = 60 # 创建窗口 screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT)) pygame.display.set_caption('打飞机') # 加载图片 background_image = pygame.image.load('background.png').convert() player_image = pygame.image.load('player.png').convert_alpha() enemy_image = pygame.image.load('enemy.png').convert_alpha() bullet_image = pygame.image.load('bullet.png').convert_alpha() # 定义游戏对象 class GameObject: def __init__(self, x, y, image): self.x = x self.y = y self.image = image self.rect = self.image.get_rect() self.rect.x = self.x self.rect.y = self.y def draw(self, surface): surface.blit(self.image, (self.x, self.y)) # 定义玩家类 class Player(GameObject): def __init__(self, x, y, image): super().__init__(x, y, image) self.speed = 5 self.bullets = [] def update(self): keys = pygame.key.get_pressed() if keys[pygame.K_LEFT]: self.x -= self.speed if keys[pygame.K_RIGHT]: self.x += self.speed if keys[pygame.K_UP]: self.y -= self.speed if keys[pygame.K_DOWN]: self.y += self.speed if keys[pygame.K_SPACE]: self.fire() # 更新子弹 for bullet in self.bullets: bullet.update() def fire(self): bullet = Bullet(self.x + self.rect.width / 2, self.y) self.bullets.append(bullet) # 定义敌机类 class Enemy(GameObject): def __init__(self, x, y, image): super().__init__(x, y, image) self.speed = 3 def update(self): self.y += self.speed # 定义子弹类 class Bullet(GameObject): def __init__(self, x, y): super().__init__(x, y, bullet_image) self.speed = 10 def update(self): self.y -= self.speed # 创建游戏对象 player = Player(SCREEN_WIDTH / 2 - player_image.get_rect().width / 2, SCREEN_HEIGHT - player_image.get_rect().height, player_image) enemies = [Enemy(random.randint(0, SCREEN_WIDTH - enemy_image.get_rect().width), -enemy_image.get_rect().height, enemy_image) for i in range(ENEMY_COUNT)] # 游戏主循环 clock = pygame.time.Clock() while True: # 处理事件 for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() exit() # 更新游戏对象 player.update() for enemy in enemies: enemy.update() # 绘制游戏对象 screen.blit(background_image, (0, 0)) player.draw(screen) for enemy in enemies: enemy.draw(screen) for bullet in player.bullets: bullet.draw(screen) # 检测碰撞 for enemy in enemies: if player.rect.colliderect(enemy.rect): pygame.quit() exit() for bullet in player.bullets: if bullet.rect.colliderect(enemy.rect): enemies.remove(enemy) player.bullets.remove(bullet) # 更新屏幕 pygame.display.update() # 控制帧率 clock.tick(FPS) ``` 注意,这个游戏还有一些不完美的地方,比如没有限制玩家的移动范围,敌机的速度和生成位置都是固定的,没有动态变化等。你可以在这个基础上进行改进和扩展。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值