pygame實(shí)現(xiàn)俄羅斯方塊游戲
更新時(shí)間:2018年06月26日 09:24:33 作者:我是蒟蒻
這篇文章主要為大家詳細(xì)介紹了pygame實(shí)現(xiàn)俄羅斯方塊游戲,代碼注釋詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
本文實(shí)例為大家分享了pygame實(shí)現(xiàn)俄羅斯方塊的具體代碼,供大家參考,具體內(nèi)容如下
import random, time, pygame, sys
from pygame.locals import *
FPS = 25
WINDOWWIDTH = 640#整個(gè)游戲屏幕的寬
WINDOWHEIGHT = 480#整個(gè)游戲屏幕的高
BOXSIZE = 20#每個(gè)小格子的寬和高
BOARDWIDTH = 10#游戲窗口本身有10個(gè)方塊的寬度
BOARDHEIGHT = 20#游戲窗口本身有20個(gè)方塊的高度
BLANK = '.'#表示空白空格
#每當(dāng)玩家按下向左或向右箭頭鍵的時(shí)候,下落的磚塊都應(yīng)該分別向左或向右移動(dòng)一個(gè)方塊。然而,玩家也可以保持按住了向左箭頭鍵或向右箭頭鍵以使得下落的磚塊持續(xù)移動(dòng)。
MOVESIDEWAYSFREQ = 0.15 #按向左箭頭鍵或向右箭頭鍵每次持續(xù)按下超過0.15秒的時(shí)候,磚塊相應(yīng)的移動(dòng)一個(gè)空格
MOVEDOWNFREQ = 0.1 #按向下頭鍵每次持續(xù)按下超過0.1秒的時(shí)候,磚塊向下一個(gè)空格
XMARGIN = int((WINDOWWIDTH - BOARDWIDTH * BOXSIZE) / 2)#(0INDOWWIDTH是總窗口的寬度-游戲界面一行上的方塊個(gè)數(shù)*每個(gè)方塊的寬度)/2窗口左邊或右邊剩下的像素?cái)?shù)
TOPMARGIN = WINDOWHEIGHT - (BOARDHEIGHT * BOXSIZE) - 5#TOPMARGIN:游戲窗口上面剩下的像素?cái)?shù)=總窗口的高度-(游戲界面一列上的方塊個(gè)數(shù)*每個(gè)方塊的高度)-5
# R G B
WHITE = (255, 255, 255)#白色
GRAY = (185, 185, 185)#灰色
BLACK = ( 0, 0, 0)#黑色
RED = (155, 0, 0)#紅色
GREEN = ( 0, 155, 0)#綠色
BLUE = ( 0, 0, 155)#藍(lán)色
YELLOW = (155, 155, 0)#黃色
BORDERCOLOR = BLUE#邊界顏色
BGCOLOR = BLACK#背景顏色
TEXTCOLOR = WHITE#文字顏色
COLORS = (BLUE,GREEN,RED,YELLOW) #方塊四種顏色,存于COLORS元組中
TEMPLATEWIDTH = 5#磚塊模板寬
TEMPLATEHEIGHT = 5#磚塊模板高
S_SHAPE_TEMPLATE = [['.....', #S形狀的模板
'.....',
'..OO.',
'.OO..',
'.....'],
['.....', #S逆時(shí)針變化的形狀
'..O..',
'..OO.',
'...O.',
'.....']]
Z_SHAPE_TEMPLATE = [['.....', #Z形模板
'.....',
'.OO..',
'..OO.',
'.....'],
['.....',
'..O..',
'.OO..',
'.O...',
'.....']]
I_SHAPE_TEMPLATE = [['..O..', #I型模板
'..O..',
'..O..',
'..O..',
'.....'],
['.....',
'.....',
'OOOO.',
'.....',
'.....']]
O_SHAPE_TEMPLATE = [['.....', #O型模板
'.....',
'.OO..',
'.OO..',
'.....']]
J_SHAPE_TEMPLATE = [['.....', #J型模板
'.O...',
'.OOO.',
'.....',
'.....'],
['.....',
'..OO.',
'..O..',
'..O..',
'.....'],
['.....',
'.....',
'.OOO.',
'...O.',
'.....'],
['.....',
'..O..',
'..O..',
'.OO..',
'.....']]
L_SHAPE_TEMPLATE = [['.....', #L型模板
'...O.',
'.OOO.',
'.....',
'.....'],
['.....',
'..O..',
'..O..',
'..OO.',
'.....'],
['.....',
'.....',
'.OOO.',
'.O...',
'.....'],
['.....',
'.OO..',
'..O..',
'..O..',
'.....']]
T_SHAPE_TEMPLATE = [['.....', #T型模板
'..O..',
'.OOO.',
'.....',
'.....'],
['.....',
'..O..',
'..OO.',
'..O..',
'.....'],
['.....',
'.....',
'.OOO.',
'..O..',
'.....'],
['.....',
'..O..',
'.OO..',
'..O..',
'.....']]
PIECES = {'S': S_SHAPE_TEMPLATE, #PIECES是一個(gè)字典,它儲(chǔ)存了所有不同的模板(列表)。每個(gè)模板都擁有一個(gè)形狀所有可能的旋轉(zhuǎn)(列表)。
'Z': Z_SHAPE_TEMPLATE,
'J': J_SHAPE_TEMPLATE,
'L': L_SHAPE_TEMPLATE,
'I': I_SHAPE_TEMPLATE,
'O': O_SHAPE_TEMPLATE,
'T': T_SHAPE_TEMPLATE}
def main(): #main()函數(shù)還負(fù)責(zé)創(chuàng)建了一些其他的全局常量,并且顯示了在游戲運(yùn)行的時(shí)候出現(xiàn)的初始屏幕。
global FPSCLOCK, DISPLAYSURF, BASICFONT, BIGFONT
pygame.init()#在inport pygame之后 調(diào)用其他函數(shù)之前總要調(diào)用這個(gè)函數(shù)
FPSCLOCK = pygame.time.Clock()#pygame.time.Clock()創(chuàng)建pygame.time.Clock對(duì)象
DISPLAYSURF = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT)) #pygame.display.set_mode()的參數(shù)是一個(gè)元組,該元祖中有兩個(gè)參數(shù),
#即:創(chuàng)建窗口的寬和高,單位是像素,該函數(shù)返回pygame.Surface對(duì)象
BASICFONT = pygame.font.Font('freesansbold.ttf', 18)#字體
BIGFONT = pygame.font.Font('freesansbold.ttf', 100)#字體
pygame.display.set_caption('Tetromino')#設(shè)置窗口標(biāo)題
showTextScreen('Tetromino')#設(shè)置在開始界面顯示的文字
while True: #游戲循環(huán),該游戲循壞會(huì)在一秒之內(nèi)多次檢查是否發(fā)生了任何新的事件,例如:點(diǎn)擊鼠標(biāo)或按下鍵盤
pygame.mixer.music.load('tetrisc.mp3')#加載音樂
pygame.mixer.music.play(-1, 0.0)#播放音樂
runGame()#調(diào)用runGame()開始游戲,當(dāng)游戲失敗的時(shí)候,runGame()將返回main(),
pygame.mixer.music.stop()#然后main()會(huì)停止背景音樂
showTextScreen('Game Over')#并顯示游戲結(jié)束屏幕。當(dāng)玩家按下一個(gè)鍵,showTextScreen()函數(shù)將返回,程序回到main()中的的第一行,重新開始游戲
def runGame():#實(shí)際的游戲代碼都在runGame中
#在游戲開始并且磚塊開始下落前,我們需要將一些變量初始化為游戲開始時(shí)候的值。
board = getBlankBoard()#創(chuàng)建一個(gè)空白游戲板數(shù)據(jù)結(jié)構(gòu)
lastMoveDownTime = time.time()#lastMoveDownTime最后按向下方向鍵的時(shí)間
lastMoveSidewaysTime = time.time()#lastMoveSidewaysTime最后按左右向鍵的時(shí)間
lastFallTime = time.time()#最后下落磚塊的時(shí)間
movingDown = False #沒有按下向下方向鍵
movingLeft = False #沒有按下向左方向鍵
movingRight = False #沒有按下向右方向鍵
score = 0 #得分
level, fallFreq = calculateLevelAndFallFreq(score)#計(jì)算關(guān)卡數(shù)和下落頻率,因?yàn)榇藭r(shí)score=0,所以經(jīng)計(jì)算后level=1,fallFreq=0.25
fallingPiece = getNewPiece() #fallingPiece變量將設(shè)置為能夠被玩家操作的當(dāng)前下落的磚塊
nextPiece = getNewPiece() #nextPice為在屏幕的Next部分出現(xiàn)的磚塊,即下一個(gè)將要下落的磚塊
while True: # 游戲主循環(huán),它負(fù)責(zé)磚塊在落向底部的過程中,游戲主要部分的代碼
if fallingPiece == None:#在下落的磚塊已經(jīng)著陸之后,fallingPiece變量設(shè)置為None
fallingPiece = nextPiece#這意味著nextPiece中的磚塊將會(huì)復(fù)制到fallingPiece中。
nextPiece = getNewPiece()#生成新的新的nextPiece磚塊,磚塊可以通過getNewPiece()函數(shù)生成。
lastFallTime = time.time() #該變量也重新設(shè)置為當(dāng)前時(shí)間,以便磚塊能夠在fallFreq中所設(shè)置的那么多秒之內(nèi)下落。
if not isValidPosition(board, fallingPiece):
#但是,如果游戲板已經(jīng)填滿了,isValidPosition()將返回False,導(dǎo)致這是一個(gè)無效的位置,那么,我們知道游戲板已經(jīng)填滿了,玩家失敗了。
return #在這種情況下 runGame()函數(shù)將被返回。
for event in pygame.event.get(): #事件處理循環(huán)負(fù)責(zé)玩家旋轉(zhuǎn)下落的磚塊,移動(dòng)下落的磚塊。
#松開一個(gè)剪頭鍵將會(huì)把movingLeft或movingRight或movingDown變量設(shè)置為False,表示玩家不再想
#要讓磚塊朝著該方向移動(dòng)。隨后的代碼將會(huì)根據(jù)這些“moving”變量中的Boolean值來確定做什么。
if event.type == KEYUP:#當(dāng)按鍵彈起的時(shí)候響應(yīng)KEYUP事件
if (event.key == K_LEFT):#判斷當(dāng)前彈起的按鍵是否為左方向鍵
movingLeft = False #是的話置為False,表示玩家不再想要讓磚塊朝著該方向移動(dòng)。
elif (event.key == K_RIGHT):#同上
movingRight = False
elif (event.key == K_DOWN):#同上
movingDown = False
elif event.type == KEYDOWN:#當(dāng)按鍵按下的時(shí)候響應(yīng)KEYDOWN事件
if (event.key == K_LEFT) and isValidPosition(board, fallingPiece, adjX=-1):
#當(dāng)按下的按鍵為向左方向鍵,并且向左移動(dòng)一個(gè)位置有效
fallingPiece['x'] = fallingPiece['x'] -1 #左移
movingLeft = True #將movingLeft變量設(shè)置為True,并且為了確保落下的磚塊不會(huì)既向左又向右移動(dòng)
movingRight = False #將 movingRight設(shè)置為False
lastMoveSidewaysTime = time.time() #lastMoveSidewaysTime更改為當(dāng)前時(shí)間
#設(shè)置了 movingLeft,movingRigh以便玩家能夠只是按住方向鍵以保持磚塊移動(dòng)。如果movingLeft變量設(shè)置為True,程序就知道已經(jīng)按下了向左箭頭鍵并且沒有松開它。
elif (event.key == K_RIGHT ) and isValidPosition(board, fallingPiece, adjX=1): #同上
fallingPiece['x'] =fallingPiece['x'] + 1
movingRight = True
movingLeft = False
lastMoveSidewaysTime = time.time()
#按向上箭頭將會(huì)把磚塊為其下一個(gè)旋轉(zhuǎn)狀態(tài)。代碼所需要做的只是fallingPiece字典中的'rotation'鍵的值增加1。然而,如果增加'rotation'鍵的值
#大于旋轉(zhuǎn)的總數(shù)目,那么用該形狀可能旋轉(zhuǎn)的總數(shù)目(這就是len(PIECES[fallingPiece['shape']的含義)來模除它,然后,這個(gè)值將回滾到從0開始。
elif event.key == K_UP :
fallingPiece['rotation'] = (fallingPiece['rotation'] + 1) % len(PIECES[fallingPiece['shape']])
if not isValidPosition(board, fallingPiece):
#由于新的旋轉(zhuǎn)位置與游戲板上已有的一些方塊重疊而導(dǎo)致新的旋轉(zhuǎn)位置無效,那么,
#我們想要通過從fallingPiece['rotation']減去1而切換回最初的旋轉(zhuǎn)。我們也可以使用len(PIECES[fallingPiece['shape']])來模除
#它,以便如果新的值為-1,模除將其改為列表中的最后一次旋轉(zhuǎn)。????
fallingPiece['rotation'] = (fallingPiece['rotation'] - 1) % len(PIECES[fallingPiece['shape']])
#如果按下了向下鍵,說明玩家想要磚塊下落得比正常速度更快一些。
elif (event.key == K_DOWN ):
movingDown = True # movingDown設(shè)置為True
if isValidPosition(board, fallingPiece, adjY=1):#下一個(gè)位置有效
fallingPiece['y'] = fallingPiece['y'] +1 #移動(dòng)
lastMoveDownTime = time.time() #lastMoveDownTime重新設(shè)置為當(dāng)前時(shí)間。隨后將檢查這些變量,以確保只要按下向下箭頭鍵的時(shí)候,磚塊就
#會(huì)以較快的速率下降
if (movingLeft or movingRight) and time.time() - lastMoveSidewaysTime > MOVESIDEWAYSFREQ:#MOVESIDEWAYSFREQ = 0.15 按向左或向右超過0.15秒
if movingLeft and isValidPosition(board, fallingPiece, adjX=-1):#如果是向左方向鍵,并且向左一個(gè)位置有效
fallingPiece['x'] =fallingPiece['x'] - 1#左移動(dòng)一個(gè)位置
elif movingRight and isValidPosition(board, fallingPiece, adjX=1):#如果是向右方向鍵,并且向左一個(gè)位置有效
fallingPiece['x'] =fallingPiece['x'] + 1#右移動(dòng)一個(gè)位置
lastMoveSidewaysTime = time.time() #將lastMoveSidewaysTime更新為當(dāng)前時(shí)間。
if movingDown and time.time() - lastMoveDownTime > MOVEDOWNFREQ and isValidPosition(board, fallingPiece, adjY=1):
#MOVEDOWNFREQ = 0.1 按向下方向鍵超過0.1秒,并且向下一個(gè)位置有效
fallingPiece['y'] = fallingPiece['y'] + 1#向下移動(dòng)一個(gè)位置
lastMoveDownTime = time.time()#將laslastMoveDownTime更新為當(dāng)前時(shí)間。
#讓磚塊自然落下
if time.time() - lastFallTime > fallFreq:#fallFreq向下移動(dòng)的速率
if not isValidPosition(board, fallingPiece, adjY=1):#當(dāng)磚塊下一個(gè)位置無效時(shí),即表示磚塊當(dāng)前已經(jīng)著陸了。
addToBoard(board, fallingPiece) #在游戲板數(shù)據(jù)結(jié)構(gòu)中記錄這個(gè)著陸的磚塊
score=score + removeCompleteLines(board)# removeCompleteLines()將負(fù)責(zé)刪除掉游戲板上任何已經(jīng)填充完整的行,并且將方塊向下推動(dòng)。
#removeCompleteLines()函數(shù)還會(huì)返回一個(gè)整數(shù)值,表明消除了多少行,以便我們將這個(gè)數(shù)字加到得分上。
level, fallFreq = calculateLevelAndFallFreq(score)#由于分?jǐn)?shù)已經(jīng)修改了,我們調(diào)用calculateLevelAndFallFreq()函數(shù)來更新當(dāng)前的關(guān)卡以及磚塊下落得頻率。
fallingPiece = None#最后我們將fallingPiece變量設(shè)置為None,以表示下一個(gè)磚塊應(yīng)該變?yōu)樾碌南侣浯u塊,并且應(yīng)該生成一個(gè)隨機(jī)的新磚塊作為下一個(gè)磚塊。??????
else:
# 如果磚塊沒有著陸,我們直接將其Y位置向下設(shè)置一個(gè)空格,并且將lastFallTime重置為當(dāng)前時(shí)間
fallingPiece['y'] = fallingPiece['y'] +1
lastFallTime = time.time()
# drawing everything on the screen
DISPLAYSURF.fill(BGCOLOR)
drawBoard(board)
drawStatus(score, level)
drawNextPiece(nextPiece)
if fallingPiece != None:#磚塊沒有下落到底部
drawPiece(fallingPiece)
pygame.display.update()
FPSCLOCK.tick(FPS)
def makeTextObjs(text, font, color):
surf = font.render(text, True, color)
return surf, surf.get_rect()
def checkForKeyPress():
# checkForKeyPress()函數(shù)和它在Wormy游戲中所做的事件相同。首先,它調(diào)用checkForQuit()來處理任何的QUIT事件(或者是專門針對(duì)Esc鍵的KEYUP事件),如果有任何這樣的事件
#就會(huì)終止程序。然后,它從事件隊(duì)列中提取出所有的KEYDOWN, KEYUP事件。它會(huì)忽略掉任何的KEYDOWN事件(針對(duì)pygame.event.get()指定了KEYDOWN,從而從事件隊(duì)列中清除掉該類事件)。
#如果事件隊(duì)列中沒有KEYUP事件,那么該函數(shù)返回None。
for event in pygame.event.get([KEYDOWN, KEYUP]):
if event.type == KEYDOWN:
continue
return event.key
return None
def calculateLevelAndFallFreq(score):#每次玩家填滿一行,起分?jǐn)?shù)都將增加1分。每增加10分,游戲就進(jìn)入下一個(gè)關(guān)卡,磚塊下落得會(huì)更快。關(guān)卡和下落的頻率都是通過傳遞
level = int(score / 10) + 1 #給該函數(shù)的分?jǐn)?shù)來計(jì)算的。要計(jì)算關(guān)卡,我們使用int()來舍入除以10以后的分?jǐn)?shù)。因此如果分?jǐn)?shù)是0-9之間的任何數(shù)字,int()調(diào)用會(huì)將其
fallFreq = 0.27 - (level * 0.02) #舍入到0。代碼這里的+1部分,是因?yàn)槲覀兿胍谝粋€(gè)關(guān)卡作為第一關(guān),而不是第0關(guān)。當(dāng)分?jǐn)?shù)達(dá)到10分的時(shí)候,int(10/10)將會(huì)計(jì)算為1
return level, fallFreq #并且+1將會(huì)使得關(guān)卡變?yōu)?
#為了計(jì)算下落的頻率,我們首先有一個(gè)基準(zhǔn)值0.27(這意味著每0.27秒,磚塊會(huì)自然地下落一次)。然后,我們將關(guān)卡值乘以0.02,并且從基準(zhǔn)時(shí)間0.27中減去它。因此,對(duì)于關(guān)卡1,
#我們從0.27中減去0.02*1得到0.25。在關(guān)卡2中我們減去0.02*2得到0.23。對(duì)于每一個(gè)關(guān)卡來說,磚塊下落的速度都比之前的關(guān)卡塊了0.02秒。
#getNewPiece()函數(shù)產(chǎn)生一個(gè)隨機(jī)的磚塊,放置于游戲板的頂部(設(shè)置'y'=-2)。
def getNewPiece():
shape = random.choice(list(PIECES.keys()))#PIECES是一個(gè)字典,它的鍵為代表形狀的字母,值為一個(gè)形狀所有可能的旋轉(zhuǎn)(列表的列表)。
#PIECES.keys()返回值是(['Z','J','L','I','O','T'])的元組,list(PIECES.keys())返回值是['Z','J','L','I','O','T']列表
#這樣轉(zhuǎn)換是因?yàn)閞andom.choice()函數(shù)只接受列表值作為其參數(shù)。 random.choice()函數(shù)隨機(jī)地返回列表中的一項(xiàng)的值,即可能是'Z'。
newPiece = {'shape': shape,
'rotation': random.randint(0, len(PIECES[shape]) - 1), #rotation:隨機(jī)出磚塊是多個(gè)旋轉(zhuǎn)形裝的哪個(gè)
#PIECES['Z']的返回值為[[形狀],[形狀]],len(PIECES['z'])的返回值為2 2-1=1 random.randint(0,1)隨機(jī)范圍是[0,1]
'x': int(BOARDWIDTH / 2) - int(TEMPLATEWIDTH / 2), #'x'代表磚塊5x5數(shù)據(jù)結(jié)構(gòu)左上角第一個(gè)方格的橫坐標(biāo),鍵的值總是要設(shè)置為游戲板的中間。
'y': -2, #'x'代表磚塊5x5數(shù)據(jù)結(jié)構(gòu)左上角第一個(gè)方格的縱坐標(biāo),'y'鍵的值總是要設(shè)置為-2以便將其放置到游戲板上面一點(diǎn)點(diǎn)(游戲板的首行是0行)
'color': random.randint(0, len(COLORS) - 1)#COLORS:不同顏色的一個(gè)元組
}
return newPiece#getNewPiece()函數(shù)返回newPiece字典
#給游戲板數(shù)據(jù)結(jié)構(gòu)添加磚塊
def addToBoard(board, piece): #游戲板數(shù)據(jù)結(jié)構(gòu)用來記錄之前著陸的磚塊。該函數(shù)所做的事情是接受一個(gè)磚塊數(shù)據(jù)結(jié)構(gòu),并且將其上的有效磚塊添加到游戲板數(shù)據(jù)結(jié)構(gòu)中
for x in range(TEMPLATEWIDTH): #該函數(shù)這在一個(gè)磚塊著陸之后進(jìn)行
for y in range(TEMPLATEHEIGHT):#嵌套for遍歷了5x5磚塊數(shù)據(jù)結(jié)構(gòu),當(dāng)找到一個(gè)有效磚塊時(shí),將其添加到游戲板中
if PIECES[piece['shape']][piece['rotation']][y][x] != BLANK:
board[x + piece['x']][y + piece['y']] = piece['color'] #游戲板數(shù)據(jù)結(jié)構(gòu)的值有兩種形式:數(shù)字(表示磚塊顏色),'.'即空白,表示該處沒有有效磚塊
def getBlankBoard(): #創(chuàng)建一個(gè)新的游戲板數(shù)據(jù)結(jié)構(gòu)。
board = [] #創(chuàng)建一個(gè)空白的游戲板
for i in range(BOARDWIDTH):# range(10)=[0,9] BOARDWIDTH=10 BLANK = '.' #表示空白空格
board.append([BLANK] * BOARDHEIGHT)
#board[0]-board[9]每一個(gè)變量的值都是20個(gè).組成的列表
return board
def isOnBoard(x, y):#isOnBoard()函數(shù)檢查參數(shù)x,y坐標(biāo)是否存在于游戲板上
return x >= 0 and x < BOARDWIDTH and y < BOARDHEIGHT#BOARDWIDTH=10,BOARDHEIGHT=20
def isValidPosition(board, piece, adjX=0, adjY=0):#board:游戲板 piece:磚塊 adjX,adjY表示5x5磚塊左上角方塊的坐標(biāo)
#isValidPositio,n()如果磚塊中所有的方塊都在游戲板上并且沒有和游戲板上任何方塊重疊,那么返回True
#isValidPosition()函數(shù)還有名為adjX和adjY的可選參數(shù)。通常,isValidPosition()函數(shù)檢查作為第二個(gè)參數(shù)傳遞的磚塊對(duì)象所提供的位置數(shù)據(jù)(此時(shí)adjX=0, adjY=0)。
#然而,有時(shí)候我們不想要檢查磚塊的當(dāng)前位置,而是要檢查該位置之上的一些空格
##如果給adjX遞-1.那么它不會(huì)檢查磚塊的數(shù)據(jù)結(jié)構(gòu)中的位置的有效性,而是檢查磚塊所處的位置的左邊一個(gè)空格是否是有效的。
#給adjX傳遞1的話,將會(huì)檢查磚塊右邊的一個(gè)空格。還有一個(gè)可選的adjY參數(shù)。傳遞-1給adjY,將會(huì)檢查磚塊當(dāng)前所處位置的上面一個(gè)空格,
#而給adjY傳遞值3將會(huì)檢查磚塊所在位置下面的3個(gè)空格。
for x in range(TEMPLATEWIDTH): #TEMPLATEWIDTH=5 TEMPLATEWIDTH=5
for y in range(TEMPLATEHEIGHT):# 遍歷磚塊模板的所有方塊
isAboveBoard = y + piece['y'] + adjY < 0 #模板還沒完全進(jìn)入游戲板
if isAboveBoard or PIECES[piece['shape']][piece['rotation']][y][x] == BLANK:#在5x5模板中不等于'.'的方塊,即有效方塊
continue
if not isOnBoard(x + piece['x'] + adjX, y + piece['y'] + adjY):#有效磚塊不在游戲板上
return False
if board[x + piece['x'] + adjX][y + piece['y'] + adjY] != BLANK:#有效磚塊和游戲板上的方塊重疊
return False
return True
def isCompleteLine(board, y):#判斷y行是否填滿,填滿返回True
for x in range(BOARDWIDTH):#遍歷該行的所有磚塊
if board[x][y] == BLANK:#如果存在空白,則沒填滿
return False
return True
def removeCompleteLines(board):#刪除所有填滿行,每刪除一行要將游戲板上該行之上的所有方塊都下移一行。返回刪除的行數(shù)
numLinesRemoved = 0
y = BOARDHEIGHT - 1 # BOARDHEIGHT=20-1=19即從最低行開始
while y >= 0:#注意當(dāng)刪除一行時(shí)y沒有生變化,因?yàn)榇藭r(shí)它的值已經(jīng)更新為新的一行了
if isCompleteLine(board, y):#如果該行填滿
for pullDownY in range(y, 0, -1): #range(y, 0, -1)范圍[y,1]
for x in range(BOARDWIDTH):
board[x][pullDownY] = board[x][pullDownY-1]#將刪除的行之上的每一行的值都復(fù)制到下一行
for x in range(BOARDWIDTH):#刪除第一行
board[x][0]=BLANK
numLinesRemoved=numLinesRemoved+1
else:
y =y- 1 #移到下一行
return numLinesRemoved
def convertToPixelCoords(boxx, boxy):#將游戲板上方塊的坐標(biāo)轉(zhuǎn)化成像素坐標(biāo)
return (XMARGIN + (boxx * BOXSIZE)), (TOPMARGIN + (boxy * BOXSIZE))#XMARGIN為游戲板左頂點(diǎn)的橫坐標(biāo),TOPMARGIN為游戲板左頂點(diǎn)的縱坐標(biāo)
def drawBoard(board):#繪制游戲板邊界
pygame.draw.rect(DISPLAYSURF, BORDERCOLOR, (XMARGIN - 3, TOPMARGIN - 7, (BOARDWIDTH * BOXSIZE) + 8, (BOARDHEIGHT * BOXSIZE) + 8), 5)
#pygame.draw.rect(DISPLAYSURF對(duì)象,RED顏色,(x,y,width,height),線的寬度) rect:矩形 x,y表示左上角的坐標(biāo) width表示矩形的寬度 height表示高度
#線的寬度為0(默認(rèn))表示全部填充,為1會(huì)畫很細(xì)的線
pygame.draw.rect(DISPLAYSURF, BGCOLOR, (XMARGIN, TOPMARGIN, BOXSIZE * BOARDWIDTH, BOXSIZE * BOARDHEIGHT)) #填充游戲板的背景顏色
for x in range(BOARDWIDTH):#遍歷游戲板
for y in range(BOARDHEIGHT):
drawBox(x, y, board[x][y])#這個(gè)函數(shù)會(huì)自動(dòng)找出有效方塊并繪制
#繪制一個(gè)磚塊的一個(gè)有效方塊(每個(gè)磚塊有個(gè)有效方塊)
def drawBox(boxx, boxy, color, pixelx=None, pixely=None):#繪制一個(gè)有效方塊
if color == BLANK: #如果這不是一個(gè)有效方塊,這是5x5一個(gè)空白
return
if pixelx == None and pixely == None:
pixelx, pixely = convertToPixelCoords(boxx, boxy)#將游戲板上方塊的坐標(biāo)轉(zhuǎn)化成像素坐標(biāo)
pygame.draw.rect(DISPLAYSURF, COLORS[color], (pixelx + 1, pixely + 1, BOXSIZE - 1, BOXSIZE - 1))#留出1像素的空白,這樣才能在磚塊中看到組成磚塊
#的有效方塊,不然磚塊看起來就只有一片顏色。
#繪制一個(gè)磚塊
def drawPiece(piece, pixelx=None, pixely=None):#pixelx, pixely為5x5磚塊數(shù)據(jù)結(jié)構(gòu)左上角在游戲板上的的坐標(biāo)
shapeToDraw = PIECES[piece['shape']][piece['rotation']]#PIECES[piece['shape']][piece['rotation']]為一個(gè)圖形的一種旋轉(zhuǎn)方式
if pixelx == None and pixely == None:
#然而,'Next'磚塊并不會(huì)繪制到游戲板上。在這種情況下,我們忽略磚塊數(shù)據(jù)結(jié)構(gòu)中包含的位置信息,而是讓drawPiece()函數(shù)的調(diào)用者
#為pixelx何pixely參數(shù)傳遞實(shí)參,以指定應(yīng)該將磚塊確切地繪制到窗口上的什么位置。
pixelx, pixely = convertToPixelCoords(piece['x'], piece['y'])#將磚塊坐標(biāo)轉(zhuǎn)換為像素坐標(biāo)。
for x in range(TEMPLATEWIDTH): #遍歷5x5磚塊數(shù)據(jù)結(jié)構(gòu)
for y in range(TEMPLATEHEIGHT):
if shapeToDraw[y][x] != BLANK:
drawBox(None, None, piece['color'], pixelx+(x * BOXSIZE), pixely + (y * BOXSIZE))
#還記得嗎?有效方塊左上角在游戲板中的坐標(biāo)=有效方塊左上角在方塊板數(shù)據(jù)結(jié)構(gòu)中的坐標(biāo)+方塊數(shù)據(jù)額結(jié)構(gòu)左上角在游戲板中的坐標(biāo),這里這不過換成了像素格式
def drawNextPiece(piece):
nextSurf = BASICFONT.render('Next:', True, TEXTCOLOR)
nextRect = nextSurf.get_rect()
nextRect.topleft = (WINDOWWIDTH - 120, 80)
DISPLAYSURF.blit(nextSurf, nextRect)
drawPiece(piece, pixelx=WINDOWWIDTH-120, pixely=100)
def drawStatus(score, level):
scoreSurf = BASICFONT.render('Score: %s' % score, True, TEXTCOLOR)
scoreRect = scoreSurf.get_rect()
scoreRect.topleft = (WINDOWWIDTH - 150, 20)
DISPLAYSURF.blit(scoreSurf, scoreRect)
levelSurf = BASICFONT.render('Level: %s' % level, True, TEXTCOLOR)
levelRect = levelSurf.get_rect()
levelRect.topleft = (WINDOWWIDTH - 150, 50)
DISPLAYSURF.blit(levelSurf, levelRect)
def showTextScreen(text):
titleSurf, titleRect = makeTextObjs(text, BIGFONT, TEXTCOLOR)
titleRect.center = (int(WINDOWWIDTH / 2) - 3, int(WINDOWHEIGHT / 2) - 3)
DISPLAYSURF.blit(titleSurf, titleRect)
pressKeySurf, pressKeyRect = makeTextObjs('Press a key to play.', BASICFONT, TEXTCOLOR)
pressKeyRect.center = (int(WINDOWWIDTH / 2), int(WINDOWHEIGHT / 2) + 100)
DISPLAYSURF.blit(pressKeySurf, pressKeyRect)
while checkForKeyPress() == None:
pygame.display.update()
FPSCLOCK.tick()
if __name__ == '__main__':
main()


