乐趣区

关于python:用Python写的一个2048小游戏这可能就是程序员的乐趣吧

原理介绍

“应用方向键挪动方块,两个数字雷同的方块撞在一起后,将会合并为一个数字是原来两倍的新方块。游戏的时候尽可能多地合并这些数字方块就行了。”
大略理解了游戏规则之后,咱们就能够开始写这个游戏啦~ 首先,进行一下游戏初始化操作并播放一首本人喜爱的游戏背景音乐:

# 游戏初始化
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)

最初的成果大略是这样的:


写这个程序还行,玩这个网络游戏我还是一个菜鸡,嘿嘿~

退出移动版