python 基於pygame實現俄羅斯方塊

一、簡單說明

80、90後的小夥伴都玩過“俄羅斯方塊”,那種“叱吒風雲”場景 偶爾閃現在腦海 真的是太爽瞭;如果沒有來得及玩過的同學,這次可以真正的自己做一個瞭

本實例用的是Python3(當然瞭Python3.5 3.6 3.7….都行 )+ pygame實現的

運行之前需要安裝pygame模塊,安裝命令如下

pip install pygame -i https://mirrors.aliyun.com/pypi/simple/

二、運行效果

三、完整代碼

文件main.py代碼如下:

"""
作者:it項目實例網
更多項目實例,請訪問:www.itprojects.cn
"""

import random
import sys
import time

import pygame

from blocks import block_s, block_i, block_j, block_l, block_o, block_t, block_z

SCREEN_WIDTH, SCREEN_HEIGHT = 450, 750
BG_COLOR = (40, 40, 60) # 背景色
BLOCK_COL_NUM = 10 # 每行的方格數
SIZE = 30 # 每個小方格大小
BLOCK_ROW_NUM = 25 # 每列的方個數
BORDER_WIDTH = 4 # 遊戲區邊框寬度
RED = (200, 30, 30) # 紅色,GAME OVER 的字體顏色


def judge_game_over(stop_all_block_list):
 """
 判斷遊戲是否結束
 """
 if "O" in stop_all_block_list[0]:
  return True


def change_speed(score):
 speed_level = [("1", 0.5, 0, 20), ("2", 0.4, 21, 50), ("3", 0.3, 51, 100), ("4", 0.2, 101, 200), ("5", 0.1, 201, None)]
 for speed_info, speed, score_start, score_stop in speed_level:
  if score_stop and score_start <= score <= score_stop:
   return speed_info, speed
  elif score_stop is None and score >= score_start:
   return speed_info, speed


def judge_lines(stop_all_block_list):
 """
 判斷是否有同一行的方格,如果有則消除
 """
 # 記錄剛剛消除的行數
 move_row_list = list()
 # 消除滿格的行
 for row, line in enumerate(stop_all_block_list):
  if "." not in line:
   # 如果這一行沒有. 那麼就意味著全部是O,則消除這一行
   stop_all_block_list[row] = ['.' for _ in range(len(line))]
   move_row_list.append(row)

 # 如果沒有滿格的行,則結束此函數
 if not move_row_list:
  return 0

 # 移動剩餘的行到下一行
 for row in move_row_list:
  stop_all_block_list.pop(row)
  stop_all_block_list.insert(0, ['.' for _ in range(len(line))])

 return len(move_row_list) * 10


def add_to_stop_all_block_list(stop_all_block_list, current_block, current_block_start_row, current_block_start_col):
 """
 將當前已經停止移動的block添加到列表中
 """
 for row, line in enumerate(current_block):
  for col, block in enumerate(line):
   if block != '.':
    stop_all_block_list[current_block_start_row + row][current_block_start_col + col] = "O"


def change_current_block_style(current_block):
 """
 改變圖形的樣式
 """
 # 計算出,當前圖形樣式屬於哪個圖形
 current_block_style_list = None
 for block_style_list in [block_s, block_i, block_j, block_l, block_o, block_t, block_z]:
  if current_block in block_style_list:
   current_block_style_list = block_style_list

 # 得到當前正在用的圖形的索引(下標)
 index = current_block_style_list.index(current_block)
 # 它的下一個圖形的索引
 index += 1
 # 防止越界
 index = index % len(current_block_style_list)
 # 返回下一個圖形
 return current_block_style_list[index]


def judge_move_right(current_block, current_block_start_col):
 """
 判斷是否可以向右移動
 """
 # 先判斷列的方式是從右到左
 for col in range(len(current_block[0]) - 1, -1, -1):
  # 得到1列的所有元素
  col_list = [line[col] for line in current_block]
  # 判斷是否碰到右邊界
  if 'O' in col_list and current_block_start_col + col >= BLOCK_COL_NUM:
   return False
 return True