以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
您可能感興趣的文章:
- pygame實(shí)現(xiàn)俄羅斯方塊游戲(對(duì)戰(zhàn)篇1)
- pygame實(shí)現(xiàn)俄羅斯方塊游戲(AI篇2)
- pygame實(shí)現(xiàn)俄羅斯方塊游戲(AI篇1)
- pygame實(shí)現(xiàn)俄羅斯方塊游戲(基礎(chǔ)篇3)
- pygame實(shí)現(xiàn)俄羅斯方塊游戲(基礎(chǔ)篇2)
- pygame實(shí)現(xiàn)俄羅斯方塊游戲(基礎(chǔ)篇1)
- python和pygame實(shí)現(xiàn)簡單俄羅斯方塊游戲
- Python使用pygame模塊編寫俄羅斯方塊游戲的代碼實(shí)例
- pygame庫實(shí)現(xiàn)俄羅斯方塊小游戲
相關(guān)文章
Python使用sorted對(duì)字典的key或value排序
這篇文章主要介紹了Python使用sorted對(duì)字典的key或value排序,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-11-11
使用Python & Flask 實(shí)現(xiàn)RESTful Web API的實(shí)例
下面小編就為大家?guī)硪黄褂肞ython & Flask 實(shí)現(xiàn)RESTful Web API的實(shí)例。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-09-09
python爬蟲設(shè)置每個(gè)代理ip的簡單方法
在本篇文章里小編給大家整理了一篇關(guān)于python爬蟲設(shè)置每個(gè)代理ip的簡單方法,有興趣的朋友們可以學(xué)習(xí)參考下。2021-08-08
Python實(shí)現(xiàn)導(dǎo)彈自動(dòng)追蹤代碼實(shí)例
這篇文章主要介紹了Python實(shí)現(xiàn)導(dǎo)彈自動(dòng)追蹤代碼實(shí)例,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-11-11

