欧美三区_成人在线免费观看视频_欧美极品少妇xxxxⅹ免费视频_a级毛片免费播放_鲁一鲁中文字幕久久_亚洲一级特黄

Python使用pygame模塊編寫俄羅斯方塊游戲的代碼實(shí)例

系統(tǒng) 1610 0

文章先介紹了關(guān)于俄羅斯方塊游戲的幾個(gè)術(shù)語。

  • 邊框――由10*20個(gè)空格組成,方塊就落在這里面。
  • 盒子――組成方塊的其中小方塊,是組成方塊的基本單元。
  • 方塊――從邊框頂?shù)粝碌臇|西,游戲者可以翻轉(zhuǎn)和改變位置。每個(gè)方塊由4個(gè)盒子組成。
  • 形狀――不同類型的方塊。這里形狀的名字被叫做T, S, Z ,J, L, I , O。如下圖所示:

Python使用pygame模塊編寫俄羅斯方塊游戲的代碼實(shí)例_第1張圖片

模版――用一個(gè)列表存放形狀被翻轉(zhuǎn)后的所有可能樣式。全部存放在變量里,變量名字如S_SHAPE_TEMPLATE or J_SHAPE_TEMPLATE
著陸――當(dāng)一個(gè)方塊到達(dá)邊框的底部或接觸到在其他的盒子話,我們就說這個(gè)方塊著陸了。那樣的話,另一個(gè)方塊就會(huì)開始下落。
下面先把代碼敲一遍,試著了解作者意圖,體會(huì)俄羅斯方塊游戲的制作過程。

            
import random, time, pygame, sys 
from pygame.locals import * 
 
FPS = 25 
WINDOWWIDTH = 640 
WINDOWHEIGHT = 480 
BOXSIZE = 20 
BOARDWIDTH = 10 
BOARDHEIGHT = 20 
BLANK = '.' 
 
MOVESIDEWAYSFREQ = 0.15 
MOVEDOWNFREQ = 0.1 
 
XMARGIN = int((WINDOWWIDTH - BOARDWIDTH * BOXSIZE) / 2) 
TOPMARGIN = WINDOWHEIGHT - (BOARDHEIGHT * BOXSIZE) - 5 
#        R  G  B 
WHITE    = (255, 255, 255) 
GRAY    = (185, 185, 185) 
BLACK    = ( 0,  0,  0) 
RED     = (155,  0,  0) 
LIGHTRED  = (175, 20, 20) 
GREEN    = ( 0, 155,  0) 
LIGHTGREEN = ( 20, 175, 20) 
BLUE    = ( 0,  0, 155) 
LIGHTBLUE  = ( 20, 20, 175) 
YELLOW   = (155, 155,  0) 
LIGHTYELLOW = (175, 175, 20) 
 
BORDERCOLOR = BLUE 
BGCOLOR = BLACK 
TEXTCOLOR = WHITE 
TEXTSHADOWCOLOR = GRAY 
COLORS   = (   BLUE,   GREEN,   RED,   YELLOW) 
LIGHTCOLORS = (LIGHTBLUE, LIGHTGREEN, LIGHTRED, LIGHTYELLOW) 
assert len(COLORS) == len(LIGHTCOLORS) # each color must have light color 
 
TEMPLATEWIDTH = 5 
TEMPLATEHEIGHT = 5 
 
S_SHAPE_TEMPLATE = [['.....', 
           '.....', 
           '..OO.', 
           '.OO..', 
           '.....'], 
          ['.....', 
           '..O..', 
           '..OO.', 
           '...O.', 
           '.....']] 
 
Z_SHAPE_TEMPLATE = [['.....', 
           '.....', 
           '.OO..', 
           '..OO.', 
           '.....'], 
          ['.....', 
           '..O..', 
           '.OO..', 
           '.O...', 
           '.....']] 
 
I_SHAPE_TEMPLATE = [['..O..', 
           '..O..', 
           '..O..', 
           '..O..', 
           '.....'], 
          ['.....', 
           '.....', 
           'OOOO.', 
           '.....', 
           '.....']] 
 
O_SHAPE_TEMPLATE = [['.....', 
           '.....', 
           '.OO..', 
           '.OO..', 
           '.....']] 
 
J_SHAPE_TEMPLATE = [['.....', 
           '.O...', 
           '.OOO.', 
           '.....', 
           '.....'], 
          ['.....', 
           '..OO.', 
           '..O..', 
           '..O..', 
           '.....'], 
          ['.....', 
           '.....', 
           '.OOO.', 
           '...O.', 
           '.....'], 
          ['.....', 
           '..O..', 
           '..O..', 
           '.OO..', 
           '.....']] 
 
