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的显示,并绘制到屏幕上。每次获得键盘事件都对原有的表格进行遍历,位置移动,相同数字碰撞叠加。
效果图:
感谢观看点个赞呗!!!!