欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Pygame用200行代碼實(shí)現(xiàn)俄羅斯方塊

 更新時間:2023年12月15日 09:10:18   作者:微小冷  
俄羅斯方塊的邏輯很簡單,就是幾個方塊組合在一起,然后下落,當(dāng)其碰到四周的墻壁后便無法移動,若某行被方塊所填滿,那么就刪除這一行,然后此行上面的所有方塊下降一行,本文給大家介紹了用Pygame實(shí)現(xiàn)俄羅斯方塊,文中代碼示例介紹的非常詳細(xì),需要的朋友可以參考下

邏輯設(shè)計

俄羅斯方塊的邏輯很簡單,就是幾個方塊組合在一起,然后下落,當(dāng)其碰到四周的墻壁后便無法移動。若某行被方塊所填滿,那么就刪除這一行,然后此行上面的所有方塊下降一行。

為了將這個邏輯代碼化,可以用布爾矩陣來表示具體的方塊類型,比如長條形方塊可用如下矩陣表示。

BLOCK_I = [[0,1,0,0],
           [0,1,0,0],
           [0,1,0,0],
           [0,1,0,0]]

在實(shí)際操作時,會經(jīng)常遇到旋轉(zhuǎn)操作,其基本邏輯是,將第i ii行變成第− i -i−i列,從而旋轉(zhuǎn)邏輯如下

def rotateBlock(block):
    newBlock = [[[] for _ in block] for b in block[0]]
    for i,row in enumerate(block, 1):
        for j,r in enumerate(row, 0):
            newBlock[j][-i] = r
    return newBlock

定義好所有的方塊,并將其封入列表BLOCK中,

BLOCK_S = [[0,1,1],
           [1,1,0],
           [0,0,0]]

BLOCK_Z = [[1,1,0],
     [0,1,1],
     [0,0,0]]

# I型方塊
BLOCK_I = [[0,1,0,0],
     [0,1,0,0],
     [0,1,0,0],
     [0,1,0,0]],

# O型方塊
BLOCK_O = [[1,1],
            [1,1]]
# J型方塊
BLOCK_J = [[1,0,0],
     [1,1,1],
     [0,0,0]]

# L型方塊
BLOCK_L = [[0,0,1],
     [1,1,1],
     [0,0,0]]

# T型方塊
BLOCK_T = [[0,1,0],
     [1,1,1],
     [0,0,0]]

BLOCKS = [BLOCK_S, BLOCK_I, BLOCK_J, BLOCK_L, BLOCK_O, BLOCK_T, BLOCK_Z]

有了這個,就可以隨機(jī)生成其中某個方塊了,這個過程需要引入一點(diǎn)隨機(jī)性

import random
# 創(chuàng)建一個圖形
def newBlock():
    block = random.choice(BLOCKS)
    for _ in range(random.randint(0,4)):
        block = rotateBlock(block)
    return block

挪動邏輯

原理十分簡單,但想要寫出一個可以玩的游戲,卻還需要注意一些細(xì)節(jié)問題。比如俄羅斯方塊在碰到墻壁時的行為;旋轉(zhuǎn)方塊的方法。在實(shí)現(xiàn)這些具體問題之前,先設(shè)置幾個常量

SCREEN_WIDTH, SCREEN_HEIGHT = 450, 750
BLOCK_COL_NUM = 10  # 每行的方格數(shù)
BLOCK_ROW_NUM = 25  # 每列的方個數(shù)
SIZE = 30  # 每個小方格大小
BG_COLOR = (40, 40, 60)  # 背景色
RED = (200, 30, 30)  # 紅色,GAME OVER 的字體顏色
WHITE = (255,255,255)   # 白色
BLACK = (0,0,0)         # 黑色
GREEN = (60, 128, 80)   # 綠色
STOP_LST = [[0 for _ in range(BLOCK_COL_NUM)]
               for _ in range(BLOCK_ROW_NUM)]


接下來逐個實(shí)現(xiàn)俄羅斯方塊的細(xì)節(jié),當(dāng)左右移動方塊時,若方塊碰到墻壁,則需要一個判定函數(shù),代碼如下。其中isR為True時表示向右移動,否則向左移動。其判斷邏輯非常直觀,只需查看是否超出邊界。