L_SHAPE_TEMPLATE = [['.....', 
           '...O.', 
           '.OOO.', 
           '.....', 
           '.....'], 
          ['.....', 
           '..O..', 
           '..O..', 
           '..OO.', 
           '.....'], 
          ['.....', 
           '.....', 
           '.OOO.', 
           '.O...', 
           '.....'], 
          ['.....', 
           '.OO..', 
           '..O..', 
           '..O..', 
           '.....']] 
 
T_SHAPE_TEMPLATE = [['.....', 
           '..O..', 
           '.OOO.', 
           '.....', 
           '.....'], 
          ['.....', 
           '..O..', 
           '..OO.', 
           '..O..', 
           '.....'], 
          ['.....', 
           '.....', 
           '.OOO.', 
           '..O..', 
           '.....'], 
          ['.....', 
           '..O..', 
           '.OO..', 
           '..O..', 
           '.....']] 
 
PIECES = {'S': S_SHAPE_TEMPLATE, 
     '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(): 
  global FPSCLOCK, DISPLAYSURF, BASICFONT, BIGFONT 
  pygame.init() 
  FPSCLOCK = pygame.time.Clock() 
  DISPLAYSURF = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT)) 
  BASICFONT = pygame.font.Font('freesansbold.ttf', 18) 
  BIGFONT = pygame.font.Font('freesansbold.ttf', 100) 
  pygame.display.set_caption('Tetromino') 
 
  showTextScreen('Tetromino') 
  while True: # game loop 
    if random.randint(0, 1) == 0: 
      pygame.mixer.music.load('tetrisb.mid') 
    else: 
      pygame.mixer.music.load('tetrisc.mid') 
    pygame.mixer.music.play(-1, 0.0) 
    runGame() 
    pygame.mixer.music.stop() 
    showTextScreen('Game Over') 
 
 
def runGame(): 
  # setup variables for the start of the game 
  board = getBlankBoard() 
  lastMoveDownTime = time.time() 
  lastMoveSidewaysTime = time.time() 
  lastFallTime = time.time() 
  movingDown = False # note: there is no movingUp variable 
  movingLeft = False 
  movingRight = False 
  score = 0 
  level, fallFreq = calculateLevelAndFallFreq(score) 
 
  fallingPiece = getNewPiece() 
  nextPiece = getNewPiece() 
 
  while True: # game loop 
    if fallingPiece == None: 
      # No falling piece in play, so start a new piece at the top 
      fallingPiece = nextPiece 
      nextPiece = getNewPiece() 
      lastFallTime = time.time() # reset lastFallTime 
 
      if not isValidPosition(board, fallingPiece): 
        return # can't fit a new piece on the board, so game over 
 
    checkForQuit() 
    for event in pygame.event.get(): # event handling loop 
      if event.type == KEYUP: 
        if (event.key == K_p): 
          # Pausing the game 
          DISPLAYSURF.fill(BGCOLOR) 
          pygame.mixer.music.stop() 
          showTextScreen('Paused') # pause until a key press 
          pygame.mixer.music.play(-1, 0.0) 
          lastFallTime = time.time() 
          lastMoveDownTime = time.time() 
          lastMoveSidewaysTime = time.time() 
        elif (event.key == K_LEFT or event.key == K_a): 
          movingLeft = False 
        elif (event.key == K_RIGHT or event.key == K_d): 
          movingRight = False 
        elif (event.key == K_DOWN or event.key == K_s): 
          movingDown = False 
 
      elif event.type == KEYDOWN: 
        # moving the piece sideways 
        if (event.key == K_LEFT or event.key == K_a) and isValidPosition(board, fallingPiece, adjX=-1): 
          fallingPiece['x'] -= 1 
          movingLeft = True 
          movingRight = False 
          lastMoveSidewaysTime = time.time() 
 
        elif (event.key == K_RIGHT or event.key == K_d) and isValidPosition(board, fallingPiece, adjX=1): 
          fallingPiece['x'] += 1 
          movingRight = True 
          movingLeft = False 
          lastMoveSidewaysTime = time.time() 
 
        # rotating the piece (if there is room to rotate) 
        elif (event.key == K_UP or event.key == K_w): 
          fallingPiece['rotation'] = (fallingPiece['rotation'] + 1) % len(PIECES[fallingPiece['shape']]) 
          if not isValidPosition(board, fallingPiece): 
            fallingPiece['rotation'] = (fallingPiece['rotation'] - 1) % len(PIECES[fallingPiece['shape']]) 
        elif (event.key == K_q): # rotate the other direction 
          fallingPiece['rotation'] = (fallingPiece['rotation'] - 1) % len(PIECES[fallingPiece['shape']]) 
          if not isValidPosition(board, fallingPiece): 
            fallingPiece['rotation'] = (fallingPiece['rotation'] + 1) % len(PIECES[fallingPiece['shape']]) 
 
        # making the piece fall faster with the down key 
        elif (event.key == K_DOWN or event.key == K_s): 
          movingDown = True 
          if isValidPosition(board, fallingPiece, adjY=1): 
            fallingPiece['y'] += 1 
          lastMoveDownTime = time.time() 
 
        # move the current piece all the way down 
        elif event.key == K_SPACE: 
          movingDown = False 
          movingLeft = False 
          movingRight = False 
          for i in range(1, BOARDHEIGHT): 
            if not isValidPosition(board, fallingPiece, adjY=i): 
              break 
          fallingPiece['y'] += i - 1 
 
    # handle moving the piece because of user input 
    if (movingLeft or movingRight) and time.time() - lastMoveSidewaysTime > MOVESIDEWAYSFREQ: 
      if movingLeft and isValidPosition(board, fallingPiece, adjX=-1): 
        fallingPiece['x'] -= 1 
      elif movingRight and isValidPosition(board, fallingPiece, adjX=1): 
        fallingPiece['x'] += 1 
      lastMoveSidewaysTime = time.time() 
 
    if movingDown and time.time() - lastMoveDownTime > MOVEDOWNFREQ and isValidPosition(board, fallingPiece, adjY=1): 
      fallingPiece['y'] += 1 
      lastMoveDownTime = time.time() 
 
    # let the piece fall if it is time to fall 
    if time.time() - lastFallTime > fallFreq: 
      # see if the piece has landed 
      if not isValidPosition(board, fallingPiece, adjY=1): 
        # falling piece has landed, set it on the board 
        addToBoard(board, fallingPiece) 
        score += removeCompleteLines(board) 
        level, fallFreq = calculateLevelAndFallFreq(score) 
        fallingPiece = None 
      else: 
        # piece did not land, just move the piece down 
        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 terminate(): 
  pygame.quit() 
  sys.exit() 
 
 
