用Python手把手教你实现2048小游戏
作者:彳余大胆 时间:2023-02-22 23:27:57
一、开发环境
Python版本:3.6.4
相关模块:
pygame模块;
以及一些Python自带的模块。
二、环境搭建
安装Python并添加到环境变量,pip安装需要的相关模块即可。
三、原理介绍
“使用方向键移动方块,两个数字相同的方块撞在一起后,将会合并为一个数字是原来两倍的新方块。游戏的时候尽可能多地合并这些数字方块就行了。”
大概了解了游戏规则之后,我们就可以开始写这个游戏啦~首先,进行一下游戏初始化操作并播放一首自己喜欢的游戏背景音乐:
# 游戏初始化
pygame.init()
screen = pygame.display.set_mode(cfg.SCREENSIZE)
pygame.display.set_caption('2048 —— 彳余大胆')
# 播放背景音乐
pygame.mixer.music.load(cfg.BGMPATH)
pygame.mixer.music.play(-1, 30)
接着,我们来定义一个2048游戏类,里面主要负责实现2048的各种游戏规则:
'''2048游戏'''
class Game2048(object):
def __init__(self, matrix_size=(4, 4), max_score_filepath=None, **kwargs):
# matrix_size: (num_rows, num_cols)
self.matrix_size = matrix_size
# 游戏最高分保存路径
self.max_score_filepath = max_score_filepath
# 初始化
self.initialize()
具体而言,我们先用一个二维的列表来保存当前的游戏状态:
self.game_matrix = [['null' for _ in range(self.matrix_size[1])] for _ in range(self.matrix_size[0])]
其中null表示当前的块里没有数字。否则,对应的位置则用当前的数字表示。很显然地,2048小游戏的当前游戏状态是可以用一个4*4的列表表示的:
游戏一开始,我们需要在这个二维列表里随机地选择两个位置生成数字(即2或者4):
'''在新的位置随机生成数字'''
def randomGenerateNumber(self):
empty_pos = []
for i in range(self.matrix_size[0]):
for j in range(self.matrix_size[1]):
if self.game_matrix[i][j] == 'null': empty_pos.append([i, j])
i, j = random.choice(empty_pos)
self.game_matrix[i][j] = 2 if random.random() > 0.1 else 4
self.randomGenerateNumber()
self.randomGenerateNumber()
然后,当玩家按下方向键(↑↓←→)时,这个二维列表要根据玩家的操作指令进行更新,主要分为两个部分:
移动所有的数字块并进行必要的合并和记分;
随机地在一个还没有数字的位置上生成一个数字。
具体而言,代码实现如下:
'''更新游戏状态'''
def update(self):
game_matrix_before = copy.deepcopy(self.game_matrix)
self.move()
if game_matrix_before != self.game_matrix: self.randomGenerateNumber()
其中,移动所有的数字并进行必要的合并的代码实现如下:
'''根据指定的方向, 移动所有数字块'''
def move(self):
# 提取非空数字
def extract(array):
array_new = []
for item in array:
if item != 'null': array_new.append(item)
return array_new
# 合并非空数字
def merge(array):
score = 0
if len(array) < 2: return array, score
for i in range(len(array)-1):
if array[i] == 'null':
break
if array[i] == array[i+1]:
array[i] *= 2
array.pop(i+1)
array.append('null')
score += array[i]
return extract(array), score
# 不需要移动的话直接return
if self.move_direction is None: return
# 向上
if self.move_direction == 'up':
for j in range(self.matrix_size[1]):
col = []
for i in range(self.matrix_size[0]):
col.append(self.game_matrix[i][j])
col = extract(col)
col.reverse()
col, score = merge(col)
self.score += score
col.reverse()
col = col + ['null',] * (self.matrix_size[0] - len(col))
for i in range(self.matrix_size[0]):
self.game_matrix[i][j] = col[i]
# 向下
elif self.move_direction == 'down':
for j in range(self.matrix_size[1]):
col = []
for i in range(self.matrix_size[0]):
col.append(self.game_matrix[i][j])
col = extract(col)
col, score = merge(col)
self.score += score
col = ['null',] * (self.matrix_size[0] - len(col)) + col
for i in range(self.matrix_size[0]):
self.game_matrix[i][j] = col[i]
# 向左
elif self.move_direction == 'left':
for idx, row in enumerate(copy.deepcopy(self.game_matrix)):
row = extract(row)
row.reverse()
row, score = merge(row)
self.score += score
row.reverse()
row = row + ['null',] * (self.matrix_size[1] - len(row))
self.game_matrix[idx] = row
# 向右
elif self.move_direction == 'right':
for idx, row in enumerate(copy.deepcopy(self.game_matrix)):
row = extract(row)
row, score = merge(row)
self.score += score
row = ['null',] * (self.matrix_size[1] - len(row)) + row
self.game_matrix[idx] = row
self.move_direction = None
懒得动脑子了(反正就4*4那么大T_T),所以直接遍历了这个二维列表以实现我们想要的所有操作了。最后,我们再写个函数以根据当前的游戏状态来判断游戏是否结束就ok啦:
'''游戏是否结束'''
@property
def isgameover(self):
for i in range(self.matrix_size[0]):
for j in range(self.matrix_size[1]):
if self.game_matrix[i][j] == 'null': return False
if (i == self.matrix_size[0] - 1) and (j == self.matrix_size[1] - 1):
continue
elif (i == self.matrix_size[0] - 1):
if (self.game_matrix[i][j] == self.game_matrix[i][j+1]):
return False
elif (j == self.matrix_size[1] - 1):
if (self.game_matrix[i][j] == self.game_matrix[i+1][j]):
return False
else:
if (self.game_matrix[i][j] == self.game_matrix[i+1][j]) or (self.game_matrix[i][j] == self.game_matrix[i][j+1]):
return False
return True
其实很简单,如果二维列表被数字填满,且数字不能再进行合并的话,这局游戏就结束了,否则,游戏就没有结束。
定义完2048游戏类,我们的游戏基本上算是写完了。只需要在游戏主循环里根据用户操作来更新当前的游戏状态并将游戏里所有必要的元素显示在屏幕上就ok啦:
# 游戏主循环
clock = pygame.time.Clock()
is_running = True
while is_running:
screen.fill(pygame.Color(cfg.BG_COLOR))
# --按键检测
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
elif event.type == pygame.KEYDOWN:
if event.key in [pygame.K_UP, pygame.K_DOWN, pygame.K_LEFT, pygame.K_RIGHT]:
game_2048.setDirection({pygame.K_UP: 'up', pygame.K_DOWN: 'down', pygame.K_LEFT: 'left', pygame.K_RIGHT: 'right'}[event.key])
# --更新游戏状态
game_2048.update()
if game_2048.isgameover:
game_2048.saveMaxScore()
is_running = False
# --将必要的游戏元素画到屏幕上
drawGameMatrix(screen, game_2048.game_matrix, cfg)
start_x, start_y = drawScore(screen, game_2048.score, game_2048.max_score, cfg)
drawGameIntro(screen, start_x, start_y, cfg)
# --屏幕更新
pygame.display.update()
clock.tick(cfg.FPS)
return endInterface(screen, cfg)
四、效果图
最后的效果大概是这样的:
玩这个我还是一个菜鸡,嘿嘿~
来源:https://blog.csdn.net/Gtieguo/article/details/117465249