# 判斷是否可以向左右移動
# isR為True,判斷能否向右移動;isR為False,判斷能否向左移動
def judgeMoveLR(block, stCol, isR):
    nCol = len(block[0])
    cols = range(nCol-1, -1, -1) if isR else range(nCol)
    for col in cols:
        lstCol = [line[col] for line in block]
        if 1 not in lstCol:
            continue
        if not 0 <= stCol + col < BLOCK_COL_NUM:
            return False
    return True

如果判定成功,則需要移動方塊,那么根據(jù)其輸入左移或者右移,可以構(gòu)造一個函數(shù)

# 相左或者向右移動
def moveLR(block, stCol, key):
    isR = key == pygame.K_RIGHT
    stCol = stCol + 1 if isR else stCol - 1
    if judgeMoveLR(block ,stCol, isR):
        return 1 if isR else -1
    return 0

方塊在下落過程中若碰壁,則稍微有些麻煩,因?yàn)橄路娇赡芤呀?jīng)堆積了一些方塊,為此不僅需要知道當(dāng)前下落方塊的信息,還要知道已經(jīng)堆積的方塊的信息。

# 判斷是否可以繼續(xù)下落
def judgeMoveDown(block, stRow, stCol, stopLst):
    # 堆積方塊的位置
    stopPosition = list()
    for row, line in enumerate(stopLst):
        for col, b in enumerate(line):
            if b: stopPosition.append((row, col))
    # 判斷碰撞
    for row, line in enumerate(block):
        if 1 in line and stRow + row >= BLOCK_ROW_NUM:
            return False
        for col, b in enumerate(line):
            if b and (stRow + row, stCol + col) in stopPosition:
                return False
    return True

最后將三者合在一起,用于判斷方塊是否可以繼續(xù)移動

def canMove(block, stRow, stCol, stopLst):
    flag = judgeMoveLR(block, stCol, False)
    flag &= judgeMoveLR(block, stCol, True)
    flag &= judgeMoveDown(block, stRow, stCol, stopLst)
    return flag

消除和堆積

其消除邏輯是,當(dāng)某行全為1的時候,就把這行刪掉,然后在頂端補(bǔ)充全0的列表。

def judgeLines(stopLst):
    # 記錄剛剛消除的行數(shù)
    i, N, count = 0, len(stopLst), 0
    for i in range(N):
        if 0 not in stopLst[i]:
            line = [0]*len(stopLst.pop(i))
            stopLst.insert(0, line)
            count += 10
    return count

堆積邏輯則相對簡單,只需將堆積部位置為1即可。

# 將停止移動的block添加到堆積方塊
def addToStopLst(stopLst, block, stRow, stCol):
    for row, line in enumerate(block):
        for col, b in enumerate(line):
            if b: stopLst[stRow + row][stCol + col] = 1

至此,俄羅斯方塊的操作邏輯便設(shè)計完成,接下來是繪圖。

參數(shù)邏輯

俄羅斯方塊的下落速度可以區(qū)分不同關(guān)卡,下面是一種用分?jǐn)?shù)決定下落速度的方案,其速度值表示方塊下落的延時時間。

def changeSpeed(score):
    scores = [20, 50, 100, 200]
    infos = "12345"
    speeds = [0.5, 0.4, 0.3, 0.2, 0.1]
    ind = bisect(scores, score)
    return infos[ind], speeds[ind]

繪圖邏輯

首先是背景繪制,主要包括背景顏色和網(wǎng)格的繪制。

def drawBackground(screen):
    screen.fill(BG_COLOR)
    width = SIZE * BLOCK_COL_NUM
    pygame.draw.line(screen, BLACK, (width, 0), (width, SCREEN_HEIGHT), 4)
    for x in range(BLOCK_COL_NUM):
        pygame.draw.line(screen, BLACK, (x * SIZE, 0), (x * SIZE, SCREEN_HEIGHT), 1)
    for y in range(BLOCK_ROW_NUM):
        pygame.draw.line(screen, BLACK, (0, y * SIZE), (width, y * SIZE), 1)

這里僅采使用了左側(cè)窗口,其右側(cè)將用于存放提示信息,主要包括得分、速度等級以及接下來落下的方塊。