def checkForKeyPress(): 
  # Go through event queue looking for a KEYUP event. 
  # Grab KEYDOWN events to remove them from the event queue. 
  checkForQuit() 
 
  for event in pygame.event.get([KEYDOWN, KEYUP]): 
    if event.type == KEYDOWN: 
      continue 
    return event.key 
  return None 
 
 
def showTextScreen(text): 
  # This function displays large text in the 
  # center of the screen until a key is pressed. 
  # Draw the text drop shadow 
  titleSurf, titleRect = makeTextObjs(text, BIGFONT, TEXTSHADOWCOLOR) 
  titleRect.center = (int(WINDOWWIDTH / 2), int(WINDOWHEIGHT / 2)) 
  DISPLAYSURF.blit(titleSurf, titleRect) 
 
  # Draw the text 
  titleSurf, titleRect = makeTextObjs(text, BIGFONT, TEXTCOLOR) 
  titleRect.center = (int(WINDOWWIDTH / 2) - 3, int(WINDOWHEIGHT / 2) - 3) 
  DISPLAYSURF.blit(titleSurf, titleRect) 
 
  # Draw the additional "Press a key to play." text. 
  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() 
 
 
def checkForQuit(): 
  for event in pygame.event.get(QUIT): # get all the QUIT events 
    terminate() # terminate if any QUIT events are present 
  for event in pygame.event.get(KEYUP): # get all the KEYUP events 
    if event.key == K_ESCAPE: 
      terminate() # terminate if the KEYUP event was for the Esc key 
    pygame.event.post(event) # put the other KEYUP event objects back 
 
 
def calculateLevelAndFallFreq(score): 
  # Based on the score, return the level the player is on and 
  # how many seconds pass until a falling piece falls one space. 
  level = int(score / 10) + 1 
  fallFreq = 0.27 - (level * 0.02) 
  return level, fallFreq 
 
def getNewPiece(): 
  # return a random new piece in a random rotation and color 
  shape = random.choice(list(PIECES.keys())) 
  newPiece = {'shape': shape, 
        'rotation': random.randint(0, len(PIECES[shape]) - 1), 
        'x': int(BOARDWIDTH / 2) - int(TEMPLATEWIDTH / 2), 
        'y': -2, # start it above the board (i.e. less than 0) 
        'color': random.randint(0, len(COLORS)-1)} 
  return newPiece 
 
 
def addToBoard(board, piece): 
  # fill in the board based on piece's location, shape, and rotation 
  for x in range(TEMPLATEWIDTH): 
    for y in range(TEMPLATEHEIGHT): 
      if PIECES[piece['shape']][piece['rotation']][y][x] != BLANK: 
        board[x + piece['x']][y + piece['y']] = piece['color'] 
 
 