def judge_move_left(current_block, current_block_start_col):
 """
 判斷是否可以向左移動
 """
 # 先判斷列的方式是從左到右
 for col in range(len(current_block[0])):
  # 得到1列的所有元素
  col_list = [line[col] for line in current_block]
  # 判斷是否碰到右邊界
  if 'O' in col_list and current_block_start_col + col < 0:
   return False
 return True


def judge_move_down(current_block, current_block_start_row, current_block_start_col, stop_all_block_list):
 """
 判斷是否碰撞到其它圖形或者底邊界
 """
 # 得到其它圖形所有的坐標
 stop_all_block_position = list()
 for row, line in enumerate(stop_all_block_list):
  for col, block in enumerate(line):
   if block != ".":
    stop_all_block_position.append((row, col))
 # print(stop_all_block_position)

 # 判斷碰撞
 for row, line in enumerate(current_block):
  if 'O' in line and current_block_start_row + row >= BLOCK_ROW_NUM:
   # 如果當前行有0,且從起始行開始算+當前顯示的行,超過瞭總行數,那麼就認為碰到瞭底部
   return False
  for col, block in enumerate(line):
   if block != "." and (current_block_start_row + row, current_block_start_col + col) in stop_all_block_position:
    return False

 return True


def get_block():
 """
 創建一個圖形
 """
 block_style_list = random.choice([block_s, block_i, block_j, block_l, block_o, block_t, block_z])
 return random.choice(block_style_list)


