python作业-2048小游戏

需了解的知识

Pygame中的各个模块及其功能:

Pygame.init():初始化所有导入的模块

pygame.display:

pygame.display.init()  —  初始化 display 模块

pygame.display.set_mode()  —  初始化一个准备显示的窗口或屏幕

pygame.display.set_caption()  — 设置当前窗口标题

pygame.mixer.music:

pygame.mixer.music.load()  —  加载音乐进行播放

pygame.mixer.music.play()  —  开始播放音乐(参数:int播放次数,-1为无限重复。。)

pygame.time,Clock(创建一个对象帮助跟踪时间):

pygame.time.Clock.tick():  —  更新时钟

pygame.event(用户事件和队列进行交互):

pygame.event.get():  —  在队列中获取事件

pygame.key(与键盘使用的关系):

常用列表:

pygame

Constant      ASCII   Description

---------------------------------

K_BACKSPACE         backspace

K_TAB               tab

K_CLEAR               clear

K_RETURN            return

K_PAUSE               pause

K_ESCAPE      ^[      escape

K_SPACE               space

K_EXCLAIM     !       exclaim

K_QUOTEDBL    "       quotedbl

K_HASH        #       hash

K_DOLLAR      $       dollar

K_AMPERSAND   &       ampersand

K_QUOTE               quote

K_LEFTPAREN   (       left parenthesis

K_RIGHTPAREN  )       right parenthesis

K_ASTERISK    *       asterisk

K_PLUS        +       plus sign

K_COMMA       ,       comma

K_MINUS       -       minus sign

K_PERIOD      .       period

K_SLASH       /       forward slash

K_0           0       0

。。。

K_COLON       :       colon

K_SEMICOLON   ;       semicolon

K_LESS        <       less-than sign

K_EQUALS      =       equals sign

K_GREATER     >       greater-than sign

K_QUESTION    ?       question mark

K_AT          @       at

K_LEFTBRACKET [       left bracket

K_BACKSLASH          backslash

K_RIGHTBRACKET ]      right bracket

K_CARET       ^       caret

K_UNDERSCORE  _       underscore

K_BACKQUOTE   `       grave

K_a           a       a

。。。

K_DELETE              delete

K_KP0                 keypad 0

。。。

K_KP_PERIOD   .       keypad period

K_KP_DIVIDE   /       keypad divide

K_KP_MULTIPLY *       keypad multiply

K_KP_MINUS    -       keypad minus

K_KP_PLUS     +       keypad plus

K_KP_ENTER          keypad enter

K_KP_EQUALS   =       keypad equals

K_UP                  up arrow

K_DOWN                down arrow

K_RIGHT               right arrow

K_LEFT                left arrow

K_INSERT              insert

K_HOME                home

K_END                 end

K_PAGEUP              page up

K_PAGEDOWN            page down

K_F1                  F1

。。。

K_NUMLOCK             numlock

K_CAPSLOCK            capslock

K_SCROLLOCK           scrollock

K_RSHIFT              right shift

K_LSHIFT              left shift

K_RCTRL               right control

K_LCTRL               left control

K_RALT                right alt

K_LALT                left alt

K_RMETA               right meta

K_LMETA               left meta

K_LSUPER              left Windows key

K_RSUPER              right Windows key

K_MODE                mode shift

K_HELP                help

K_PRINT               print screen

K_SYSREQ              sysrq

K_BREAK               break

K_MENU                menu

K_POWER               power

K_EURO                Euro

 

系统结构

Modules存放实现的模块

Resources存放游戏资源文件

cfg.py存放配置文件

实现代码

cfg.py配置文件:

 

import os

'''FPS'''
FPS = 60
'''背景颜色'''
BG_COLOR = '#92877d'
'''屏幕大小'''
SCREENSIZE = (650, 370)
'''保存当前最高分的文件'''
MAX_SCORE_FILEPATH = 'score'
'''字体路径'''
FONTPATH = os.path.join(os.getcwd(), 'resources/font/Gabriola.ttf')
'''背景音乐路径'''
BGMPATH = os.path.join(os.getcwd(), 'resources/audio/bgm.mp3')
'''其他一些必要的常量'''
MARGIN_SIZE = 10
BLOCK_SIZE = 80
GAME_MATRIX_SIZE = (4, 4)

执行文件2048Game.py

# 游戏初始化

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)

# 实例化2048游戏
game_2048 = Game2048(matrix_size=cfg.GAME_MATRIX_SIZE, max_score_filepath=cfg.MAX_SCORE_FILEPATH)

# 游戏主循环
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)

在modules中定义一个Game2048的类(里面主要负责实现2048的各种游戏规则):

class Game2048(object):


   def __init__(self, matrix_size=(4, 4), max_score_filepath=None):

      # matrix_size: (num_rows, num_cols)

      self.matrix_size = matrix_size

      # 游戏最高分保存路径

      self.max_score_filepath = max_score_filepath

      # 初始化

      self.initialize()

游戏开始时需要随机的在二维列表里随机选择两个位置生成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

然后,当玩家按下方向键(↑↓← →)时,这个二维列表要根据玩家的操作指令进行更新,主要分为两个部分:

移动所有的数字块并进行必要的合并和记分;

随机地在一个还没有数字的位置上生成一个数字。

更新游戏状态

def update(self):
   game_matrix_before = copy.deepcopy(self.game_matrix)
   self.move()
   if game_matrix_before != self.game_matrix: self.randomGenerateNumber()
   if self.score > self.max_score: self.max_score = self.score

移动所有的数字并进行必要的合并的代码实现如下:

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

判断游戏是否结束:

游戏是否结束

 

@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

在游戏主循环里根据用户操作来更新当前的游戏状态并将游戏里所有必要的元素显示在屏幕:

# 游戏主循环

 

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)

实验

使用python ./Game2048来执行:

 

总结和展望

       通过此次学习,我了解了python的灵活性以及代码的可阅读性比一般的语言要强,并且如今python社区有许多活跃的用户可以在网络上找到许多相关的资料资源。通过此次学习深刻理解了python中的面向对象思想,也了解了一些游戏的设计想法和可供实现的模块。现如今正在学习其他东西,如果未来有更多充裕的时间可以加深python的理解,学习更多的内容,自己做出更好的项目。

参考:https://mp.weixin.qq.com/s/WJhg4J0MuuEcmDasRzuE9Q

原文地址:https://www.cnblogs.com/jev-0987/p/13073461.html