def getBlankBoard(): 
  # create and return a new blank board data structure 
  board = [] 
  for i in range(BOARDWIDTH): 
    board.append([BLANK] * BOARDHEIGHT) 
  return board 
 
 
def isOnBoard(x, y): 
  return x >= 0 and x < BOARDWIDTH and y < BOARDHEIGHT 
 
 
def isValidPosition(board, piece, adjX=0, adjY=0): 
  # Return True if the piece is within the board and not colliding 
  for x in range(TEMPLATEWIDTH): 
    for y in range(TEMPLATEHEIGHT): 
      isAboveBoard = y + piece['y'] + adjY < 0 
      if isAboveBoard or PIECES[piece['shape']][piece['rotation']][y][x] == BLANK: 
        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): 
  # Return True if the line filled with boxes with no gaps. 
  for x in range(BOARDWIDTH): 
    if board[x][y] == BLANK: 
      return False 
  return True 
 
 
def removeCompleteLines(board): 
  # Remove any completed lines on the board, move everything above them down, and return the number of complete lines. 
  numLinesRemoved = 0 
  y = BOARDHEIGHT - 1 # start y at the bottom of the board 
  while y >= 0: 
    if isCompleteLine(board, y): 
      # Remove the line and pull boxes down by one line. 
      for pullDownY in range(y, 0, -1): 
        for x in range(BOARDWIDTH): 
          board[x][pullDownY] = board[x][pullDownY-1] 
      # Set very top line to blank. 
      for x in range(BOARDWIDTH): 
        board[x][0] = BLANK 
      numLinesRemoved += 1 
      # Note on the next iteration of the loop, y is the same. 
      # This is so that if the line that was pulled down is also 
      # complete, it will be removed. 
    else: 
      y -= 1 # move on to check next row up 
  return numLinesRemoved 
 
 
def convertToPixelCoords(boxx, boxy): 
  # Convert the given xy coordinates of the board to xy 
  # coordinates of the location on the screen. 
  return (XMARGIN + (boxx * BOXSIZE)), (TOPMARGIN + (boxy * BOXSIZE)) 
 
 
def drawBox(boxx, boxy, color, pixelx=None, pixely=None): 
  # draw a single box (each tetromino piece has four boxes) 
  # at xy coordinates on the board. Or, if pixelx & pixely 
  # are specified, draw to the pixel coordinates stored in 
  # pixelx & pixely (this is used for the "Next" piece). 
  if color == BLANK: 
    return 
  if pixelx == None and pixely == None: 
    pixelx, pixely = convertToPixelCoords(boxx, boxy) 
  pygame.draw.rect(DISPLAYSURF, COLORS[color], (pixelx + 1, pixely + 1, BOXSIZE - 1, BOXSIZE - 1)) 
  pygame.draw.rect(DISPLAYSURF, LIGHTCOLORS[color], (pixelx + 1, pixely + 1, BOXSIZE - 4, BOXSIZE - 4)) 
 
 
def drawBoard(board): 
  # draw the border around the board 
  pygame.draw.rect(DISPLAYSURF, BORDERCOLOR, (XMARGIN - 3, TOPMARGIN - 7, (BOARDWIDTH * BOXSIZE) + 8, (BOARDHEIGHT * BOXSIZE) + 8), 5) 
 
  # fill the background of the board 
  pygame.draw.rect(DISPLAYSURF, BGCOLOR, (XMARGIN, TOPMARGIN, BOXSIZE * BOARDWIDTH, BOXSIZE * BOARDHEIGHT)) 
  # draw the individual boxes on the board 
  for x in range(BOARDWIDTH): 
    for y in range(BOARDHEIGHT): 
      drawBox(x, y, board[x][y]) 
 
 
def drawStatus(score, level): 
  # draw the score text 
  scoreSurf = BASICFONT.render('Score: %s' % score, True, TEXTCOLOR) 
  scoreRect = scoreSurf.get_rect() 
  scoreRect.topleft = (WINDOWWIDTH - 150, 20) 
  DISPLAYSURF.blit(scoreSurf, scoreRect) 
 
  # draw the level text 
  levelSurf = BASICFONT.render('Level: %s' % level, True, TEXTCOLOR) 
  levelRect = levelSurf.get_rect() 
  levelRect.topleft = (WINDOWWIDTH - 150, 50) 
  DISPLAYSURF.blit(levelSurf, levelRect) 
 
 