def main():
 pygame.init()
 screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
 pygame.display.set_caption('俄羅斯方塊')

 current_block = get_block() # 當前圖形
 current_block_start_row = -2 # 當前圖片從哪一行開始顯示圖形
 current_block_start_col = 4 # 當前圖形從哪一列開始顯示
 next_block = get_block() # 下一個圖形
 last_time = time.time()
 speed = 0.5 # 降落的速度
 speed_info = '1' # 顯示的速度等級

 # 定義一個列表,用來存儲所有的已經停止移動的形狀
 stop_all_block_list = [['.' for i in range(BLOCK_COL_NUM)] for j in range(BLOCK_ROW_NUM)]

 # 字體
 font = pygame.font.Font('yh.ttf', 24) # 黑體24
 game_over_font = pygame.font.Font("yh.ttf", 72)
 game_over_font_width, game_over_font_height = game_over_font.size('GAME OVER')
 game_again_font_width, game_again_font_height = font.size('鼠標點擊任意位置,再來一局')

 # 得分
 score = 0

 # 標記遊戲是否結束
 game_over = False

 # 創建計時器(防止while循環過快,占用太多CPU的問題)
 clock = pygame.time.Clock()
 while True:
  for event in pygame.event.get():
   if event.type == pygame.QUIT:
    sys.exit()
   elif event.type == pygame.KEYDOWN:
    if event.key == pygame.K_LEFT:
     if judge_move_left(current_block, current_block_start_col - 1):
      current_block_start_col -= 1
    elif event.key == pygame.K_RIGHT:
     if judge_move_right(current_block, current_block_start_col + 1):
      current_block_start_col += 1
    elif event.key == pygame.K_UP:
     current_block_next_style = change_current_block_style(current_block)
     if judge_move_left(current_block_next_style, current_block_start_col) and \
       judge_move_right(current_block_next_style, current_block_start_col) and \
       judge_move_down(current_block, current_block_start_row, current_block_start_col, stop_all_block_list):
      # 判斷新的樣式沒有越界
      current_block = current_block_next_style
    elif event.key == pygame.K_DOWN:
     # 判斷是否可以向下移動,如果碰到底部或者其它的圖形就不能移動瞭
     if judge_move_down(current_block, current_block_start_row + 1, current_block_start_col, stop_all_block_list):
      current_block_start_row += 1
   elif event.type == pygame.MOUSEBUTTONDOWN and event.button:
    if game_over:
     # 重置遊戲用到的變量
     current_block = get_block() # 當前圖形
     current_block_start_row = -2 # 當前圖片從哪一行開始顯示圖形
     current_block_start_col = 4 # 當前圖形從哪一列開始顯示
     next_block = get_block() # 下一個圖形
     stop_all_block_list = [['.' for i in range(BLOCK_COL_NUM)] for j in range(BLOCK_ROW_NUM)]
     score = 0
     game_over = False

  # 判斷是否修改當前圖形顯示的起始行
  if not game_over and time.time() - last_time > speed:
   last_time = time.time()
   # 判斷是否可以向下移動,如果碰到底部或者其它的圖形就不能移動瞭
   if judge_move_down(current_block, current_block_start_row + 1, current_block_start_col, stop_all_block_list):
    current_block_start_row += 1
   else:
    # 將這個圖形存儲到統一的列表中,這樣便於判斷是否成為一行
    add_to_stop_all_block_list(stop_all_block_list, current_block, current_block_start_row, current_block_start_col)
    # 判斷是否有同一行的,如果有就消除,且加上分數
    score += judge_lines(stop_all_block_list)
    # 判斷遊戲是否結束(如果第一行中間有O那麼就表示遊戲結束)
    game_over = judge_game_over(stop_all_block_list)
    # 調整速度
    speed_info, speed = change_speed(score)
    # 創建新的圖形
    current_block = next_block
    next_block = get_block()
    # 重置數據
    current_block_start_col = 4
    current_block_start_row = -2

  # 畫背景(填充背景色)
  screen.fill(BG_COLOR)

  # 畫遊戲區域分隔線
  pygame.draw.line(screen, (100, 40, 200), (SIZE * BLOCK_COL_NUM, 0), (SIZE * BLOCK_COL_NUM, SCREEN_HEIGHT), BORDER_WIDTH)

  # 顯示當前圖形
  for row, line in enumerate(current_block):
   for col, block in enumerate(line):
    if block != '.':
     pygame.draw.rect(screen, (20, 128, 200), ((current_block_start_col + col) * SIZE, (current_block_start_row + row) * SIZE, SIZE, SIZE), 0)

  # 顯示所有停止移動的圖形
  for row, line in enumerate(stop_all_block_list):
   for col, block in enumerate(line):
    if block != '.':
     pygame.draw.rect(screen, (20, 128, 200), (col * SIZE, row * SIZE, SIZE, SIZE), 0)

  # 畫網格線 豎線
  for x in range(BLOCK_COL_NUM):
   pygame.draw.line(screen, (0, 0, 0), (x * SIZE, 0), (x * SIZE, SCREEN_HEIGHT), 1)
  # 畫網格線 橫線
  for y in range(BLOCK_ROW_NUM):
   pygame.draw.line(screen, (0, 0, 0), (0, y * SIZE), (BLOCK_COL_NUM * SIZE, y * SIZE), 1)

  # 顯示右側(得分、速度、下一行圖形)
  # 得分
  score_show_msg = font.render('得分: ', True, (255, 255, 255))
  screen.blit(score_show_msg, (BLOCK_COL_NUM * SIZE + 10, 10))
  score_show_msg = font.render(str(score), True, (255, 255, 255))
  screen.blit(score_show_msg, (BLOCK_COL_NUM * SIZE + 10, 50))
  # 速度
  speed_show_msg = font.render('速度: ', True, (255, 255, 255))
  screen.blit(speed_show_msg, (BLOCK_COL_NUM * SIZE + 10, 100))
  speed_show_msg = font.render(speed_info, True, (255, 255, 255))
  screen.blit(speed_show_msg, (BLOCK_COL_NUM * SIZE + 10, 150))
  # 下一個圖形(文字提示)
  next_style_msg = font.render('下一個: ', True, (255, 255, 255))
  screen.blit(next_style_msg, (BLOCK_COL_NUM * SIZE + 10, 200))
  # 下一個圖形(圖形)
  for row, line in enumerate(next_block):
   for col, block in enumerate(line):
    if block != '.':
     pygame.draw.rect(screen, (20, 128, 200), (320 + SIZE * col, (BLOCK_COL_NUM + row) * SIZE, SIZE, SIZE), 0)
     # 顯示這個方格的4個邊的顏色
     # 左
     pygame.draw.line(screen, (0, 0, 0), (320 + SIZE * col, (BLOCK_COL_NUM + row) * SIZE), (320 + SIZE * col, (BLOCK_COL_NUM + row + 1) * SIZE), 1)
     # 上
     pygame.draw.line(screen, (0, 0, 0), (320 + SIZE * col, (BLOCK_COL_NUM + row) * SIZE), (320 + SIZE * (col + 1), (BLOCK_COL_NUM + row) * SIZE), 1)
     # 下
     pygame.draw.line(screen, (0, 0, 0), (320 + SIZE * col, (BLOCK_COL_NUM + row + 1) * SIZE), (320 + SIZE * (col + 1), (BLOCK_COL_NUM + row + 1) * SIZE), 1)
     # 右
     pygame.draw.line(screen, (0, 0, 0), (320 + SIZE * (col + 1), (BLOCK_COL_NUM + row) * SIZE), (320 + SIZE * (col + 1), (BLOCK_COL_NUM + row + 1) * SIZE), 1)

  # 顯示遊戲結束畫面
  if game_over:
   game_over_tips = game_over_font.render('GAME OVER', True, RED)
   screen.blit(game_over_tips, ((SCREEN_WIDTH - game_over_font_width) // 2, (SCREEN_HEIGHT - game_over_font_height) // 2))
   # 顯示"鼠標點擊任意位置,再來一局"
   game_again = font.render('鼠標點擊任意位置,再來一局', True, RED)
   screen.blit(game_again, ((SCREEN_WIDTH - game_again_font_width) // 2, (SCREEN_HEIGHT - game_again_font_height) // 2 + 80))

  # 刷新顯示(此時窗口才會真正的顯示)
  pygame.display.update()
  # FPS(每秒鐘顯示畫面的次數)
  clock.tick(60) # 通過一定的延時,實現1秒鐘能夠循環60次


if __name__ == '__main__':
 main()

文件blocks.py代碼如下:

# S形方塊
block_s = [['.OO',
   'OO.',
   '...'],
   ['O..',
   'OO.',
   '.O.']]
# Z形方塊
block_z = [['OO.',
   '.OO',
   '...'],
   ['.O.',
   'OO.',
   'O..']]
# I型方塊
block_i = [['.O..',
   '.O..',
   '.O..',
   '.O..'],
   ['....',
   '....',
   'OOOO',
   '....']]
# O型方塊
block_o = [['OO',
   'OO']]
# J型方塊
block_j = [['O..',
   'OOO',
   '...'],
   ['.OO',
   '.O.',
   '.O.'],
   ['...',
   'OOO',
   '..O'],
   ['.O.',
   '.O.',
   'OO.']]
# L型方塊
block_l = [['..O',
   'OOO',
   '...'],
   ['.O.',
   '.O.',
   '.OO'],
   ['...',
   'OOO',
   'O..'],
   ['OO.',
   '.O.',
   '.O.']]
# T型方塊
block_t = [['.O.',
   'OOO',
   '...'],
   ['.O.',
   '.OO',
   '.O.'],
   ['...',
   'OOO',
   '.O.'],
   ['.O.',
   'OO.',
   '.O.']]

以上就是python 基於pygame實現俄羅斯方塊的詳細內容,更多關於python 俄羅斯方塊的資料請關註WalkonNet其它相關文章!

推薦閱讀: