Jenkins的分散式環境構建
阿新 • • 發佈:2020-11-29
1 import random, time, pygame, sys 2 from pygame.locals import * 3 4 FPS = 25 5 WINDOWWIDTH = 640#整個遊戲螢幕的寬 6 WINDOWHEIGHT = 480#整個遊戲螢幕的高 7 BOXSIZE = 20#每個小格子的寬和高 8 BOARDWIDTH = 10#遊戲視窗本身有10個方塊的寬度 9 BOARDHEIGHT = 20#遊戲視窗本身有20個方塊的高度 10 BLANK = '.'#表示空白空格 11 12 #每當玩家按下向左或向右箭頭鍵的時候,下落的磚塊都應該分別向左或向右移動一個方塊。然而,玩家也可以保持按住了向左箭頭鍵或向右箭頭鍵以使得下落的磚塊持續移動。13 MOVESIDEWAYSFREQ = 0.15 #按向左箭頭鍵或向右箭頭鍵每次持續按下超過0.15秒的時候,磚塊相應的移動一個空格 14 MOVEDOWNFREQ = 0.1 #按向下頭鍵每次持續按下超過0.1秒的時候,磚塊向下一個空格 15 XMARGIN = int((WINDOWWIDTH - BOARDWIDTH * BOXSIZE) / 2)#(0INDOWWIDTH是總視窗的寬度-遊戲介面一行上的方塊個數*每個方塊的寬度)/2視窗左邊或右邊剩下的畫素數 16 TOPMARGIN = WINDOWHEIGHT - (BOARDHEIGHT * BOXSIZE) - 5#TOPMARGIN:遊戲視窗上面剩下的畫素數=總視窗的高度-(遊戲介面一列上的方塊個數*每個方塊的高度)-517 # R G B 18 WHITE = (255, 255, 255)#白色 19 GRAY = (185, 185, 185)#灰色 20 BLACK = ( 0, 0, 0)#黑色 21 RED = (155, 0, 0)#紅色 22 GREEN = ( 0, 155, 0)#綠色 23 BLUE = ( 0, 0, 155)#藍色 24 YELLOW = (155, 155, 0)#黃色 25 BORDERCOLOR = BLUE#邊界顏色 26 BGCOLOR = BLACK#背景顏色 27 TEXTCOLOR = WHITE#文字顏色 28 COLORS = (BLUE,GREEN,RED,YELLOW) #方塊四種顏色,存於COLORS元組中 29 TEMPLATEWIDTH = 5#磚塊模板寬 30 TEMPLATEHEIGHT = 5#磚塊模板高 31 32 S_SHAPE_TEMPLATE = [['.....', #S形狀的模板 33 '.....', 34 '..OO.', 35 '.OO..', 36 '.....'], 37 ['.....', #S逆時針變化的形狀 38 '..O..', 39 '..OO.', 40 '...O.', 41 '.....']] 42 43 Z_SHAPE_TEMPLATE = [['.....', #Z形模板 44 '.....', 45 '.OO..', 46 '..OO.', 47 '.....'], 48 ['.....', 49 '..O..', 50 '.OO..', 51 '.O...', 52 '.....']] 53 54 I_SHAPE_TEMPLATE = [['..O..', #I型模板 55 '..O..', 56 '..O..', 57 '..O..', 58 '.....'], 59 ['.....', 60 '.....', 61 'OOOO.', 62 '.....', 63 '.....']] 64 65 O_SHAPE_TEMPLATE = [['.....', #O型模板 66 '.....', 67 '.OO..', 68 '.OO..', 69 '.....']] 70 71 J_SHAPE_TEMPLATE = [['.....', #J型模板 72 '.O...', 73 '.OOO.', 74 '.....', 75 '.....'], 76 ['.....', 77 '..OO.', 78 '..O..', 79 '..O..', 80 '.....'], 81 ['.....', 82 '.....', 83 '.OOO.', 84 '...O.', 85 '.....'], 86 ['.....', 87 '..O..', 88 '..O..', 89 '.OO..', 90 '.....']] 91 92 L_SHAPE_TEMPLATE = [['.....', #L型模板 93 '...O.', 94 '.OOO.', 95 '.....', 96 '.....'], 97 ['.....', 98 '..O..', 99 '..O..', 100 '..OO.', 101 '.....'], 102 ['.....', 103 '.....', 104 '.OOO.', 105 '.O...', 106 '.....'], 107 ['.....', 108 '.OO..', 109 '..O..', 110 '..O..', 111 '.....']] 112 113 T_SHAPE_TEMPLATE = [['.....', #T型模板 114 '..O..', 115 '.OOO.', 116 '.....', 117 '.....'], 118 ['.....', 119 '..O..', 120 '..OO.', 121 '..O..', 122 '.....'], 123 ['.....', 124 '.....', 125 '.OOO.', 126 '..O..', 127 '.....'], 128 ['.....', 129 '..O..', 130 '.OO..', 131 '..O..', 132 '.....']] 133 134 PIECES = {'S': S_SHAPE_TEMPLATE, #PIECES是一個字典,它儲存了所有不同的模板(列表)。每個模板都擁有一個形狀所有可能的旋轉(列表)。 135 'Z': Z_SHAPE_TEMPLATE, 136 'J': J_SHAPE_TEMPLATE, 137 'L': L_SHAPE_TEMPLATE, 138 'I': I_SHAPE_TEMPLATE, 139 'O': O_SHAPE_TEMPLATE, 140 'T': T_SHAPE_TEMPLATE} 141 142 def main(): #main()函式還負責建立了一些其他的全域性常量,並且顯示了在遊戲執行的時候出現的初始螢幕。 143 global FPSCLOCK, DISPLAYSURF, BASICFONT, BIGFONT 144 pygame.init()#在inport pygame之後 呼叫其他函式之前總要呼叫這個函式 145 FPSCLOCK = pygame.time.Clock()#pygame.time.Clock()建立pygame.time.Clock物件 146 DISPLAYSURF = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT)) #pygame.display.set_mode()的引數是一個元組,該元祖中有兩個引數, 147 #即:建立視窗的寬和高,單位是畫素,該函式返回pygame.Surface物件 148 BASICFONT = pygame.font.Font('freesansbold.ttf', 18)#字型 149 BIGFONT = pygame.font.Font('freesansbold.ttf', 100)#字型 150 pygame.display.set_caption('Tetromino')#設定視窗標題 151 showTextScreen('Tetromino')#設定在開始介面顯示的文字 152 153 while True: #遊戲迴圈,該遊戲循壞會在一秒之內多次檢查是否發生了任何新的事件,例如:點選滑鼠或按下鍵盤 154 pygame.mixer.music.load('tetrisc.mp3')#載入音樂 155 pygame.mixer.music.play(-1, 0.0)#播放音樂 156 runGame()#呼叫runGame()開始遊戲,當遊戲失敗的時候,runGame()將返回main(), 157 pygame.mixer.music.stop()#然後main()會停止背景音樂 158 showTextScreen('Game Over')#並顯示遊戲結束螢幕。當玩家按下一個鍵,showTextScreen()函式將返回,程式回到main()中的的第一行,重新開始遊戲 159 160 def runGame():#實際的遊戲程式碼都在runGame中 161 #在遊戲開始並且磚塊開始下落前,我們需要將一些變數初始化為遊戲開始時候的值。 162 board = getBlankBoard()#建立一個空白遊戲板資料結構 163 lastMoveDownTime = time.time()#lastMoveDownTime最後按向下方向鍵的時間 164 lastMoveSidewaysTime = time.time()#lastMoveSidewaysTime最後按左右向鍵的時間 165 lastFallTime = time.time()#最後下落磚塊的時間 166 movingDown = False #沒有按下向下方向鍵 167 movingLeft = False #沒有按下向左方向鍵 168 movingRight = False #沒有按下向右方向鍵 169 score = 0 #得分 170 level, fallFreq = calculateLevelAndFallFreq(score)#計算關卡數和下落頻率,因為此時score=0,所以經計算後level=1,fallFreq=0.25 171 fallingPiece = getNewPiece() #fallingPiece變數將設定為能夠被玩家操作的當前下落的磚塊 172 nextPiece = getNewPiece() #nextPice為在螢幕的Next部分出現的磚塊,即下一個將要下落的磚塊 173 174 while True: # 遊戲主迴圈,它負責磚塊在落向底部的過程中,遊戲主要部分的程式碼 175 if fallingPiece == None:#在下落的磚塊已經著陸之後,fallingPiece變數設定為None 176 fallingPiece = nextPiece#這意味著nextPiece中的磚塊將會複製到fallingPiece中。 177 nextPiece = getNewPiece()#生成新的新的nextPiece磚塊,磚塊可以通過getNewPiece()函式生成。 178 lastFallTime = time.time() #該變數也重新設定為當前時間,以便磚塊能夠在fallFreq中所設定的那麼多秒之內下落。 179 if not isValidPosition(board, fallingPiece): 180 #但是,如果遊戲板已經填滿了,isValidPosition()將返回False,導致這是一個無效的位置,那麼,我們知道遊戲板已經填滿了,玩家失敗了。 181 return #在這種情況下 runGame()函式將被返回。 182 183 for event in pygame.event.get(): #事件處理迴圈負責玩家旋轉下落的磚塊,移動下落的磚塊。 184 #鬆開一個剪頭鍵將會把movingLeft或movingRight或movingDown變數設定為False,表示玩家不再想 185 #要讓磚塊朝著該方向移動。隨後的程式碼將會根據這些“moving”變數中的Boolean值來確定做什麼。 186 if event.type == KEYUP:#當按鍵彈起的時候響應KEYUP事件 187 if (event.key == K_LEFT):#判斷當前彈起的按鍵是否為左方向鍵 188 movingLeft = False #是的話置為False,表示玩家不再想要讓磚塊朝著該方向移動。 189 elif (event.key == K_RIGHT):#同上 190 movingRight = False 191 elif (event.key == K_DOWN):#同上 192 movingDown = False 193 194 elif event.type == KEYDOWN:#當按鍵按下的時候響應KEYDOWN事件 195 if (event.key == K_LEFT) and isValidPosition(board, fallingPiece, adjX=-1): 196 #當按下的按鍵為向左方向鍵,並且向左移動一個位置有效 197 fallingPiece['x'] = fallingPiece['x'] -1 #左移 198 movingLeft = True #將movingLeft變數設定為True,並且為了確保落下的磚塊不會既向左又向右移動 199 movingRight = False #將 movingRight設定為False 200 lastMoveSidewaysTime = time.time() #lastMoveSidewaysTime更改為當前時間 201 #設定了 movingLeft,movingRigh以便玩家能夠只是按住方向鍵以保持磚塊移動。如果movingLeft變數設定為True,程式就知道已經按下了向左箭頭鍵並且沒有鬆開它。 202 203 elif (event.key == K_RIGHT ) and isValidPosition(board, fallingPiece, adjX=1): #同上 204 fallingPiece['x'] =fallingPiece['x'] + 1 205 movingRight = True 206 movingLeft = False 207 lastMoveSidewaysTime = time.time() 208 209 #按向上箭頭將會把磚塊為其下一個旋轉狀態。程式碼所需要做的只是fallingPiece字典中的'rotation'鍵的值增加1。然而,如果增加'rotation'鍵的值 210 #大於旋轉的總數目,那麼用該形狀可能旋轉的總數目(這就是len(PIECES[fallingPiece['shape']的含義)來模除它,然後,這個值將回滾到從0開始。 211 elif event.key == K_UP : 212 fallingPiece['rotation'] = (fallingPiece['rotation'] + 1) % len(PIECES[fallingPiece['shape']]) 213 if not isValidPosition(board, fallingPiece): 214 #由於新的旋轉位置與遊戲板上已有的一些方塊重疊而導致新的旋轉位置無效,那麼, 215 #我們想要通過從fallingPiece['rotation']減去1而切換回最初的旋轉。我們也可以使用len(PIECES[fallingPiece['shape']])來模除 216 #它,以便如果新的值為-1,模除將其改為列表中的最後一次旋轉。???? 217 fallingPiece['rotation'] = (fallingPiece['rotation'] - 1) % len(PIECES[fallingPiece['shape']]) 218 219 #如果按下了向下鍵,說明玩家想要磚塊下落得比正常速度更快一些。 220 elif (event.key == K_DOWN ): 221 movingDown = True # movingDown設定為True 222 if isValidPosition(board, fallingPiece, adjY=1):#下一個位置有效 223 fallingPiece['y'] = fallingPiece['y'] +1 #移動 224 lastMoveDownTime = time.time() #lastMoveDownTime重新設定為當前時間。隨後將檢查這些變數,以確保只要按下向下箭頭鍵的時候,磚塊就 225 #會以較快的速率下降 226 227 if (movingLeft or movingRight) and time.time() - lastMoveSidewaysTime > MOVESIDEWAYSFREQ:#MOVESIDEWAYSFREQ = 0.15 按向左或向右超過0.15秒 228 if movingLeft and isValidPosition(board, fallingPiece, adjX=-1):#如果是向左方向鍵,並且向左一個位置有效 229 fallingPiece['x'] =fallingPiece['x'] - 1#左移動一個位置 230 elif movingRight and isValidPosition(board, fallingPiece, adjX=1):#如果是向右方向鍵,並且向左一個位置有效 231 fallingPiece['x'] =fallingPiece['x'] + 1#右移動一個位置 232 lastMoveSidewaysTime = time.time() #將lastMoveSidewaysTime更新為當前時間。 233 234 if movingDown and time.time() - lastMoveDownTime > MOVEDOWNFREQ and isValidPosition(board, fallingPiece, adjY=1): 235 #MOVEDOWNFREQ = 0.1 按向下方向鍵超過0.1秒,並且向下一個位置有效 236 fallingPiece['y'] = fallingPiece['y'] + 1#向下移動一個位置 237 lastMoveDownTime = time.time()#將laslastMoveDownTime更新為當前時間。 238 239 #讓磚塊自然落下 240 if time.time() - lastFallTime > fallFreq:#fallFreq向下移動的速率 241 if not isValidPosition(board, fallingPiece, adjY=1):#當磚塊下一個位置無效時,即表示磚塊當前已經著陸了。 242 addToBoard(board, fallingPiece) #在遊戲板資料結構中記錄這個著陸的磚塊 243 score=score + removeCompleteLines(board)# removeCompleteLines()將負責刪除掉遊戲板上任何已經填充完整的行,並且將方塊向下推動。 244 #removeCompleteLines()函式還會返回一個整數值,表明消除了多少行,以便我們將這個數字加到得分上。 245 level, fallFreq = calculateLevelAndFallFreq(score)#由於分數已經修改了,我們呼叫calculateLevelAndFallFreq()函式來更新當前的關卡以及磚塊下落得頻率。 246 fallingPiece = None#最後我們將fallingPiece變數設定為None,以表示下一個磚塊應該變為新的下落磚塊,並且應該生成一個隨機的新磚塊作為下一個磚塊。?????? 247 else: 248 # 如果磚塊沒有著陸,我們直接將其Y位置向下設定一個空格,並且將lastFallTime重置為當前時間 249 fallingPiece['y'] = fallingPiece['y'] +1 250 lastFallTime = time.time() 251 252 # drawing everything on the screen 253 DISPLAYSURF.fill(BGCOLOR) 254 drawBoard(board) 255 drawStatus(score, level) 256 drawNextPiece(nextPiece) 257 if fallingPiece != None:#磚塊沒有下落到底部 258 drawPiece(fallingPiece) 259 pygame.display.update() 260 FPSCLOCK.tick(FPS) 261 262 def makeTextObjs(text, font, color): 263 surf = font.render(text, True, color) 264 return surf, surf.get_rect() 265 266 def checkForKeyPress(): 267 # checkForKeyPress()函式和它在Wormy遊戲中所做的事件相同。首先,它呼叫checkForQuit()來處理任何的QUIT事件(或者是專門針對Esc鍵的KEYUP事件),如果有任何這樣的事件 268 #就會終止程式。然後,它從事件佇列中提取出所有的KEYDOWN, KEYUP事件。它會忽略掉任何的KEYDOWN事件(針對pygame.event.get()指定了KEYDOWN,從而從事件佇列中清除掉該類事件)。 269 #如果事件佇列中沒有KEYUP事件,那麼該函式返回None。 270 for event in pygame.event.get([KEYDOWN, KEYUP]): 271 if event.type == KEYDOWN: 272 continue 273 return event.key 274 return None 275 276 def calculateLevelAndFallFreq(score):#每次玩家填滿一行,起分數都將增加1分。每增加10分,遊戲就進入下一個關卡,磚塊下落得會更快。關卡和下落的頻率都是通過傳遞 277 level = int(score / 10) + 1 #給該函式的分數來計算的。要計算關卡,我們使用int()來舍入除以10以後的分數。因此如果分數是0-9之間的任何數字,int()呼叫會將其 278 fallFreq = 0.27 - (level * 0.02) #舍入到0。程式碼這裡的+1部分,是因為我們想要第一個關卡作為第一關,而不是第0關。當分數達到10分的時候,int(10/10)將會計算為1 279 return level, fallFreq #並且+1將會使得關卡變為2 280 #為了計算下落的頻率,我們首先有一個基準值0.27(這意味著每0.27秒,磚塊會自然地下落一次)。然後,我們將關卡值乘以0.02,並且從基準時間0.27中減去它。因此,對於關卡1, 281 #我們從0.27中減去0.02*1得到0.25。在關卡2中我們減去0.02*2得到0.23。對於每一個關卡來說,磚塊下落的速度都比之前的關卡塊了0.02秒。 282 283 #getNewPiece()函式產生一個隨機的磚塊,放置於遊戲板的頂部(設定'y'=-2)。 284 def getNewPiece(): 285 shape = random.choice(list(PIECES.keys()))#PIECES是一個字典,它的鍵為代表形狀的字母,值為一個形狀所有可能的旋轉(列表的列表)。 286 #PIECES.keys()返回值是(['Z','J','L','I','O','T'])的元組,list(PIECES.keys())返回值是['Z','J','L','I','O','T']列表 287 #這樣轉換是因為random.choice()函式只接受列表值作為其引數。 random.choice()函式隨機地返回列表中的一項的值,即可能是'Z'。 288 newPiece = {'shape': shape, 289 'rotation': random.randint(0, len(PIECES[shape]) - 1), #rotation:隨機出磚塊是多個旋轉形裝的哪個 290 #PIECES['Z']的返回值為[[形狀],[形狀]],len(PIECES['z'])的返回值為2 2-1=1 random.randint(0,1)隨機範圍是[0,1] 291 'x': int(BOARDWIDTH / 2) - int(TEMPLATEWIDTH / 2), #'x'代表磚塊5x5資料結構左上角第一個方格的橫座標,鍵的值總是要設定為遊戲板的中間。 292 'y': -2, #'x'代表磚塊5x5資料結構左上角第一個方格的縱座標,'y'鍵的值總是要設定為-2以便將其放置到遊戲板上面一點點(遊戲板的首行是0行) 293 'color': random.randint(0, len(COLORS) - 1)#COLORS:不同顏色的一個元組 294 } 295 return newPiece#getNewPiece()函式返回newPiece字典 296 297 #給遊戲板資料結構新增磚塊 298 def addToBoard(board, piece): #遊戲板資料結構用來記錄之前著陸的磚塊。該函式所做的事情是接受一個磚塊資料結構,並且將其上的有效磚塊新增到遊戲板資料結構中 299 for x in range(TEMPLATEWIDTH): #該函式這在一個磚塊著陸之後進行 300 for y in range(TEMPLATEHEIGHT):#巢狀for遍歷了5x5磚塊資料結構,當找到一個有效磚塊時,將其新增到遊戲板中 301 if PIECES[piece['shape']][piece['rotation']][y][x] != BLANK: 302 board[x + piece['x']][y + piece['y']] = piece['color'] #遊戲板資料結構的值有兩種形式:數字(表示磚塊顏色),'.'即空白,表示該處沒有有效磚塊 303 304 def getBlankBoard(): #建立一個新的遊戲板資料結構。 305 board = [] #建立一個空白的遊戲板 306 for i in range(BOARDWIDTH):# range(10)=[0,9] BOARDWIDTH=10 BLANK = '.' #表示空白空格 307 board.append([BLANK] * BOARDHEIGHT) 308 #board[0]-board[9]每一個變數的值都是20個.組成的列表 309 return board 310 311 def isOnBoard(x, y):#isOnBoard()函式檢查引數x,y座標是否存在於遊戲板上 312 return x >= 0 and x < BOARDWIDTH and y < BOARDHEIGHT#BOARDWIDTH=10,BOARDHEIGHT=20 313 314 def isValidPosition(board, piece, adjX=0, adjY=0):#board:遊戲板 piece:磚塊 adjX,adjY表示5x5磚塊左上角方塊的座標 315 #isValidPositio,n()如果磚塊中所有的方塊都在遊戲板上並且沒有和遊戲板上任何方塊重疊,那麼返回True 316 #isValidPosition()函式還有名為adjX和adjY的可選引數。通常,isValidPosition()函式檢查作為第二個引數傳遞的磚塊物件所提供的位置資料(此時adjX=0, adjY=0)。 317 #然而,有時候我們不想要檢查磚塊的當前位置,而是要檢查該位置之上的一些空格 318 ##如果給adjX遞-1.那麼它不會檢查磚塊的資料結構中的位置的有效性,而是檢查磚塊所處的位置的左邊一個空格是否是有效的。 319 #給adjX傳遞1的話,將會檢查磚塊右邊的一個空格。還有一個可選的adjY引數。傳遞-1給adjY,將會檢查磚塊當前所處位置的上面一個空格, 320 #而給adjY傳遞值3將會檢查磚塊所在位置下面的3個空格。 321 for x in range(TEMPLATEWIDTH): #TEMPLATEWIDTH=5 TEMPLATEWIDTH=5 322 for y in range(TEMPLATEHEIGHT):# 遍歷磚塊模板的所有方塊 323 isAboveBoard = y + piece['y'] + adjY < 0 #模板還沒完全進入遊戲板 324 if isAboveBoard or PIECES[piece['shape']][piece['rotation']][y][x] == BLANK:#在5x5模板中不等於'.'的方塊,即有效方塊 325 continue 326 if not isOnBoard(x + piece['x'] + adjX, y + piece['y'] + adjY):#有效磚塊不在遊戲板上 327 return False 328 if board[x + piece['x'] + adjX][y + piece['y'] + adjY] != BLANK:#有效磚塊和遊戲板上的方塊重疊 329 return False 330 return True 331 332 def isCompleteLine(board, y):#判斷y行是否填滿,填滿返回True 333 for x in range(BOARDWIDTH):#遍歷該行的所有磚塊 334 if board[x][y] == BLANK:#如果存在空白,則沒填滿 335 return False 336 return True 337 338 def removeCompleteLines(board):#刪除所有填滿行,每刪除一行要將遊戲板上該行之上的所有方塊都下移一行。返回刪除的行數 339 numLinesRemoved = 0 340 y = BOARDHEIGHT - 1 # BOARDHEIGHT=20-1=19即從最低行開始 341 while y >= 0:#注意當刪除一行時y沒有生變化,因為此時它的值已經更新為新的一行了 342 if isCompleteLine(board, y):#如果該行填滿 343 for pullDownY in range(y, 0, -1): #range(y, 0, -1)範圍[y,1] 344 for x in range(BOARDWIDTH): 345 board[x][pullDownY] = board[x][pullDownY-1]#將刪除的行之上的每一行的值都複製到下一行 346 for x in range(BOARDWIDTH):#刪除第一行 347 board[x][0]=BLANK 348 numLinesRemoved=numLinesRemoved+1 349 else: 350 y =y- 1 #移到下一行 351 return numLinesRemoved 352 353 def convertToPixelCoords(boxx, boxy):#將遊戲板上方塊的座標轉化成畫素座標 354 return (XMARGIN + (boxx * BOXSIZE)), (TOPMARGIN + (boxy * BOXSIZE))#XMARGIN為遊戲板左頂點的橫座標,TOPMARGIN為遊戲板左頂點的縱座標 355 356 def drawBoard(board):#繪製遊戲板邊界 357 pygame.draw.rect(DISPLAYSURF, BORDERCOLOR, (XMARGIN - 3, TOPMARGIN - 7, (BOARDWIDTH * BOXSIZE) + 8, (BOARDHEIGHT * BOXSIZE) + 8), 5) 358 #pygame.draw.rect(DISPLAYSURF物件,RED顏色,(x,y,width,height),線的寬度) rect:矩形 x,y表示左上角的座標 width表示矩形的寬度 height表示高度 359 #線的寬度為0(預設)表示全部填充,為1會畫很細的線 360 pygame.draw.rect(DISPLAYSURF, BGCOLOR, (XMARGIN, TOPMARGIN, BOXSIZE * BOARDWIDTH, BOXSIZE * BOARDHEIGHT)) #填充遊戲板的背景顏色 361 for x in range(BOARDWIDTH):#遍歷遊戲板 362 for y in range(BOARDHEIGHT): 363 drawBox(x, y, board[x][y])#這個函式會自動找出有效方塊並繪製 364 365 #繪製一個磚塊的一個有效方塊(每個磚塊有個有效方塊) 366 def drawBox(boxx, boxy, color, pixelx=None, pixely=None):#繪製一個有效方塊 367 if color == BLANK: #如果這不是一個有效方塊,這是5x5一個空白 368 return 369 if pixelx == None and pixely == None: 370 pixelx, pixely = convertToPixelCoords(boxx, boxy)#將遊戲板上方塊的座標轉化成畫素座標 371 pygame.draw.rect(DISPLAYSURF, COLORS[color], (pixelx + 1, pixely + 1, BOXSIZE - 1, BOXSIZE - 1))#留出1畫素的空白,這樣才能在磚塊中看到組成磚塊 372 #的有效方塊,不然磚塊看起來就只有一片顏色。 373 374 #繪製一個磚塊 375 def drawPiece(piece, pixelx=None, pixely=None):#pixelx, pixely為5x5磚塊資料結構左上角在遊戲板上的的座標 376 shapeToDraw = PIECES[piece['shape']][piece['rotation']]#PIECES[piece['shape']][piece['rotation']]為一個圖形的一種旋轉方式 377 if pixelx == None and pixely == None: 378 #然而,'Next'磚塊並不會繪製到遊戲板上。在這種情況下,我們忽略磚塊資料結構中包含的位置資訊,而是讓drawPiece()函式的呼叫者 379 #為pixelx何pixely引數傳遞實參,以指定應該將磚塊確切地繪製到視窗上的什麼位置。 380 pixelx, pixely = convertToPixelCoords(piece['x'], piece['y'])#將磚塊座標轉換為畫素座標。 381 for x in range(TEMPLATEWIDTH): #遍歷5x5磚塊資料結構 382 for y in range(TEMPLATEHEIGHT): 383 if shapeToDraw[y][x] != BLANK: 384 drawBox(None, None, piece['color'], pixelx+(x * BOXSIZE), pixely + (y * BOXSIZE)) 385 #還記得嗎?有效方塊左上角在遊戲板中的座標=有效方塊左上角在方塊板資料結構中的座標+方塊資料額結構左上角在遊戲板中的座標,這裡這不過換成了畫素格式 386 387 def drawNextPiece(piece): 388 nextSurf = BASICFONT.render('Next:', True, TEXTCOLOR) 389 nextRect = nextSurf.get_rect() 390 nextRect.topleft = (WINDOWWIDTH - 120, 80) 391 DISPLAYSURF.blit(nextSurf, nextRect) 392 drawPiece(piece, pixelx=WINDOWWIDTH-120, pixely=100) 393 394 def drawStatus(score, level): 395 scoreSurf = BASICFONT.render('Score: %s' % score, True, TEXTCOLOR) 396 scoreRect = scoreSurf.get_rect() 397 scoreRect.topleft = (WINDOWWIDTH - 150, 20) 398 DISPLAYSURF.blit(scoreSurf, scoreRect) 399 levelSurf = BASICFONT.render('Level: %s' % level, True, TEXTCOLOR) 400 levelRect = levelSurf.get_rect() 401 levelRect.topleft = (WINDOWWIDTH - 150, 50) 402 DISPLAYSURF.blit(levelSurf, levelRect) 403 404 def showTextScreen(text): 405 titleSurf, titleRect = makeTextObjs(text, BIGFONT, TEXTCOLOR) 406 titleRect.center = (int(WINDOWWIDTH / 2) - 3, int(WINDOWHEIGHT / 2) - 3) 407 DISPLAYSURF.blit(titleSurf, titleRect) 408 pressKeySurf, pressKeyRect = makeTextObjs('Press a key to play.', BASICFONT, TEXTCOLOR) 409 pressKeyRect.center = (int(WINDOWWIDTH / 2), int(WINDOWHEIGHT / 2) + 100) 410 DISPLAYSURF.blit(pressKeySurf, pressKeyRect) 411 while checkForKeyPress() == None: 412 pygame.display.update() 413 FPSCLOCK.tick() 414 415 if __name__ == '__main__': 416 main()