項目簡介:設計經(jīng)典游戲——俄羅斯方塊唆姐。
1延曙、項目需求
使用 Python 的第三個庫 Pygame 來制作俄羅斯方塊险掀。
2嗜价、項目思路
俄羅斯方塊其實就是一副能夠實現(xiàn)人機交互的動畫腋妙,可以讓人來控制四格拼版?zhèn)€的圖形樣式和位置的呈現(xiàn)默怨。那么動畫的原理是什么呢?就以我的孩子在繪畫培訓班的例子來做解答骤素,就是讓孩子先畫出一副一副的靜態(tài)圖片匙睹,然后再將一副一副的靜態(tài)圖片裝訂成冊,然后快速進行快速翻書济竹,那么就會呈現(xiàn)出來動畫的效果痕檬。
翻書
知道了動畫的原理之后,對照我們的俄羅斯方塊游戲送浊,其實就是將不同樣式的四格拼版在游戲區(qū)域中的不同位置分解成 N 多張靜態(tài)的圖片梦谜。
3、項目步驟
- 構建 Python 開發(fā)環(huán)境袭景。
- 在窗體內構建四格拼版游戲區(qū)域唁桩。
- 在游戲區(qū)域內活動小方格。
- 在游戲區(qū)域內繪制不同樣式的四格拼板耸棒。
- 四格拼板的沖突和限制荒澡。
4、代碼展示
# -*- coding: utf-8 -*-
import pygame, random
__author__ = {
'name': "東方鶚",
'github': "https://github.com/eastossifrage",
'B 站主頁': "https://space.bilibili.com/194359739",
'知乎專欄': "https://zhuanlan.zhihu.com/ousi-python",
'簡書專欄': "http://www.reibang.com/c/2036276cf0e8",
'version': "1.0"
}
# 定義幾個顏色 R G B
bgcolor = ( 30, 25, 25) # 背景設置為黑色
yellow = (255, 245, 40) # 黃色
light_yellow = (175, 175, 20)
white = (255, 245, 245)
gray = (185, 185, 185)
black = ( 0, 0, 0)
red = (155, 0, 0)
light_red = (175, 20, 20)
green = ( 0, 155, 0)
light_green = ( 20, 175, 20)
blue = ( 0, 0, 155)
light_blue = ( 20, 20, 175)
# 定義顏色元組
colors = (yellow, gray, black, red, green, blue)
# 定義屏幕大小
s_width = 800
s_height = 600
# 定義俄羅斯方塊游戲區(qū)域的大小
a_width = 364
a_height = 544
# 定義正方形的大小
edge = 20
# 定義游戲區(qū)域左上角坐標
coordinate = ((s_width-a_width)//4, s_height-a_height)
# 定義游戲區(qū)域中的小方格的行列數(shù)
box_row = a_height//edge # 小方格的每列個數(shù)与殃,也就是行數(shù)
box_col = a_width//edge # 小方格的每行個數(shù)单山,也就是列數(shù)
#定義游戲區(qū)域中的小方格的開始位置
inital_pos = (0, int(box_col//2))
# 以下是七種形狀的拼版按照小方格的位置所對應的坐標
I = [[(0, -1), (0, 0), (0, 1), (0, 2)],
[(-1, 0), (0, 0), (1, 0), (2, 0)]]
J = [[(-2, 0), (-1, 0), (0, 0), (0, -1)],
[(-1, 0), (0, 0), (0, 1), (0, 2)],
[(0, 1), (0, 0), (1, 0), (2, 0)],
[(0, -2), (0, -1), (0, 0), (1, 0)]]
L = [[(-2, 0), (-1, 0), (0, 0), (0, 1)],
[(1, 0), (0, 0), (0, 1), (0, 2)],
[(0, -1), (0, 0), (1, 0), (2, 0)],
[(0, -2), (0, -1), (0, 0), (-1, 0)]]
O = [[(0, 0), (0, 1), (1, 0), (1, 1)]]
S = [[(-1, 0), (0, 0), (0, 1), (1, 1)],
[(1, -1), (1, 0), (0, 0), (0, 1)]]
T = [[(0, -1), (0, 0), (0, 1), (-1, 0)],
[(-1, 0), (0, 0), (1, 0), (0, 1)],
[(0, -1), (0, 0), (0, 1), (1, 0)],
[(-1, 0), (0, 0), (1, 0), (0, -1)]]
Z = [[(0, -1), (0, 0), (1, 0), (1, 1)],
[(-1, 0), (0, 0), (0, -1), (1, -1)]]
# 定義拼版元組
# shapes_tuple = (I, J, L, O, S, T, Z)
shapes_tuple = (J, L, S, T, Z)
# 定義刷新頻率
fps = 15 #設置屏幕刷新率
def box(rect, color):
''' 功能:畫出用于組成圖形的單個正方形
參數(shù):rect: 該參數(shù)為一個pygame.Rect對象在游戲區(qū)域的相對坐標
color:小方格的顏色
'''
pygame.Surface.fill(screen, color, rect) # 填充方格內的顏色
pygame.draw.rect(screen, white, rect, 1) # 畫出方格的線條
def area():
''' 功能:畫出游戲區(qū)域
'''
rect = pygame.Rect(coordinate, (a_width, a_height))
pygame.draw.rect(screen, light_blue, rect, 5) # 畫出游戲區(qū)域
def rect_matrix():
''' 功能:以游戲區(qū)域為基礎,畫出用于呈現(xiàn)方塊圖形的矩陣幅疼。
'''
# 下面一行列表推導的代碼用于構造小方格的二維列表
return [[pygame.Rect((coordinate[0] + x*edge + 2),
(coordinate[1] + y*edge + 2), edge, edge)
for x in range(box_col)] for y in range(box_row)]
def color_matrix():
''' 功能:以游戲區(qū)域為基礎米奸,畫出用于呈現(xiàn)方塊顏色的矩陣。'''
# 下面一行列表推導的代碼用于構造小方格顏色的二維列表爽篷,默認是 None
return [[None for x in range(box_col)] for y in range(box_row)]
def show_shape(rect_matrix, row, col, shape, color):
'''功能:顯示游戲區(qū)域內的四格拼版躏升。
參數(shù):matrix: 游戲區(qū)域的網(wǎng)格的坐標
row:拼版的中心點相對背景網(wǎng)格的橫坐標
col:拼版的中心點相對背景網(wǎng)格的縱坐標
shape: 四格拼版的小方格相對于中心點的坐標
color:拼版的顏色
'''
for x in shape:
if row+x[0] >= 0: # 舍棄中心點以上部分,防止從最底部出現(xiàn)
box(rect_matrix[row+x[0]][col+x[1]], color)
def conflict(color_matrix, row, col, shape):
'''功能:檢測游戲區(qū)域內的四格拼版是否與底部邊界或其它已存在的拼版有沖突狼忱。
參數(shù):matrix: 游戲區(qū)域的網(wǎng)格的坐標
row:拼版的中心點相對背景網(wǎng)格的橫坐標
col:拼版的中心點相對背景網(wǎng)格的縱坐標
shape: 四格拼版的小方格相對于中心點的坐標
'''
for x in shape:
if row+x[0] >= box_row: # 檢測四格拼版是否與
return True # 游戲區(qū)域內的底部邊界有沖突
if row+x[0] >= 0 and \
color_matrix[row+x[0]][col+x[1]] != None: # 檢測四格拼板中的小方格是否
return True # 與當前位置有沖突
return False
def clear_line(color_matrix):
'''功能:清空已連成一線的行'''
num = 0
for x in color_matrix:
if None not in x:
num = color_matrix.index(x)
for i in reversed(range(1, num+1)): # 需要倒序輸出
color_matrix[i] = color_matrix[i-1]
if __name__ == "__main__":
pygame.init() # 使用 pygame 之前先進行初始化
clock=pygame.time.Clock() # 定義時鐘
screen = pygame.display.set_mode((s_width, s_height), pygame.RESIZABLE, 32)
# 上面一行代碼的功能為設置屏幕大小膨疏,此實例為 800*600一睁,
# 第二個參數(shù)是 RESIZABLE,表示打開一個可以改變大小的窗口佃却,
# 第三個參數(shù)是 32 位真彩色者吁。
pygame.display.set_caption("俄羅斯方塊") # 設置窗體名稱
r_mtx = rect_matrix()
c_mtx = color_matrix()
row, col = inital_pos
color = random.choice(colors)
shapes = random.choice(shapes_tuple)
shape = random.choice(shapes)
shape_num = shapes.index(shape) # 獲取四格拼板的形狀列表的下標
while True:
#pygame.time.delay(25)
screen.fill(bgcolor) # 表示填充背景顏色。
for event in pygame.event.get():
if event.type == pygame.QUIT: # 檢測退出動作
exit()
area()
for r in range(box_row):
for c in range(box_col):
if c_mtx[r][c] is not None:
box(r_mtx[r][c], c_mtx[r][c])
shape_left = min(shape, key=lambda x:x[1])[1] # 拼版的最左邊坐標值
shape_right = max(shape, key=lambda x:x[1])[1] # 拼版的最右邊坐標值
cft = conflict(c_mtx, row, col, shape)
keys = pygame.key.get_pressed() # 檢測鍵盤動作
if keys[pygame.K_LEFT] and not cft: # 使用向左鍵來控制方塊向左移動
if col + shape_left > 0:
col -= 1
if conflict(c_mtx, row, col, shape): # 如果沖突
col += 1 # 回退一格
if keys[pygame.K_RIGHT] and not cft: # 使用向左鍵來控制方塊向右移動
if col + shape_right < box_col-1:
col += 1
if conflict(c_mtx, row, col, shape): # 如果沖突
col -= 1 # 回退一格
if keys[pygame.K_a] and not cft: # 使用 W 鍵將拼版左轉
shape_num -= 1
shape = shapes[shape_num%len(shapes)] # 選擇新拼版
shape_left = min(shape, key=lambda x:x[1])[1] # 新拼版的最左邊坐標值
shape_right = max(shape, key=lambda x:x[1])[1] # 新拼版的最右邊坐標值
if col+shape_left < 0 or \
col+shape_right > box_col-1 or \
conflict(c_mtx, row, col, shape): # 如果沖突饲帅、超出左或右邊界
# 要注意 or 邏輯的短路順序
shape_num += 1 # 回退到上一個拼版
shape = shapes[shape_num%len(shapes)] # 選擇原拼版
if keys[pygame.K_d] and not cft: # 使用 D 鍵將拼版右轉
shape_num += 1
shape = shapes[shape_num%len(shapes)]
shape_left = min(shape, key=lambda x:x[1])[1] # 拼版的最左邊坐標值
shape_right = max(shape, key=lambda x:x[1])[1] # 拼版的最右邊坐標值
if col+shape_left < 0 or \
col+shape_right > box_col-1 or \
conflict(c_mtx, row, col, shape): # 如果沖突复凳、超出左或右邊界
# 要注意 or 邏輯的短路順序
shape_num -= 1 # 回退到上一個拼版
shape = shapes[shape_num%len(shapes)] # 選擇原拼版
if cft:
for x in shape:
if row+x[0] > 0: # 舍棄中心點以上部分,防止從最底部出現(xiàn)
c_mtx[row+x[0]-1][col+x[1]] = color
if row != 0: # 檢測拼版重疊的位置是否在第一行灶泵,如果不是育八,生成新拼版
row, col = inital_pos # 設置新拼版的起始位置
color = random.choice(colors) # 重新選擇顏色
shapes = random.choice(shapes_tuple)
shape = random.choice(shapes) # 重新選擇拼版
else: # 檢測拼版重疊的位置是否在第一行,如果是赦邻,游戲結束
print("GAME OVER")
break
else:
clear_line(c_mtx) # 清空已填滿的行
show_shape(r_mtx, row, col, shape, color) # 顯示游戲區(qū)域內的四格拼版
row += 1
clock.tick(fps)
pygame.display.update()