python小游戏,pygame小游戏,华容道(数字版)

华容道--python游戏

游戏截图

在这里插入图片描述

游戏源码

写的一个小游戏,欢迎大家指正

import pygame
import sys
import random
import time
from pygame.locals import *

class SlidePuzzle:
    # 主窗口的尺寸
    WINDOW_WIDTH = 1024
    WINDOW_HEIGHT = 768


    # 滑块的数量及大小
    TILE_WIDTH = 4
    TILE_HEIGHT = 4
    TILE_SIZE = 150


    # 设置颜色常量      R    G    B
    WHITE         = (245, 245, 245)
    # GREEN         = (  0, 204,   0)
    GREEN         = (32,178,170)
    BLACK         = (  0,   0,   0)
    BRIGHT_BLUE    = (  0,  50, 255)
    DARKTURQUOISE = (  3,  54,  73)


    # 设置不同场景的颜色
    BG_COLOR = DARKTURQUOISE  # 整体背景颜色
    TILE_COLOR = GREEN  # 滑块的颜色
    BORDER_COLOR = BRIGHT_BLUE  # 边框的颜色
    TEXT_COLOR = WHITE  # 滑块上的字的颜色
    BUTTON_COLOR = WHITE  # 按钮的颜色
    BUTTON_TEXT_COLOR = BLACK  # 按钮文字的颜色
    MESSAGE_COLOR = WHITE  # 消息的颜色


    # X Y轴的间距
    MARGIN_X = int((WINDOW_WIDTH - (TILE_SIZE * TILE_WIDTH + (TILE_WIDTH - 1))) / 2)
    MARGIN_Y = int((WINDOW_HEIGHT - (TILE_SIZE * TILE_HEIGHT - (TILE_HEIGHT - 1))) / 2)

    # 设置
    FPS = 20
    BLANK = None
    BASIC_FONT_SIZE = 20  # 基础字体大小
    FINISH_FONT_SIZE = 30  # 游戏结束画面字体大小
    SHUFFLE_NUM = 80  # 打乱面板的次数
    ANIMATION_SPEED = 13  # 动画播放速度

    # 方向的常量
    UP = "up"
    DOWN = 'down'
    LEFT = "left"
    RIGHT = "right"

    def __init__(self):
        self.DISPLAY_SURFACE = pygame.display.set_mode((self.WINDOW_WIDTH, self.WINDOW_HEIGHT))
        self.DISPLAY_CLOCK = pygame.time.Clock()

    def check_for_quit(self):
        """
        检查用户是否退出
        :return:
        """
        for event in pygame.event.get(QUIT):
            self.terminate()
        for event in pygame.event.get(KEYUP):
            if event.key == K_ESCAPE:
                self.terminate()
            pygame.event.post(event)

    @staticmethod
    def terminate():
        """
        关闭pygame并退出程序
        :return:
        """
        pygame.quit()
        sys.exit()

    def draw_button(self):
        """
        画出 三个按钮 按钮的位置固定不变
        :return:
        """
        new_game_x = int(self.WINDOW_WIDTH - 150)
        new_game_y = int(self.WINDOW_HEIGHT - 200)
        reset_game_x = int(new_game_x - 10)
        reset_game_y = int(new_game_y + 50)
        solved_game_x = int(reset_game_x)
        solved_game_y = int(reset_game_y + 50)

        new_game_surface, self.new_game_rect = self.make_text("开始新游戏", self.BASIC_FONT_SIZE, self.BUTTON_TEXT_COLOR, self.BUTTON_COLOR,
                                                         new_game_x,new_game_y)
        reset_game_surface, self.reset_game_rect = self.make_text("重新开始本局", self.BASIC_FONT_SIZE, self.BUTTON_TEXT_COLOR, self.BUTTON_COLOR,
                                                             reset_game_x, reset_game_y)
        solved_game_surface, self.solved_game_rect = self.make_text("展示正确步骤", self.BASIC_FONT_SIZE, self.BUTTON_TEXT_COLOR, self.BUTTON_COLOR,
                                                               solved_game_x, solved_game_y)

        self.DISPLAY_SURFACE.blit(new_game_surface, self.new_game_rect)
        self.DISPLAY_SURFACE.blit(reset_game_surface, self.reset_game_rect)
        self.DISPLAY_SURFACE.blit(solved_game_surface, self.solved_game_rect)

    def make_text(self, text: str, size: int, color: tuple, bg_color: tuple, top: int, left: int) -> tuple:
        """
        创建文本的 surface对象 及文本的 rect 对象
        :param text: 文字内容
        :param size: 文字大小
        :param color: 文字颜色
        :param bg_color: 文字背景颜色
        :param top: 文字 rect 的左上角的 x 坐标
        :param left: 文字 rect 的左上角的 y 坐标
        :return:(text_surface, text_rect)
        """
        font = pygame.font.SysFont(['华文楷体',"simhei"], size)
        text_surface = font.render(text, True, color, bg_color)
        text_rect = text_surface.get_rect()
        text_rect.topleft = (top, left)

        return text_surface, text_rect

    def generate_board(self) -> list:
        """
        根据滑块的数量,创建一个数据面板
        1  2  3
        4  5  6
        7  8  None
        :return: list数据面板
        """
        boards = []
        counters = 1
        for x in range(self.TILE_WIDTH):
            current_column = []
            for y in range(self.TILE_HEIGHT):
                current_column.append(counters)
                counters += self.TILE_WIDTH
            boards.append(current_column)
            counters -= self.TILE_WIDTH * (self.TILE_HEIGHT - 1) + self.TILE_WIDTH - 1
        boards[self.TILE_WIDTH - 1][self.TILE_HEIGHT - 1] = None
        return boards

    def make_main_board(self):
        """
        创建一个打乱的面板,并返回该面板,以及每次移动的记录列表
        :return: 打乱的面板 main_board   记录每次移动方向的列表 moves_list -> []
        """
        moves_list = []
        current_board = self.generate_board()
        self.draw_board(current_board, "正在新建游戏")
        pygame.display.update()
        slide_to = None
        for i in range(self.SHUFFLE_NUM):
            move = self.direction_random(current_board, slide_to)
            self.move_animation(current_board, move, self.TILE_SIZE / 2)
            self.make_move(current_board, move)
            moves_list.append(move)
            slide_to = move

        return current_board, moves_list

    def make_move(self, board, slide_to):
        """
        按照移动方向,更改游戏面板数据
        :param board: 面板
        :param slide_to: 移动方向
        :return:
        """
        blank_x, blank_y = self.get_blank_position(board)
        if slide_to == self.UP and self.valid_move(board, self.UP):
            board[blank_x][blank_y], board[blank_x][blank_y + 1] = board[blank_x][blank_y + 1], board[blank_x][blank_y]
        elif slide_to == self.DOWN and self.valid_move(board, self.DOWN):
            board[blank_x][blank_y], board[blank_x][blank_y - 1] = board[blank_x][blank_y - 1], board[blank_x][blank_y]
        elif slide_to == self.LEFT and self.valid_move(board, self.LEFT):
            board[blank_x][blank_y], board[blank_x + 1][blank_y] = board[blank_x + 1][blank_y], board[blank_x][blank_y]
        elif slide_to == self.RIGHT and self.valid_move(board, self.RIGHT):
            board[blank_x][blank_y], board[blank_x - 1][blank_y] = board[blank_x - 1][blank_y], board[blank_x][blank_y]

    def move_animation(self, board, slide_to, animation_speed):
        """
        滑块移动的动画
        :param board:面板
        :param slide_to:移动方向
        :param animation_speed: 动画的播放速度
        :return:
        """
        blank_x, blank_y = self.get_blank_position(board)

        # 需要移动的滑块的坐标:
        move_x, move_y = None, None

        if slide_to == self.UP:
            move_x, move_y = blank_x, blank_y + 1
        elif slide_to == self.DOWN:
            move_x, move_y = blank_x, blank_y - 1
        elif slide_to == self.LEFT:
            move_x, move_y = blank_x + 1, blank_y
        elif slide_to == self.RIGHT:
            move_x, move_y = blank_x - 1, blank_y

        self.draw_board(board, "移动中")
        basic_surf = self.DISPLAY_SURFACE.copy()

        move_pixel_x, move_pixel_y = self.get_top_left_coordinate(move_x, move_y)
        pygame.draw.rect(basic_surf, self.BG_COLOR, (move_pixel_x, move_pixel_y, self.TILE_SIZE, self.TILE_SIZE))


        for i in range(0, self.TILE_SIZE, int(animation_speed)):
            self.check_for_quit()
            self.DISPLAY_SURFACE.blit(basic_surf, (0, 0))
            if slide_to == self.UP:
                self.draw_tile(move_x, move_y, board[move_x][move_y], 0, -i)
            elif slide_to == self.DOWN:
                self.draw_tile(move_x, move_y, board[move_x][move_y], 0, i)
            elif slide_to == self.LEFT:
                self.draw_tile(move_x, move_y, board[move_x][move_y], -i, 0)
            elif slide_to == self.RIGHT:
                self.draw_tile(move_x, move_y, board[move_x][move_y], i, 0)

            pygame.display.update()
            self.DISPLAY_CLOCK.tick(self.FPS)

    def draw_board(self, board, msg):
        """
        画出游戏面板
        :param board:面板
        :param msg: 展示的信息
        :return:
        """
        self.DISPLAY_SURFACE.fill(self.BG_COLOR)
        for x in range(len(board)):
            for y in range(len(board[0])):
                if board[x][y]:
                    self.draw_tile(x, y, board[x][y])
        msg_surf, msg_rect = self.make_text(msg, self.BASIC_FONT_SIZE, self.TEXT_COLOR, self.BG_COLOR, 10, 30)
        self.DISPLAY_SURFACE.blit(msg_surf, msg_rect)
        self.draw_button()

    def draw_tile(self, tile_x, tile_y, number, offset_x=0, offset_y=0):
        """
        画 滑块
        :param tile_x: 滑块的 X 值
        :param tile_y: 滑块的 Y 值
        :param number: 滑块上的数字
        :param offset_x: 滑块 x 轴上滑动速度
        :param offset_y: 滑块 y 轴上滑动速度
        :return:
        """
        pixel_x, pixel_y = self.get_top_left_coordinate(tile_x, tile_y)

        pygame.draw.rect(self.DISPLAY_SURFACE, self.TILE_COLOR,
                         (pixel_x + offset_x, pixel_y + offset_y, self.TILE_SIZE, self.TILE_SIZE))

        text_surf, text_rect = self.make_text(str(number), self.BASIC_FONT_SIZE, self.TEXT_COLOR, self.TILE_COLOR,
                                              int(pixel_x + offset_x + self.TILE_SIZE * 4 / 9),
                                              int(pixel_y + offset_y + self.TILE_SIZE * 4 / 9))
        self.DISPLAY_SURFACE.blit(text_surf, text_rect)

    def get_top_left_coordinate(self, tile_x, tile_y):
        """
        获得滑块的 左上角的像素坐标
        :param tile_x: 滑块 X 坐标
        :param tile_y: 滑块 Y 坐标
        :return: pixel_x,  pixel_y
        """
        pixel_x = self.MARGIN_X + (tile_x * self.TILE_SIZE) + (tile_x - 1)
        pixel_y = self.MARGIN_Y + (tile_y * self.TILE_SIZE) + (tile_y - 1)
        return pixel_x, pixel_y

    def direction_random(self, board, slide_to):
        """
        产生一个随机的方向
        :param board: 面板
        :param slide_to: 移动方向
        :return: 移动的方向 UP  DOWN  LEFT  RIGHT
        """
        all_direction = [self.UP, self.DOWN, self.LEFT, self.RIGHT]

        if slide_to == self.UP or not self.valid_move(board, self.DOWN):
            all_direction.remove(self.DOWN)
        if slide_to == self.DOWN or not self.valid_move(board, self.UP):
            all_direction.remove(self.UP)
        if slide_to == self.LEFT or not self.valid_move(board, self.RIGHT):
            all_direction.remove(self.RIGHT)
        if slide_to == self.RIGHT or not self.valid_move(board, self.LEFT):
            all_direction.remove(self.LEFT)
        return random.choice(all_direction)

    def valid_move(self, board, slide_to):
        """
        判断此次移动是否有效
        :param board: 面板
        :param slide_to: 移动方向
        :return: Boolean_value
        """
        blank_x, blank_y = self.get_blank_position(board)
        if slide_to == self.UP and blank_y != self.TILE_HEIGHT - 1:
            return True
        elif slide_to == self.DOWN and blank_y != 0:
            return True
        elif slide_to == self.LEFT and blank_x != self.TILE_WIDTH - 1:
            return True
        elif slide_to == self.RIGHT and blank_x != 0:
            return True
        return False

    def get_blank_position(self, board):
        """
        获取当前面板中 空白 面板所在的位置
        :param board: 面板
        :return: (tile_x, tile_y)
        """
        for x in range(len(board)):
            for y in range(len(board[0])):
                if board[x][y] == self.BLANK:
                    return x, y

    def opposite_direction(self, direction):
        """
        翻转方向
        :param direction: 输入的方向
        :return: 输出的方向
        """
        if direction == self.UP:
            return self.DOWN
        elif direction == self.DOWN:
            return self.UP
        elif direction == self.LEFT:
            return self.RIGHT
        elif direction == self.RIGHT:
            return self.LEFT

    def finished_game(self, message, move_direction_list, star_time, end_time):
        """
        游戏结束后的画面
        :param message:游戏结束后的话语
        :param move_direction_list: 用户的移动列表
        :param star_time: 游戏开始时间
        :param end_time: 游戏结束时间
        :return:
        """
        self.DISPLAY_SURFACE.fill(self.BG_COLOR)
        all_time = int((end_time - star_time))
        move_num = len(move_direction_list)
        if move_num:
            text = "{},您共计移动{}步,总用时{}秒!AI完成游戏需要{}步。".format(message, move_num,
                                                               all_time, self.SHUFFLE_NUM)
        else:
            text = "解决方案已经展示完毕!!"
        end_surf, end_rect = self.make_text(text, self.FINISH_FONT_SIZE, self.TEXT_COLOR,
                                            self.BG_COLOR, 10, int(self.WINDOW_HEIGHT / 3))
        end_rect.center = (self.WINDOW_WIDTH/2, self.WINDOW_HEIGHT/2)
        self.DISPLAY_SURFACE.blit(end_surf, end_rect)
        self.draw_clue_msg()
        running = True
        while running:
            self.check_for_quit()
            for event in pygame.event.get():
                if event.type == KEYUP:
                    running = False
            pygame.display.update()
            self.DISPLAY_CLOCK.tick(self.FPS)

    def draw_clue_msg(self):
        """
        绘画提示信息
        :return:
        """
        clue_surf, clue_rect = self.make_text("按任意键开始游戏", self.BASIC_FONT_SIZE, self.TEXT_COLOR,
                                              self.BG_COLOR, int(self.WINDOW_WIDTH - 200), int(self.WINDOW_HEIGHT - 50))
        self.DISPLAY_SURFACE.blit(clue_surf, clue_rect)

    def reset_game(self, board, move_direction):
        """
        重置本局游戏
        :return:
        """
        solved_direction = move_direction[:]
        solved_direction.reverse()
        for dir in solved_direction:
            current_direction = self.opposite_direction(dir)
            self.move_animation(board, current_direction, int(self.TILE_SIZE / 2))
            self.make_move(board, current_direction)
        move_direction.clear()

    def main(self):
        """
        游戏运行的主程序
        :return:
        """
        pygame.init()
        pygame.display.set_caption("华容道")
        star_time = time.time()
        # self.DISPLAY_SURFACE.fill(self.BG_COLOR)

        # 创建正确的数据面板
        VALID_BOARD = self.generate_board()
        main_board, SHUFFLE_LIST = self.make_main_board()

        move_direction = []

        while True:
            self.check_for_quit()
            self.draw_board(main_board, "游戏开始!")

            if main_board == VALID_BOARD:
                end_time = time.time()
                self.finished_game("恭喜您顺利通关", move_direction, star_time, end_time)
                main_board, SHUFFLE_LIST = self.make_main_board()
                move_direction.clear()
                star_time = time.time()


            for event in pygame.event.get():
                # 判断鼠标点击事件
                if event.type == MOUSEBUTTONUP:
                    pos_x, pos_y = pygame.mouse.get_pos()
                    # 显示正确的游戏结果
                    if self.solved_game_rect.collidepoint(pos_x, pos_y):
                        solved_direction = SHUFFLE_LIST[:] + move_direction[:]
                        solved_direction.reverse()
                        for dir in solved_direction:
                            current_direction = self.opposite_direction(dir)
                            self.move_animation(main_board, current_direction, int(self.TILE_SIZE / 4))
                            self.make_move(main_board, current_direction)
                        move_direction.clear()
                        end_time = time.time()
                        self.finished_game("", move_direction, star_time, end_time)
                        star_time = time.time()

                    # 开始一局新游戏
                    elif self.new_game_rect.collidepoint(pos_x, pos_y):
                        main_board, SHUFFLE_LIST = self.make_main_board()
                        star_time = time.time()
                        move_direction.clear()

                    # 重新开始本局游戏
                    elif self.reset_game_rect.collidepoint(pos_x, pos_y):
                        self.reset_game(main_board, move_direction)


                # 判断键盘点击事件
                if event.type == KEYUP:
                    if event.key == K_LEFT:
                        slide_to = self.LEFT
                        if self.valid_move(main_board, slide_to):
                            self.move_animation(main_board, slide_to, self.ANIMATION_SPEED)
                            self.make_move(main_board, slide_to)
                            move_direction.append(slide_to)
                    elif event.key == K_RIGHT:
                        slide_to = self.RIGHT
                        if self.valid_move(main_board, slide_to):
                            self.move_animation(main_board, slide_to, self.ANIMATION_SPEED)
                            self.make_move(main_board, slide_to)
                            move_direction.append(slide_to)
                    elif event.key == K_UP:
                        slide_to = self.UP
                        if self.valid_move(main_board, slide_to):
                            self.move_animation(main_board, slide_to, self.ANIMATION_SPEED)
                            self.make_move(main_board, slide_to)
                            move_direction.append(slide_to)
                    elif event.key == K_DOWN:
                        slide_to = self.DOWN
                        if self.valid_move(main_board, slide_to):
                            self.move_animation(main_board, slide_to, self.ANIMATION_SPEED)
                            self.make_move(main_board, slide_to)
                            move_direction.append(slide_to)

            pygame.display.update()
            self.DISPLAY_CLOCK.tick(self.FPS)


