游戏截图
游戏源码
写的一个小游戏,欢迎大家指正
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()