def drawPiece(piece, pixelx=None, pixely=None): 
  shapeToDraw = PIECES[piece['shape']][piece['rotation']] 
  if pixelx == None and pixely == None: 
    # if pixelx & pixely hasn't been specified, use the location stored in the piece data structure 
    pixelx, pixely = convertToPixelCoords(piece['x'], piece['y']) 
 
  # draw each of the boxes that make up the piece 
  for x in range(TEMPLATEWIDTH): 
    for y in range(TEMPLATEHEIGHT): 
      if shapeToDraw[y][x] != BLANK: 
        drawBox(None, None, piece['color'], pixelx + (x * BOXSIZE), pixely + (y * BOXSIZE)) 
 
 
def drawNextPiece(piece): 
  # draw the "next" text 
  nextSurf = BASICFONT.render('Next:', True, TEXTCOLOR) 
  nextRect = nextSurf.get_rect() 
  nextRect.topleft = (WINDOWWIDTH - 120, 80) 
  DISPLAYSURF.blit(nextSurf, nextRect) 
  # draw the "next" piece 
  drawPiece(piece, pixelx=WINDOWWIDTH-120, pixely=100) 
 
 
if __name__ == '__main__': 
  main() 


          

代碼一開始仍是一些變量的初始化,我們這里還加載了time模塊,后面會(huì)用到。BOXSIZE, BOARDWIDTH, BOARDHEIGHT與前面貪吃蛇相關(guān)初始化類似,使其與屏幕像素點(diǎn)聯(lián)系起來。

            
MOVESIDEWAYSFREQ = 0.15
MOVEDOWNFREQ = 0.1

          

這兩個(gè)變量的作用是這樣的,每當(dāng)游戲者按下左鍵或右鍵,下降的方塊相應(yīng)的向左或右移一個(gè)格子。然而游戲者也可以一直按下方向左鍵或右鍵讓方塊保持移動(dòng)。MOVESIDEWAYSFREQ這個(gè)固定值表示如果一直按下方向左鍵或右鍵那么每0.15秒方塊才會(huì)繼續(xù)移動(dòng)。
MOVEDOWNFREQ 這個(gè)固定值與上面的是一樣的除了它是告訴當(dāng)游戲者一直按下方向下鍵時(shí)方塊下落的頻率。

            
XMARGIN = int((WINDOWWIDTH - BOARDWIDTH * BOXSIZE) / 2)
TOPMARGIN = WINDOWHEIGHT - (BOARDHEIGHT * BOXSIZE) - 5

          

這兩句的意思就看下面這個(gè)圖就明白了。

Python使用pygame模塊編寫俄羅斯方塊游戲的代碼實(shí)例_第2張圖片

然后是一些顏色值的定義。其中要注意的是COLORS和LIGHTCOLORS,COLORS是組成方塊的小方塊的顏色,而LIGHTCOLORS是圍繞在小方塊周圍的顏色,為了強(qiáng)調(diào)出輪廓而設(shè)計(jì)的。
接著是定義方塊了。游戲必須知道每個(gè)類型的方塊有多少種形狀,在這里我們用在列表中嵌入含有字符串的列表來構(gòu)成這個(gè)模版,一個(gè)方塊類型的模版含有了這個(gè)方塊可能變換的所有形狀。比如I的模版如下:

            
I_SHAPE_TEMPLATE = [['..O..', 
           '..O..', 
           '..O..', 
           '..O..', 
           '.....'], 
          ['.....', 
           '.....', 
           'OOOO.', 
           '.....', 
           '.....']] 

          

TEMPLATEWIDTH = 5和TEMPLATEHEIGHT = 5則表示組成形狀的行和列,如下圖所示:

Python使用pygame模塊編寫俄羅斯方塊游戲的代碼實(shí)例_第3張圖片

在看這段定義。

            
PIECES = {'S': S_SHAPE_TEMPLATE, 
     'Z': Z_SHAPE_TEMPLATE, 
     'J': J_SHAPE_TEMPLATE, 
     'L': L_SHAPE_TEMPLATE, 
     'I': I_SHAPE_TEMPLATE, 
     'O': O_SHAPE_TEMPLATE, 
     'T': T_SHAPE_TEMPLATE} 

          

PIECES這個(gè)變量是一個(gè)字典,里面儲(chǔ)存了所有的不同模版。因?yàn)槊總€(gè)又有一個(gè)類型的方塊的所有變換形狀。那就意味著PIECES變量包含了每個(gè)類型的方塊和所有的的變換形狀。這就是存放我們游戲中用到的形狀的數(shù)據(jù)結(jié)構(gòu)。(又加強(qiáng)了對(duì)字典的理解)
主函數(shù)main()
主函數(shù)的前部分主要是創(chuàng)建一些全局變量和在游戲開始之前顯示一個(gè)開始畫面。

            
while True: # game loop 
  if random.randint(0, 1) == 0: 
    pygame.mixer.music.load('tetrisb.mid') 
  else: 
    pygame.mixer.music.load('tetrisc.mid') 
  pygame.mixer.music.play(-1, 0.0) 
  runGame() 
  pygame.mixer.music.stop() 
  showTextScreen('Game Over') 


          