if __name__ == '__main__':
    play = SlidePuzzle()
    play.main()


### 使用 Pygame 实现数字华容道游戏 #### 项目概述 数字华容道是一种经典的益智类小游戏,玩家通过移动方块来使特定编号的方块到达指定位置。该游戏可以利用 Pygame开发图形界面并处理用户交互。 #### 准备工作 安装所需的库可以通过 pip 完成: ```bash pip install pygame ``` #### 主要功能模块设计 1. **初始化设置** - 设置窗口大小、颜色等基本参数。 2. **创建棋盘布局** - 构建初始状态下的空白格子以及各个数字的位置分布。 3. **事件监听器** - 处理鼠标点击事件以判断是否能够交换相邻两格的内容。 4. **胜利条件检测** - 当所有数字按照顺序排列完成时提示获胜信息。 #### 示例代码片段 下面是一个简化的实现框架: ```python import sys import random import pygame as pg class SlidePuzzle: def __init__(self, size=4): self.size = size self.board = [[None]*size for _ in range(size)] nums = list(range(1, size*size)) + [None] random.shuffle(nums) idx = iter(nums) for row in range(self.size): for col in range(self.size): self.board[row][col] = next(idx) self.empty_pos = (size-1, size-1) def draw_board(self, screen): block_size = min(screen.get_width(), screen.get_height()) // self.size font = pg.font.Font(None, int(block_size * .7)) for r in range(self.size): for c in range(self.size): rect = pg.Rect(c*block_size, r*block_size, block_size, block_size) if num := self.board[r][c]: color = 'lightblue' text_surf = font.render(str(num), True, "black") screen.fill(color, rect.inflate(-8, -8)) screen.blit(text_surf, text_surf.get_rect(center=rect.center)) def move_tile(self, pos): erow, ecol = self.empty_pos trow, tcol = pos dr, dc = abs(erow-trow), abs(ecol-tcol) if not ((dr == 1 and dc == 0) or (dc == 1 and dr == 0)): return False self.board[erow][ecol], self.board[trow][tcol] \ = self.board[trow][tcol], None self.empty_pos = trow, tcol return True def main(): pg.init() clock = pg.time.Clock() puzzle = SlidePuzzle() win_widht = 600 win_height = 600 window_surface = pg.display.set_mode((win_widht, win_height)) pg.display.set_caption('Slide Puzzle') running = True while running: for event in pg.event.get(): if event.type == pg.QUIT: running = False elif event.type == pg.MOUSEBUTTONDOWN: mouse_x, mouse_y = event.pos block_side_len = min(win_widht, win_height)//puzzle.size clicked_row = mouse_y//block_side_len clicked_col = mouse_x//block_side_len moved_successfully = puzzle.move_tile( (clicked_row, clicked_col)) window_surface.fill("white") puzzle.draw_board(window_surface) pg.display.flip() clock.tick(30) if __name__ == '__main__': try: main() finally: pg.quit() ``` 该程序展示了如何构建一个简单的滑动拼图游戏,并允许玩家通过单击屏幕上的不同部分来进行游戏操作[^2]。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值