python遊戲開發之俄羅斯方塊(一):簡版

編程語言:python(3.6.4)python

主要應用的模塊:pygame編程

(下面有源碼,可是拒絕分享完整的源碼,下面的代碼整合起來就是完整的源碼)數組

首先列出個人核心思路:app

1,圖像由「核心變量」徹底控制,圖像變化的本質是 變量的改變

2,自上而下式的思考,圖像變化的問題將一步步轉爲 一系列具體的變量修改

3,「核心變量」在思考過程當中並不是不可變動,爲了寫函數方便,能夠適當讓步

正文開始:dom

核心變量到圖像

首先當作品圖預覽圖編程語言

從上圖和遊戲玩法能夠得出如下兩點:函數

1,方塊位置十分有規律學習

2,兩類方塊(上面移動的,下方固定的 都比較有特色)3d

方塊的大小都是固定的,只須要操心位置的問題,下面建座標系code

下一步,座標的儲存方式

###歡迎加羣:725479218,完整源碼,以及pygame的學習方法,都有

記錄方式有兩種:

 1,橫縱座標作一個二元元組,再用一個列表裝着一堆二元元組

      例如:[(20,1),(20,2),(20,3),(20,4)]表明第20行的1~4列的四個方塊

  2,二維數組,一行是一個列表,用兩個索引表明橫縱座標,值爲1就表明有方塊,0就是沒有方塊

例如:block[20][1] 值爲1就表示20行第1列有方塊,block[20][5] 爲0表示20行第5列有沒有方塊

講道理,兩種記錄方式沒什麼大區別,並且第一種彷佛更好用

但後面會有這樣的問題

怎麼判斷一行是否被填滿,填滿後怎麼消除,消除後怎麼使上方的方塊下落。

兩種記錄方式對應的解法:

    1,假如判斷第2行 只要依次判斷(2, 0), (2, 1)···· (2, 8), (2, 9) 是否都存在於列表就能夠,消除、下落就有點麻煩,以第2行爲例 遍歷列表 2行如下的不修改,2行的所有清除,2行以上的 行數-1

    2,被填滿 等價於 全是1 等價於 沒有0 ,一個not in 就能夠啦,pop就能夠清除一行,並且後面列表的索引會向前補(實現下落),而後在最後補充一個空列表就完事啦(防止被刪光)

因此

充當背景的方塊 就使用2號記錄方式

下一步 對接pygame繪製函數

核心變量的聲明

background = [[0 for i in range(10)]for j in range(21)]
active = []

繪製函數

# 初版
def new_draw():
    screen.fill(white)

    for i in range(1, 21):
        for j in range(10):
            bolck = background[i][j]
            if bolck:
                pygame.draw.rect(screen, blue, (j * 25 + 1, 500 - i * 25 + 1, 23, 23))

    for i, j in active:
        pygame.draw.rect(screen, blue, (j * 25+1, 500 - i * 25 + 1, 23, 23))

    pygame.display.update()

補充:座標轉換

鍵盤到圖像(本質:鍵盤到核心變量)

下面簡略列出須要的函數

首先,方塊移動的難點在「旋轉」上

Q:爲何不先考慮左右移動 A:旋轉的問題的有些複雜,須要變動「核心變量」 核心變量一但變動 其它相關函數都得改寫 因此爲了省心,優先考慮可能涉及「核心變量」的事情

解決思路:

  1,爲每一個形狀創建一個「狀態庫」,手寫出每一個姿態,旋轉時再讀取

  2,旋轉先後存在明確的數學關係

選那個沒有懸念

追加一個變量,記錄旋轉中心座標

旋轉時依照方程轉換座標

公式很簡單吧

若是旋轉在原點,將會更簡單

PS:注意座標系,公式不能直接抄

因此,從記錄「絕對座標」變動爲「中心座標+相對座標」

PS:繪製函數須要作相應的調整

旋轉過程 ( x , y ) --> (-y , x)

重要的細節:移動是有限制的

方塊在邊界處,就得限制向外的移動,若是移動後與已有的方塊重疊,也得限制移動

####代碼時間 左右移動

def move_LR(n):
    """n=-1表明向左,n=1表明向右"""
    x, y = centre
    y += n
    for i, j in active:
        i += x
        j += y
        if j < 0 or j > 9 or background[i][j]:
            break
    else:
        centre.clear()
        centre.extend([x, y])

PS:centre是列表

Q:clear + extend 是什麼騷操做?不能夠直接賦值嗎? A:函數內部能夠讀取 但不能修改全局變量 可是能夠調用全局變量的方法 因此clear+extend修改centra 這樣就不用將centra傳入傳出啦 (危險操做,謹慎使用)

旋轉的