上面這段代碼中runGame()是程序的核心部分。循環(huán)中首先簡(jiǎn)單的隨機(jī)決定采用哪個(gè)背景音樂。然后調(diào)用runGame(),當(dāng)游戲失敗,runGame()就會(huì)返回到main()函數(shù),這時(shí)會(huì)停止背景音樂和顯示游戲失敗的畫面。
當(dāng)游戲者按下一個(gè)鍵,showTextScreen()顯示游戲失敗的函數(shù)就會(huì)返回。游戲循環(huán)會(huì)再次開始然后繼續(xù)下一次游戲。
runGame()

            
def runGame(): 
  # setup variables for the start of the game 
  board = getBlankBoard() 
  lastMoveDownTime = time.time() 
  lastMoveSidewaysTime = time.time() 
  lastFallTime = time.time() 
  movingDown = False # note: there is no movingUp variable 
  movingLeft = False 
  movingRight = False 
  score = 0 
  level, fallFreq = calculateLevelAndFallFreq(score) 
 
  fallingPiece = getNewPiece() 
  nextPiece = getNewPiece() 


          

在游戲開始和方塊掉落之前,我們需要初始化一些跟游戲開始相關(guān)的變量。fallingPiece變量被賦值成當(dāng)前掉落的變量,nextPiece變量被賦值成游戲者可以在屏幕NEXT區(qū)域看見的下一個(gè)方塊。

            
while True: # game loop 
  if fallingPiece == None: 
    # No falling piece in play, so start a new piece at the top 
    fallingPiece = nextPiece 
    nextPiece = getNewPiece() 
    lastFallTime = time.time() # reset lastFallTime 
 
    if not isValidPosition(board, fallingPiece): 
      return # can't fit a new piece on the board, so game over 
 
  checkForQuit() 


          

這部分包含了當(dāng)方塊往底部掉落時(shí)的的所有代碼。fallingPiece變量在方塊著陸后被設(shè)置成None。這意味著nextPiece變量中的下一個(gè)方塊應(yīng)該被賦值給fallingPiece變量,然后一個(gè)隨機(jī)的方塊又會(huì)被賦值給nextPiece變量。lastFallTime變量也被賦值成當(dāng)前時(shí)間,這樣我們就可以通過fallFreq變量控制方塊下落的頻率。
來自getNewPiece函數(shù)的方塊只有一部分被放置在方框區(qū)域中。但是如果這是一個(gè)非法的位置,比如此時(shí)游戲方框已經(jīng)被填滿(isVaildPostion()函數(shù)返回False),那么我們就知道方框已經(jīng)滿了,游戲者輸?shù)袅擞螒颉.?dāng)這些發(fā)生時(shí),runGame()函數(shù)就會(huì)返回。
事件處理循環(huán)
事件循環(huán)主要處理當(dāng)翻轉(zhuǎn)方塊,移動(dòng)方塊時(shí)或者暫停游戲時(shí)的一些事情。
暫停游戲

            
if (event.key == K_p): 
  # Pausing the game 
  DISPLAYSURF.fill(BGCOLOR) 
  pygame.mixer.music.stop() 
  showTextScreen('Paused') # pause until a key press 
  pygame.mixer.music.play(-1, 0.0) 
  lastFallTime = time.time() 
  lastMoveDownTime = time.time() 
  lastMoveSidewaysTime = time.time() 


          

如果游戲者按下P鍵,游戲就會(huì)暫停。我們應(yīng)該隱藏掉游戲界面以防止游戲者作弊(否則游戲者會(huì)看著畫面思考怎么處理方塊),用DISPLAYSURF.fill(BGCOLOR)就可以實(shí)現(xiàn)這個(gè)效果。注意的是我們還要保存一些時(shí)間變量值。

            
elif (event.key == K_LEFT or event.key == K_a): 
  movingLeft = False 
elif (event.key == K_RIGHT or event.key == K_d): 
  movingRight = False 
elif (event.key == K_DOWN or event.key == K_s): 
  movingDown = False 


          

