Python3+pygame實現的俄羅斯方塊 程式碼完整 有演示效果
- 2021 年 3 月 2 日
- 筆記
一、簡單說明
80、90後的小夥伴都玩過「俄羅斯方塊」,那種「叱吒風雲」場景 偶爾閃現在腦海 真的是太爽了;如果沒有來得及玩過的同學,這次可以真正的自己做一個了
本實例用的是Python3(當然了Python3.5 3.6 3.7….都行 )+ pygame實現的
運行之前需要安裝pygame模組,安裝命令如下
pip install pygame -i https://mirrors.aliyun.com/pypi/simple/
二、運行效果
三、完整程式碼
下面的程式碼,用到了字體文件yh.ttf,下載地址 //www.itprojects.cn/detail.html?example_id=8bf48a0ac4cee29043d4122fe6e563cb
文件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.']]