def rotate():
    x, y = centre
    l = [(-j, i) for i, j in active]
    for i, j in l:
        i += x
        j += y
        if j < 0 or j > 9 or background[i][j]:
            break
    else:
        active.clear()
        active.extend(l)

PS:由於旋轉的機制很簡陋,會有田字形方塊的也能旋轉的奇怪現象發生。

講道理下落並不難,關鍵是下落結束後會有不少後事要處理

  1,檢查是否落到底部,是:繼續,否:跳出

  2,active的信息轉到background,

  3,檢查background是否有「行」被填滿 是:繼續,否:跳至5

  4,清掉滿行,補上空行,計分

  5,生成新的active,檢查其位置是否被佔(被佔<=>方塊被堆至頂部<=>game over)

那就開始擼代碼

def move_down():
    x, y = centre
    x -= 1
    for i, j in active:
        i += x
        j += y
        if background[i][j]:
            break
    else:
        centre.clear()
        centre.extend([x, y])
        return
    # 若是新位置未被佔用 經過return結束
    # 若是新位置被佔用則繼續向下執行
    x, y = centre
    for i, j in active:
        background[x + i][y + j] = 1

    l = []
    for i in range(1, 20):
        if 0 not in background[i]:
            l.append(i)
    # l裝 行號,鑑於刪去後,部分索引變化,對其降序排列,倒着刪除
    l.sort(reverse=True)

    for i in l:
        background.pop(i)
        background.append([0 for j in range(10)])
        # 隨刪隨補

    score[0] += len(l)
    pygame.display.set_caption("分數:%d" % (score[0]))

    active.clear()
    active.extend(list(random.choice(all_block)))
    # all_block保存7種形狀的信息,手打出來的
    centre.clear()
    centre.extend([20, 4])

    x, y = centre
    for i, j in active:
        i += x
        j += y
        if background[i][j]:
            break
    else:
        return
    alive.append(1)

控制結構 下一步組裝

由於核心變量發生變化,new_draw重寫

def new_draw():
    screen.fill(white)

    for i in range(1, 21):
        for j in range(10):
            bolck = background[i][j]
            if bolck:
                pygame.draw.rect(screen, blue, (j * 25 + 1, 500 - i * 25 + 1, 23, 23))

    x, y = centre
    for i, j in active:
        i += x
        j += y
        pygame.draw.rect(screen, blue, (j * 25 + 1, 500 - i * 25 + 1, 23, 23))

    pygame.display.update()

核心變量定義

all_block = (((0, 0), (0, -1), (0, 1), (0, 2)),
             ((0, 0), (0, 1), (-1, 0), (-1, 1)),
             ((0, 0), (0, -1), (-1, 0), (-1, 1)),
             ((0, 0), (0, 1), (-1, -1), (-1, 0)),
             ((0, 0), (0, 1), (1, 0), (0, -1)),
             ((0, 0), (1, 0), (-1, 0), (1, -1)),
             ((0, 0), (1, 0), (-1, 0), (1, 1)))
background = [[0 for i in range(10)] for j in range(24)]
background[0] = [1 for i in range(10)]
active = list(random.choice(all_block))
centre = [20, 4]
score = [0]
for i in range(1, 20):
        if 0 not in background[i]:
            l.append(i)

這個部分是從第1行纔開始檢查的(~ ̄▽ ̄)~

3,我懶,不想傳參,因此 老套路

pygame固定結構,控制結構,控制變量,龍套變量

pygame.init()
screen = pygame.display.set_mode((250, 500))
pygame.display.set_caption("俄羅斯方塊")
fclock = pygame.time.Clock()

black = 0, 0, 0
white = 255, 255, 255
blue = 0, 0, 255

times = 0
alive = []
press = False
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:
                move_LR(-1)
            elif event.key == pygame.K_RIGHT:
                move_LR(1)
            elif event.key == pygame.K_UP:
                rotate()
            elif event.key == pygame.K_DOWN:
                press = True
        elif event.type == pygame.KEYUP:
            if event.key == pygame.K_DOWN:
                press = False
    if press:
        times += 10

    if times >= 50:
        move_down()
        times = 0
    else:
        times += 1

    if alive:
        pygame.display.set_caption("over分數:%d" % (score[0]))
        time.sleep(3)
        break
    new_draw()
    fclock.tick(100)

說明:

1,原來按一次「下」,方塊只會移動一格。。。。

因此修正了一下,支持 長按,爲此加了一個變量press

2,times用於計時

3,遊戲結束的有點突兀,直接就brake啦

最後發現漏了一行沒拷上來

源碼分享,加羣獲取:725479218 羣裏面能夠獲取學習pygame的學習方法 歡迎加入

相關文章
相關標籤/搜索