def drawRight(screen, score, speedInfo):
    fontPath = r'C:\Windows\Fonts\msyh.ttc'
    font = pygame.font.Font(fontPath, 24)  # 黑體24

    posDct = {
        '得分: ':10, str(score): 50,
        '速度: ':100, speedInfo: 150,
        '下一個:':200
    }
    for k,v in posDct.items():
        msg = font.render(k, True, WHITE)
        screen.blit(msg, (BLOCK_COL_NUM * SIZE + 10, v))

然后是方塊繪制函數(shù),顧名思義,drawBlock繪制一個方塊,drawBlocks繪制一組方塊。

def drawBlock(screen, row, col, stRow, stCol):
    stRow += row * SIZE
    stCol += SIZE * col
    rect = pygame.Rect(stCol, stRow, SIZE, SIZE)
    pygame.draw.rect(screen, GREEN, rect, 0)
    pygame.draw.rect(screen, BLACK, rect, 1)

def drawBlocks(screen, block, stRow, stCol):
    for row, line in enumerate(block):
        for col, b in enumerate(line):
            if not b: continue
            drawBlock(screen, row, col, stRow, stCol)

最后,若游戲失敗,則彈出失敗信息

def drawGamerOver(screen):
    fontPath = r'C:\Windows\Fonts\msyh.ttc'
    font = pygame.font.Font(fontPath, 72)

    w, h = font.size('GAME OVER')
    msg = font.render('GAME OVER', True, RED)
    screen.blit(msg, ((SCREEN_WIDTH - w) // 2, (SCREEN_HEIGHT - h) // 2))

    # 顯示"鼠標(biāo)點(diǎn)擊任意位置,再來一局"
    font = pygame.font.Font(fontPath, 24)
    w, h = font.size('點(diǎn)擊任意位置,再來一局')
    msg = font.render('點(diǎn)擊任意位置,再來一局', True, RED)
    screen.blit(msg, ((SCREEN_WIDTH - w) // 2, (SCREEN_HEIGHT - h) // 2 + 80))

主程序

主程序內(nèi)容如下,其中initBlock用于初始化方塊。由于大家對俄羅斯方塊都很熟悉,且所有調(diào)用的子函數(shù)均已說明,所以就不再細(xì)說其流程了。

def initBlock(nextBlock=None):
    stRow, stCol = -2, 4
    nowBlock = nextBlock if nextBlock else newBlock()
    nextBlock = newBlock()
    return stRow, stCol, nowBlock, nextBlock

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

    # 初始化當(dāng)前圖形的位置,當(dāng)前圖形,以及下一個圖形
    stRow, stCol, nowBlock, nextBlock = initBlock()
    last_time = time.time()
    speed, speedInfo = 0.5, '1'
    score, gameOver = 0, False
    stopLst = deepcopy(STOP_LST)
    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 in [pygame.K_LEFT, pygame.K_RIGHT]:
                    stCol += moveLR(nowBlock, stCol, event.key)
                elif event.key == pygame.K_UP:
                    rotBlock = rotateBlock(nowBlock)
                    if canMove(rotBlock, stRow, stCol, stopLst):
                        nowBlock = rotBlock
                elif event.key == pygame.K_DOWN:
                    # 判斷是否可以向下移動,如果碰到底部或者其它的圖形就不能移動了
                    while judgeMoveDown(nowBlock, stRow + 1, stCol, stopLst):
                        stRow += 1
            if gameOver:
                stRow, stCol, nowBlock, nextBlock = initBlock()
                stopLst = deepcopy(STOP_LST)
                score = 0
                gameOver = False

        # 判斷是否修改當(dāng)前圖形顯示的起始行
        if not gameOver and time.time() - last_time > speed:
            last_time = time.time()
            # 可以向下移動的情形
            if judgeMoveDown(nowBlock, stRow + 1, stCol, stopLst):
                stRow += 1
            else:
                # 不可向下移動,則需新建一個block然后下落
                addToStopLst(stopLst, nowBlock, stRow, stCol)
                score += judgeLines(stopLst)
                gameOver =  1 in stopLst[0]             # 第一行中間有1則游戲結(jié)束
                speedInfo, speed = changeSpeed(score)   # 調(diào)整速度
                stRow, stCol, nowBlock, nextBlock = initBlock(nextBlock)

        drawBackground(screen)
        drawRight(screen, score, speedInfo)
        drawBlocks(screen, nowBlock, stRow*SIZE, stCol*SIZE)    # 當(dāng)前方塊
        drawBlocks(screen, stopLst, 0, 0)                       # 堆積方塊
        drawBlocks(screen, nextBlock, 300, 320)                 # 下一個方塊

        # 顯示游戲結(jié)束畫面
        if gameOver:
            drawGamerOver(screen)

        pygame.display.update()
        clock.tick(60)  # 通過一定的延時,實(shí)現(xiàn)1秒鐘能夠循環(huán)60次

最終游戲效果如下

以上就是Pygame用200行代碼實(shí)現(xiàn)俄羅斯方塊的詳細(xì)內(nèi)容,更多關(guān)于Pygame俄羅斯方塊的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • python將時分秒轉(zhuǎn)換成秒的實(shí)例

    python將時分秒轉(zhuǎn)換成秒的實(shí)例

    今天小編就為大家分享一篇python將時分秒轉(zhuǎn)換成秒的實(shí)例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-12-12
  • Scrapy基于scrapy_redis實(shí)現(xiàn)分布式爬蟲部署的示例

    Scrapy基于scrapy_redis實(shí)現(xiàn)分布式爬蟲部署的示例

    這篇文章主要介紹了Scrapy基于scrapy_redis實(shí)現(xiàn)分布式爬蟲部署的示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-09-09
  • 用Python制作一個可以聊天的皮卡丘版桌面寵物

    用Python制作一個可以聊天的皮卡丘版桌面寵物

    這篇文章主要為大家介紹如何利用Python制作一個可愛的皮卡丘桌面掛件寵物,文中的示例代碼講解詳細(xì),感興趣的可以了解一下
    2022-03-03
  • 在tensorflow中設(shè)置保存checkpoint的最大數(shù)量實(shí)例

    在tensorflow中設(shè)置保存checkpoint的最大數(shù)量實(shí)例

    今天小編就為大家分享一篇在tensorflow中設(shè)置保存checkpoint的最大數(shù)量實(shí)例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-01-01
  • python 如何實(shí)現(xiàn)遺傳算法

    python 如何實(shí)現(xiàn)遺傳算法

    這篇文章主要介紹了python 如何實(shí)現(xiàn)遺傳算法,幫助大家更好的利用python進(jìn)行數(shù)據(jù)分析、處理,感興趣的朋友可以了解下
    2020-09-09
  • 詳解Django模版中加載靜態(tài)文件配置方法

    詳解Django模版中加載靜態(tài)文件配置方法

    這篇文章主要介紹了Django模版中加載靜態(tài)文件配置方法,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友可以參考下
    2019-07-07
  • Python計算素數(shù)個數(shù)的兩種方法

    Python計算素數(shù)個數(shù)的兩種方法

    本文主要介紹了Python計算素數(shù)個數(shù)的兩種方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-05-05
  • Python pandas 重命名索引和列名稱的實(shí)現(xiàn)

    Python pandas 重命名索引和列名稱的實(shí)現(xiàn)

    本文主要介紹了Python pandas 重命名索引和列名稱的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-07-07
  • 使用OpenCV實(shí)現(xiàn)圖像的透視變換功能

    使用OpenCV實(shí)現(xiàn)圖像的透視變換功能

    在計算機(jī)視覺領(lǐng)域,經(jīng)常需要對圖像進(jìn)行各種幾何變換,如旋轉(zhuǎn)、縮放和平移等,本文主要介紹了如何使用OpenCV實(shí)現(xiàn)圖像的透視變換,需要的可以參考下
    2024-11-11
  • Python實(shí)現(xiàn)對照片中的人臉進(jìn)行顏值預(yù)測

    Python實(shí)現(xiàn)對照片中的人臉進(jìn)行顏值預(yù)測

    今天給大家?guī)淼氖顷P(guān)于Python實(shí)戰(zhàn)的相關(guān)知識,文章圍繞如何用Python實(shí)現(xiàn)對照片中的人臉進(jìn)行顏值預(yù)測展開,文中有非常詳細(xì)的介紹及代碼示例,需要的朋友可以參考下
    2021-06-06

最新評論