俄羅斯方塊游戲設計

項目簡介:設計經(jīng)典游戲——俄羅斯方塊唆姐。

1延曙、項目需求

使用 Python 的第三個庫 Pygame 來制作俄羅斯方塊险掀。

2嗜价、項目思路

俄羅斯方塊其實就是一副能夠實現(xiàn)人機交互的動畫腋妙,可以讓人來控制四格拼版?zhèn)€的圖形樣式和位置的呈現(xiàn)默怨。那么動畫的原理是什么呢?就以我的孩子在繪畫培訓班的例子來做解答骤素,就是讓孩子先畫出一副一副的靜態(tài)圖片匙睹,然后再將一副一副的靜態(tài)圖片裝訂成冊,然后快速進行快速翻書济竹,那么就會呈現(xiàn)出來動畫的效果痕檬。

翻書

知道了動畫的原理之后,對照我們的俄羅斯方塊游戲送浊,其實就是將不同樣式的四格拼版游戲區(qū)域中的不同位置分解成 N 多張靜態(tài)的圖片梦谜。

3、項目步驟

  1. 構建 Python 開發(fā)環(huán)境袭景。
  2. 在窗體內構建四格拼版游戲區(qū)域唁桩。
  3. 在游戲區(qū)域內活動小方格
  4. 在游戲區(qū)域內繪制不同樣式的四格拼板耸棒。
  5. 四格拼板的沖突和限制荒澡。

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()

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末髓棋,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子惶洲,更是在濱河造成了極大的恐慌按声,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,204評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件恬吕,死亡現(xiàn)場離奇詭異签则,居然都是意外死亡,警方通過查閱死者的電腦和手機铐料,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評論 3 395
  • 文/潘曉璐 我一進店門渐裂,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人钠惩,你說我怎么就攤上這事芯义。” “怎么了妻柒?”我有些...
    開封第一講書人閱讀 164,548評論 0 354
  • 文/不壞的土叔 我叫張陵扛拨,是天一觀的道長。 經(jīng)常有香客問我举塔,道長绑警,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,657評論 1 293
  • 正文 為了忘掉前任央渣,我火速辦了婚禮计盒,結果婚禮上,老公的妹妹穿的比我還像新娘芽丹。我一直安慰自己北启,他們只是感情好,可當我...
    茶點故事閱讀 67,689評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著咕村,像睡著了一般场钉。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上懈涛,一...
    開封第一講書人閱讀 51,554評論 1 305
  • 那天逛万,我揣著相機與錄音,去河邊找鬼批钠。 笑死宇植,一個胖子當著我的面吹牛,可吹牛的內容都是我干的埋心。 我是一名探鬼主播指郁,決...
    沈念sama閱讀 40,302評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼拷呆!你這毒婦竟也來了闲坎?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,216評論 0 276
  • 序言:老撾萬榮一對情侶失蹤洋腮,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后手形,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體啥供,經(jīng)...
    沈念sama閱讀 45,661評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,851評論 3 336
  • 正文 我和宋清朗相戀三年库糠,在試婚紗的時候發(fā)現(xiàn)自己被綠了伙狐。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,977評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡瞬欧,死狀恐怖贷屎,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情艘虎,我是刑警寧澤唉侄,帶...
    沈念sama閱讀 35,697評論 5 347
  • 正文 年R本政府宣布,位于F島的核電站野建,受9級特大地震影響属划,放射性物質發(fā)生泄漏。R本人自食惡果不足惜候生,卻給世界環(huán)境...
    茶點故事閱讀 41,306評論 3 330
  • 文/蒙蒙 一同眯、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧唯鸭,春花似錦须蜗、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽菱农。三九已至,卻和暖如春晤愧,著一層夾襖步出監(jiān)牢的瞬間大莫,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評論 1 270
  • 我被黑心中介騙來泰國打工官份, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留只厘,地道東北人。 一個月前我還...
    沈念sama閱讀 48,138評論 3 370
  • 正文 我出身青樓舅巷,卻偏偏與公主長得像羔味,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子钠右,可洞房花燭夜當晚...
    茶點故事閱讀 44,927評論 2 355

推薦閱讀更多精彩內容