停止按下方向鍵或ASD鍵會(huì)把moveLeft,moveRight,movingDown變量設(shè)置為False.,表明游戲者不再想要在此方向上移動(dòng)方塊。后面的代碼會(huì)基于moving變量處理一些事情。注意的上方向鍵和W鍵是用來翻轉(zhuǎn)方塊的而不是移動(dòng)方塊。這就是為什么沒有movingUp變量.

            
elif event.type == KEYDOWN: 
  # moving the piece sideways 
  if (event.key == K_LEFT or event.key == K_a) and isValidPosition(board, fallingPiece, adjX=-1): 
    fallingPiece['x'] -= 1 
    movingLeft = True 
    movingRight = False 
    lastMoveSidewaysTime = time.time() 


          

當(dāng)左方向鍵按下(而且往左移動(dòng)是有效的,通過調(diào)用isVaildPosition()函數(shù)知道的),那么我們應(yīng)該改變一個(gè)方塊的位置使其向左移動(dòng)一個(gè)通過讓rallingPiece['x']減1.isVaildPosition()函數(shù)有個(gè)參數(shù)選項(xiàng)是adjX和adjY.平常,isVaildPostion()函數(shù)檢查方塊的位置通過函數(shù)的第二個(gè)參數(shù)的傳遞。然而,有時(shí)我們不想檢查方塊當(dāng)前的位置,而是偏離當(dāng)前方向幾個(gè)格子的位置。
比如adjX=-1,則表示向左移動(dòng)一個(gè)格子后方塊的位置,為+1則表示向右移動(dòng)一個(gè)格子后的位置。adjY同理如此。
movingLeft變量會(huì)被設(shè)置為True,確保方塊不會(huì)向右移動(dòng),此時(shí)movingRight變量設(shè)置為False。同時(shí)需要更新lastMoveSidewaysTime的值。
這個(gè)lastMoveSidewaysTime變量設(shè)置的原因是這樣。因?yàn)橛螒蛘哂锌赡芤恢卑粗较蜴I讓其方塊移動(dòng)。如果moveLeft被設(shè)置為True,程序就會(huì)知道方向左鍵已經(jīng)被按下。如果在lastMoveSidewaysTime變量?jī)?chǔ)存的時(shí)間基礎(chǔ)上,0.15秒(儲(chǔ)存在MOVESIDEAYSFREQ變量中)過去后,那么此時(shí)程序就會(huì)將方塊再次向左移動(dòng)一個(gè)格子。

            
elif (event.key == K_UP or event.key == K_w): 
          fallingPiece['rotation'] = (fallingPiece['rotation'] + 1) % len(PIECES[fallingPiece['shape']]) 
          if not isValidPosition(board, fallingPiece): 
            fallingPiece['rotation'] = (fallingPiece['rotation'] - 1) % len(PIECES[fallingPiece['shape']]) 


          

如果方向鍵上或W鍵被按下,那么就會(huì)翻轉(zhuǎn)方塊。上面的代碼做的就是將儲(chǔ)存在fallingPiece字典中的‘rotation'鍵的鍵值加1.然而,當(dāng)增加的'rotation'鍵值大于所有當(dāng)前類型方塊的形狀的數(shù)目的話(此變量?jī)?chǔ)存在len(SHAPES[fallingPiece['shape']])變量中),那么它翻轉(zhuǎn)到最初的形狀。
?

            
if not isValidPosition(board, fallingPiece): 
            fallingPiece['rotation'] = (fallingPiece['rotation'] - 1) % len(PIECES[fallingPiece['shape']]) 

          

如果翻轉(zhuǎn)后的形狀無效因?yàn)槠渲械囊恍┬》綁K已經(jīng)超過邊框的范圍,那么我們就要把它變回原來的形狀通過將fallingPiece['rotation')減去1.

            
elif (event.key == K_q): # rotate the other direction 
          fallingPiece['rotation'] = (fallingPiece['rotation'] - 1) % len(PIECES[fallingPiece['shape']]) 
          if not isValidPosition(board, fallingPiece): 
            fallingPiece['rotation'] = (fallingPiece['rotation'] + 1) % len(PIECES[fallingPiece['shape']]) 


          

這段代碼與上面之前的那段代碼是一個(gè)意思,不同的是這段代碼是當(dāng)游戲者按下Q鍵時(shí)翻轉(zhuǎn)方塊朝相反的方向。這里我們減去1而不是加1.

            
elif (event.key == K_DOWN or event.key == K_s): 
  movingDown = True 
  if isValidPosition(board, fallingPiece, adjY=1): 
    fallingPiece['y'] += 1 
  lastMoveDownTime = time.time() 

          

如果下鍵被按下,游戲者此時(shí)希望方塊下降的比平常快。fallingPiece['y'] += 1使方塊下落一個(gè)格子(前提是這是一個(gè)有效的下落)moveDown被設(shè)置為True,lastMoceDownTime變量也被設(shè)置為當(dāng)前時(shí)間。這個(gè)變量以后將被檢查當(dāng)方向下鍵一直按下時(shí)從而保證方塊以一個(gè)比平??斓乃俾氏陆怠?

            
elif event.key == K_SPACE: 
  movingDown = False 
  movingLeft = False 
  movingRight = False 
  for i in range(1, BOARDHEIGHT): 
    if not isValidPosition(board, fallingPiece, adjY=i): 
      break 
  fallingPiece['y'] += i - 1 

          

當(dāng)游戲者按下空格鍵,方塊將會(huì)迅速的下落至著陸。程序首先需要找出到它著陸需要下降個(gè)多少個(gè)格子。其中有關(guān)moving的三個(gè)變量都要被設(shè)置為False(保證程序后面部分的代碼知道游戲者已經(jīng)停止了按下所有的方向鍵)。

            
if (movingLeft or movingRight) and time.time() - lastMoveSidewaysTime > MOVESIDEWAYSFREQ: 
  if movingLeft and isValidPosition(board, fallingPiece, adjX=-1): 
    fallingPiece['x'] -= 1 
  elif movingRight and isValidPosition(board, fallingPiece, adjX=1): 
    fallingPiece['x'] += 1 
  lastMoveSidewaysTime = time.time() 

          

這段代碼是處理一直按下某個(gè)方向鍵時(shí)的情況。
如果用戶按住鍵超過0.15秒。那么表達(dá)式(movingLeft or movingRight) and time.time() - lastMoveSidewaysTime > MOVESIDEWAYSFREQ:返回True。這樣的話我們就可以移動(dòng)方塊向左或向右移動(dòng)一個(gè)格子。
這個(gè)做法是很用的,因?yàn)槿绻脩糁貜?fù)的按下方向鍵讓方塊移動(dòng)多個(gè)格子是很煩人的。好的做法是,用戶可以按住方向鍵讓方塊保持移動(dòng)直到松開鍵為止。最后別忘了更新lastMoveSideWaysTime變量。

            
if movingDown and time.time() - lastMoveDownTime > MOVEDOWNFREQ and isValidPosition(board, fallingPiece, adjY=1): 
  fallingPiece['y'] += 1 
  lastMoveDownTime = time.time() 


          

這段代碼的意思跟上面的代碼差不多。

            
if time.time() - lastFallTime > fallFreq: 
  # see if the piece has landed 
  if not isValidPosition(board, fallingPiece, adjY=1): 
    # falling piece has landed, set it on the board 
    addToBoard(board, fallingPiece) 
    score += removeCompleteLines(board) 
    level, fallFreq = calculateLevelAndFallFreq(score) 
    fallingPiece = None 
  else: 
    # piece did not land, just move the piece down 
    fallingPiece['y'] += 1 
    lastFallTime = time.time() 


          

方塊自然下落的速率由lastFallTime變量決定。如果自從上個(gè)方塊掉落了一個(gè)格子后過去了足夠的時(shí)間,那么上面代碼就會(huì)再讓方塊移動(dòng)一個(gè)格子。


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號(hào)聯(lián)系: 360901061

您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對(duì)您有幫助就好】

您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長(zhǎng)會(huì)非常 感謝您的哦?。?!

發(fā)表我的評(píng)論
最新評(píng)論 總共0條評(píng)論
主站蜘蛛池模板: 91精品国产高清久久久久久91 | 免费国产成人高清视频网站 | 亚洲欧美国产精品久久久久久久 | 欧美精品成人a多人在线观看 | 精品影院| 深夜福利一区二区 | 91麻豆精品一二三区在线 | 白颖宇 | 特黄a大片免费视频 | 欧美一级做一级做片性十三 | 国产亚洲精品久久久极品美女 | 久草视频福利在线观看 | 亚洲精品久久久蜜桃 | 国内外一级毛片 | 国产福利视频在线观看 | 精品一区二区电影 | 台湾一级毛片永久免费 | 欧美激情久久久久久久久 | 国产在线一区二区三区 | 国产成人91激情在线播放 | 亚洲综合色一区二区三区另类 | 日本毛片免费看 | 正规成人啪啪 | 欧美男人天堂 | 91国内精品久久久久免费影院 | 草久久免费视频 | 九九热精 | videos 欧美| 91亚洲国产成人久久精品网站 | 99SE久久爱五月天婷婷 | 中文字幕成人av | 九九九热在线精品免费全部 | 能直接看av的网站 | 亚洲精品一区在线 | 一区二区三区无码高清视频 | 天天射天天干天天插 | 午夜精品久久久久久久99黑人 | 亚洲美女亚洲精品久久久久 | 久久精彩 | 欧美日韩亚洲一区 | 特级欧美视频aaaaaa |