开心消消乐:Python
生活随笔
收集整理的這篇文章主要介紹了
开心消消乐:Python
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
"""
用到以下鍵:“x”和“y”——游戲在棋盤上的位置。0,0是左上角。還有一個y可以設置的ROWABOVEBOARD行,表示它在棋盤上。方向——四個常量變量之一,上、下、左、右,游戲前進的方向。'imageNum' —— GEMIMAGES的整數索引,用于表示這個游戲用哪個圖像。
"""
import random, time, pygame, sys, copy
from pygame.locals import *FPS = 30 # 每30秒更新屏幕
WINDOWWIDTH = 600 # 窗口寬度
WINDOWHEIGHT = 600 # 窗口高度BOARDWIDTH = 8 # 8列
BOARDHEIGHT = 8 # 8行
GEMIMAGESIZE = 64 # 每小格的寬度和高度NUMGEMIMAGES = 6 # 圖片的類型,.png格式,從0開始命名 gem0.png
assert NUMGEMIMAGES >= 5 # 最少5種圖片NUMMATCHSOUNDS = 6 # 音樂的類型,.wav格式,從0開始命名 match0.wavMOVERATE = 25 #1到100,更大的num意味著更快的動作
DEDUCTSPEED = 0.8 # 每減少1分扣減DEDUCTSPEED秒。# R G B
PURPLE = (255, 0, 255)
LIGHTBLUE = (255, 202, 255)
BLUE = ( 77, 219, 255)
RED = (255, 100, 100)
BLACK = ( 0, 0, 0)
BROWN = ( 85, 65, 0)
HIGHLIGHTCOLOR = PURPLE # 游戲邊界的顏色
BGCOLOR = LIGHTBLUE # 屏幕上的背景色
GRIDCOLOR = BLUE # 游戲板的顏色
GAMEOVERCOLOR = RED #“游戲結束”文字的顏色
GAMEOVERBGCOLOR = BLACK # “游戲結束”文字的顏色
SCORECOLOR = BROWN # 得分文本的顏色# 從線到邊的距離
# 它被多次使用,因此在這里計算一次并存儲在變量中
XMARGIN = int((WINDOWWIDTH - GEMIMAGESIZE * BOARDWIDTH) / 2)
YMARGIN = int((WINDOWHEIGHT - GEMIMAGESIZE * BOARDHEIGHT) / 2)# 方向常數
UP = 'up'
DOWN = 'down'
LEFT = 'left'
RIGHT = 'right'EMPTY_SPACE = -1 # 一個任意的非正值
ROWABOVEBOARD = 'row above board' # 一個任意的非整數值def main():global FPSCLOCK, DISPLAYSURF, GEMIMAGES, GAMESOUNDS, BASICFONT, BOARDRECTS# 初始設置pygame.init()FPSCLOCK = pygame.time.Clock()DISPLAYSURF = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT))pygame.display.set_caption('Gemgem')BASICFONT = pygame.font.Font('freesansbold.ttf', 36)# 加載圖片GEMIMAGES = []for i in range(1, NUMGEMIMAGES+1):gemImage = pygame.image.load('gem%s.png' % i)if gemImage.get_size() != (GEMIMAGESIZE, GEMIMAGESIZE):gemImage = pygame.transform.smoothscale(gemImage, (GEMIMAGESIZE, GEMIMAGESIZE))GEMIMAGES.append(gemImage)# 加載聲音GAMESOUNDS = {}GAMESOUNDS['bad swap'] = pygame.mixer.Sound('badswap.wav')GAMESOUNDS['match'] = []for i in range(NUMMATCHSOUNDS):GAMESOUNDS['match'].append(pygame.mixer.Sound('match%s.wav' % i))# 創建pygame,矩形對象,用于為每個板空間執行板坐標到像素坐標的轉換BOARDRECTS = []for x in range(BOARDWIDTH):BOARDRECTS.append([])for y in range(BOARDHEIGHT):r = pygame.Rect((XMARGIN + (x * GEMIMAGESIZE),YMARGIN + (y * GEMIMAGESIZE),GEMIMAGESIZE,GEMIMAGESIZE))BOARDRECTS[x].append(r)while True:runGame()def runGame():# 運行游戲,當游戲結束時,這個函數返回# 初始化面板gameBoard = getBlankBoard()score = 0fillBoardAndAnimate(gameBoard, [], score) # Drop the initial gems.# 初始化變量firstSelectedGem = NonelastMouseDownX = NonelastMouseDownY = NonegameIsOver = FalselastScoreDeduction = time.time()clickContinueTextSurf = Nonewhile True: # 主要游戲循環clickedSpace = Nonefor event in pygame.event.get(): # 事件處理循環if event.type == QUIT or (event.type == KEYUP and event.key == K_ESCAPE):pygame.quit()sys.exit()elif event.type == KEYUP and event.key == K_BACKSPACE:return # start a new gameelif event.type == MOUSEBUTTONUP:if gameIsOver:return # 游戲結束后,點擊開始一個新的游戲if event.pos == (lastMouseDownX, lastMouseDownY):# 此事件是鼠標單擊,而不是鼠標拖動結束clickedSpace = checkForGemClick(event.pos)else:# 這是鼠標拖動結束firstSelectedGem = checkForGemClick((lastMouseDownX, lastMouseDownY))clickedSpace = checkForGemClick(event.pos)if not firstSelectedGem or not clickedSpace:# 如果不是有效拖動的一部分,取消選中這兩個firstSelectedGem = NoneclickedSpace = Noneelif event.type == MOUSEBUTTONDOWN:# 這是鼠標點擊或拖動的開始lastMouseDownX, lastMouseDownY = event.posif clickedSpace and not firstSelectedGem:# 這是第一次點擊寶石firstSelectedGem = clickedSpaceelif clickedSpace and firstSelectedGem:#點擊并選擇了兩個寶石,交換。firstSwappingGem, secondSwappingGem = getSwappingGems(gameBoard, firstSelectedGem, clickedSpace)if firstSwappingGem == None and secondSwappingGem == None:# 如果兩者都不是,那么寶石就不是相鄰的firstSelectedGem = None # 取消選擇第一塊寶石continue# 在屏幕上顯示交換動畫boardCopy = getBoardCopyMinusGems(gameBoard, (firstSwappingGem, secondSwappingGem))animateMovingGems(boardCopy, [firstSwappingGem, secondSwappingGem], [], score)# 交換在面板上的數據結構上的寶石gameBoard[firstSwappingGem['x']][firstSwappingGem['y']] = secondSwappingGem['imageNum']gameBoard[secondSwappingGem['x']][secondSwappingGem['y']] = firstSwappingGem['imageNum']# 看看這是不是一個匹配的動作matchedGems = findMatchingGems(gameBoard)if matchedGems == []:# 不是一個匹配的移動;交換寶石GAMESOUNDS['bad swap'].play()animateMovingGems(boardCopy, [firstSwappingGem, secondSwappingGem], [], score)gameBoard[firstSwappingGem['x']][firstSwappingGem['y']] = firstSwappingGem['imageNum']gameBoard[secondSwappingGem['x']][secondSwappingGem['y']] = secondSwappingGem['imageNum']else:# 是一個匹配的移動scoreAdd = 0while matchedGems != []:# 刪除匹配的寶石,然后拉下板# points是一個dicts列表,它告訴fillBoardAndAnimate()在屏幕上顯示文本以顯示玩家獲得多少點數。# 點數是一個列表,因為如果玩家得到多個匹配,那么就會出現多個點數文本。points = []for gemSet in matchedGems:scoreAdd += (10 + (len(gemSet) - 3) * 10)for gem in gemSet:gameBoard[gem[0]][gem[1]] = EMPTY_SPACEpoints.append({'points': scoreAdd,'x': gem[0] * GEMIMAGESIZE + XMARGIN,'y': gem[1] * GEMIMAGESIZE + YMARGIN})random.choice(GAMESOUNDS['match']).play()score += scoreAdd# 掉落新的寶石fillBoardAndAnimate(gameBoard, points, score)# 檢查是否有新的匹配matchedGems = findMatchingGems(gameBoard)firstSelectedGem = Noneif not canMakeMove(gameBoard):gameIsOver = True# 畫出面板DISPLAYSURF.fill(BGCOLOR)drawBoard(gameBoard)if firstSelectedGem != None:highlightSpace(firstSelectedGem['x'], firstSelectedGem['y'])if gameIsOver:if clickContinueTextSurf == None:#只呈現文本一次。在以后的迭代中,只需使用clickContinueTextSurf中已經存在的Surface對象clickContinueTextSurf = BASICFONT.render('Final Score: %s (Click to continue)' % (score), 1, GAMEOVERCOLOR, GAMEOVERBGCOLOR)clickContinueTextRect = clickContinueTextSurf.get_rect()clickContinueTextRect.center = int(WINDOWWIDTH / 2), int(WINDOWHEIGHT / 2)DISPLAYSURF.blit(clickContinueTextSurf, clickContinueTextRect)elif score > 0 and time.time() - lastScoreDeduction > DEDUCTSPEED:# 分數隨時間而下降score -= 1lastScoreDeduction = time.time()drawScore(score)pygame.display.update()FPSCLOCK.tick(FPS)def getSwappingGems(board, firstXY, secondXY):# 如果兩個寶石在(X, Y)坐標處的寶石相鄰,那么它們的“方向”鍵被設置為適當的方向值,以便彼此交換# 否則,返回(None, None)firstGem = {'imageNum': board[firstXY['x']][firstXY['y']],'x': firstXY['x'],'y': firstXY['y']}secondGem = {'imageNum': board[secondXY['x']][secondXY['y']],'x': secondXY['x'],'y': secondXY['y']}highlightedGem = Noneif firstGem['x'] == secondGem['x'] + 1 and firstGem['y'] == secondGem['y']:firstGem['direction'] = LEFTsecondGem['direction'] = RIGHTelif firstGem['x'] == secondGem['x'] - 1 and firstGem['y'] == secondGem['y']:firstGem['direction'] = RIGHTsecondGem['direction'] = LEFTelif firstGem['y'] == secondGem['y'] + 1 and firstGem['x'] == secondGem['x']:firstGem['direction'] = UPsecondGem['direction'] = DOWNelif firstGem['y'] == secondGem['y'] - 1 and firstGem['x'] == secondGem['x']:firstGem['direction'] = DOWNsecondGem['direction'] = UPelse:# 這些寶石不相鄰,不能交換return None, Nonereturn firstGem, secondGemdef getBlankBoard():# 創建并返回空白板數據結構board = []for x in range(BOARDWIDTH):board.append([EMPTY_SPACE] * BOARDHEIGHT)return boarddef canMakeMove(board):# 如果棋盤處于可以對其進行匹配移動的狀態,則返回True。否則返回假# oneOffPatterns中的模式表示gem,它們的配置方式是只需要移動一次就可以創建一個三元組oneOffPatterns = (((0,1), (1,0), (2,0)),((0,1), (1,1), (2,0)),((0,0), (1,1), (2,0)),((0,1), (1,0), (2,1)),((0,0), (1,0), (2,1)),((0,0), (1,1), (2,1)),((0,0), (0,2), (0,3)),((0,0), (0,1), (0,3)))# x和y變量在黑板上的每個空間上迭代。如果我們使用+表示當前在黑板上迭代的空間,那么這個模式:(0,1),(1,0),(2,0))表示相同的# 寶石是這樣設置的:## +A# B# C## 即,gem A與+的偏移量為(0,1),gem B與(1,0)的偏移量為(2,0)。在這種情況下,gem A可以被交換到左邊以形成一個垂直的三排三連音## 有八種可能的方式使寶石遠離形成一個三元組,因此oneOffPattern有8種模式for x in range(BOARDWIDTH):for y in range(BOARDHEIGHT):for pat in oneOffPatterns:# 檢查每個可能的模式“匹配在下一步”,看看是否可以做一個可能的行動if (getGemAt(board, x+pat[0][0], y+pat[0][1]) == \getGemAt(board, x+pat[1][0], y+pat[1][1]) == \getGemAt(board, x+pat[2][0], y+pat[2][1]) != None) or \(getGemAt(board, x+pat[0][1], y+pat[0][0]) == \getGemAt(board, x+pat[1][1], y+pat[1][0]) == \getGemAt(board, x+pat[2][1], y+pat[2][0]) != None):return True # return True the first time you find a patternreturn Falsedef drawMovingGem(gem, progress):# 畫一個寶石沿著它的“方向”鍵指示的方向滑動。進度參數是從0(剛開始)到100(幻燈片完成)的數字movex = 0movey = 0progress *= 0.01if gem['direction'] == UP:movey = -int(progress * GEMIMAGESIZE)elif gem['direction'] == DOWN:movey = int(progress * GEMIMAGESIZE)elif gem['direction'] == RIGHT:movex = int(progress * GEMIMAGESIZE)elif gem['direction'] == LEFT:movex = -int(progress * GEMIMAGESIZE)basex = gem['x']basey = gem['y']if basey == ROWABOVEBOARD:basey = -1pixelx = XMARGIN + (basex * GEMIMAGESIZE)pixely = YMARGIN + (basey * GEMIMAGESIZE)r = pygame.Rect( (pixelx + movex, pixely + movey, GEMIMAGESIZE, GEMIMAGESIZE) )DISPLAYSURF.blit(GEMIMAGES[gem['imageNum']], r)def pullDownAllGems(board):# 將木板上的寶石拉到底部,以填補任何空缺for x in range(BOARDWIDTH):gemsInColumn = []for y in range(BOARDHEIGHT):if board[x][y] != EMPTY_SPACE:gemsInColumn.append(board[x][y])board[x] = ([EMPTY_SPACE] * (BOARDHEIGHT - len(gemsInColumn))) + gemsInColumndef getGemAt(board, x, y):if x < 0 or y < 0 or x >= BOARDWIDTH or y >= BOARDHEIGHT:return Noneelse:return board[x][y]def getDropSlots(board):# 為每個列創建一個“drop slot”,并用該列缺少的一些gem填充該slot。這個函數假設寶石的重力已經下降boardCopy = copy.deepcopy(board)pullDownAllGems(boardCopy)dropSlots = []for i in range(BOARDWIDTH):dropSlots.append([])# 計算黑板上每一列的空格數for x in range(BOARDWIDTH):for y in range(BOARDHEIGHT-1, -1, -1): # 從底部開始,向上if boardCopy[x][y] == EMPTY_SPACE:possibleGems = list(range(len(GEMIMAGES)))for offsetX, offsetY in ((0, -1), (1, 0), (0, 1), (-1, 0)):# 縮小可能的寶石的范圍,我們應該把它們放在空白的地方,這樣當它們掉落的時候,我們就不會把兩個相同的寶石放在一起neighborGem = getGemAt(boardCopy, x + offsetX, y + offsetY)if neighborGem != None and neighborGem in possibleGems:possibleGems.remove(neighborGem)newGem = random.choice(possibleGems)boardCopy[x][y] = newGemdropSlots[x].append(newGem)return dropSlotsdef findMatchingGems(board):gemsToRemove = [] # a list of lists of gems in matching triplets that should be removedboardCopy = copy.deepcopy(board)# 循環遍歷每個空間,檢查3個相鄰的相同的寶石for x in range(BOARDWIDTH):for y in range(BOARDHEIGHT):# 尋找水平匹配if getGemAt(boardCopy, x, y) == getGemAt(boardCopy, x + 1, y) == getGemAt(boardCopy, x + 2, y) and getGemAt(boardCopy, x, y) != EMPTY_SPACE:targetGem = boardCopy[x][y]offset = 0removeSet = []while getGemAt(boardCopy, x + offset, y) == targetGem:#繼續檢查一行中是否有超過3個gemremoveSet.append((x + offset, y))boardCopy[x + offset][y] = EMPTY_SPACEoffset += 1gemsToRemove.append(removeSet)# 尋找垂直匹配if getGemAt(boardCopy, x, y) == getGemAt(boardCopy, x, y + 1) == getGemAt(boardCopy, x, y + 2) and getGemAt(boardCopy, x, y) != EMPTY_SPACE:targetGem = boardCopy[x][y]offset = 0removeSet = []while getGemAt(boardCopy, x, y + offset) == targetGem:# 繼續檢查,以防一行中有超過3個gemremoveSet.append((x, y + offset))boardCopy[x][y + offset] = EMPTY_SPACEoffset += 1gemsToRemove.append(removeSet)return gemsToRemovedef highlightSpace(x, y):pygame.draw.rect(DISPLAYSURF, HIGHLIGHTCOLOR, BOARDRECTS[x][y], 4)def getDroppingGems(board):#找到所有在他們下面有一個空空間的寶石boardCopy = copy.deepcopy(board)droppingGems = []for x in range(BOARDWIDTH):for y in range(BOARDHEIGHT - 2, -1, -1):if boardCopy[x][y + 1] == EMPTY_SPACE and boardCopy[x][y] != EMPTY_SPACE:# 如果不是空的,這個空間會下降,但是下面的空間是空的droppingGems.append( {'imageNum': boardCopy[x][y], 'x': x, 'y': y, 'direction': DOWN} )boardCopy[x][y] = EMPTY_SPACEreturn droppingGemsdef animateMovingGems(board, gems, pointsText, score):# pointsText是一個帶有'x'、'y'和'points'鍵的字典progress = 0 #進展在0代表開始,100代表完成while progress < 100: # 動畫循環DISPLAYSURF.fill(BGCOLOR)drawBoard(board)for gem in gems: # 布置每一個寶石drawMovingGem(gem, progress)drawScore(score)for pointText in pointsText:pointsSurf = BASICFONT.render(str(pointText['points']), 1, SCORECOLOR)pointsRect = pointsSurf.get_rect()pointsRect.center = (pointText['x'], pointText['y'])DISPLAYSURF.blit(pointsSurf, pointsRect)pygame.display.update()FPSCLOCK.tick(FPS)progress += MOVERATE # 為下一幀的動畫進行更多的進展def moveGems(board, movingGems):# 移動寶石是一個帶有鍵x, y,方向,imageNum的字典列表for gem in movingGems:if gem['y'] != ROWABOVEBOARD:board[gem['x']][gem['y']] = EMPTY_SPACEmovex = 0movey = 0if gem['direction'] == LEFT:movex = -1elif gem['direction'] == RIGHT:movex = 1elif gem['direction'] == DOWN:movey = 1elif gem['direction'] == UP:movey = -1board[gem['x'] + movex][gem['y'] + movey] = gem['imageNum']else:# 寶石位于板的上方(新的寶石來自板的上方)board[gem['x']][0] = gem['imageNum'] # move to top rowdef fillBoardAndAnimate(board, points, score):dropSlots = getDropSlots(board)while dropSlots != [[]] * BOARDWIDTH:# 只要有更多的寶石掉落,做掉落的動畫movingGems = getDroppingGems(board)for x in range(len(dropSlots)):if len(dropSlots[x]) != 0:# 使每個槽中最低的寶石開始向下移動movingGems.append({'imageNum': dropSlots[x][0], 'x': x, 'y': ROWABOVEBOARD, 'direction': DOWN})boardCopy = getBoardCopyMinusGems(board, movingGems)animateMovingGems(boardCopy, movingGems, points, score)moveGems(board, movingGems)# 通過刪除之前的最低的gem,從下拉槽中刪除下一行gems是最低的for x in range(len(dropSlots)):if len(dropSlots[x]) == 0:continueboard[x][0] = dropSlots[x][0]del dropSlots[x][0]def checkForGemClick(pos):# 查看鼠標點擊是否在面板上for x in range(BOARDWIDTH):for y in range(BOARDHEIGHT):if BOARDRECTS[x][y].collidepoint(pos[0], pos[1]):return {'x': x, 'y': y}return None # Click不在面板上def drawBoard(board):for x in range(BOARDWIDTH):for y in range(BOARDHEIGHT):pygame.draw.rect(DISPLAYSURF, GRIDCOLOR, BOARDRECTS[x][y], 1)gemToDraw = board[x][y]if gemToDraw != EMPTY_SPACE:DISPLAYSURF.blit(GEMIMAGES[gemToDraw], BOARDRECTS[x][y])def getBoardCopyMinusGems(board, gems):# 創建并返回已傳遞的板數據結構的副本,并從其中刪除“gems”列表中的gems# Gems是一個dicts列表,帶有鍵x, y,方向,imageNumboardCopy = copy.deepcopy(board)# 從面板板數據結構拷貝中刪除一些寶石for gem in gems:if gem['y'] != ROWABOVEBOARD:boardCopy[gem['x']][gem['y']] = EMPTY_SPACEreturn boardCopydef drawScore(score):scoreImg = BASICFONT.render(str(score), 1, SCORECOLOR)scoreRect = scoreImg.get_rect()scoreRect.bottomleft = (10, WINDOWHEIGHT - 6)DISPLAYSURF.blit(scoreImg, scoreRect)if __name__ == '__main__':main()
?
總結
以上是生活随笔為你收集整理的开心消消乐:Python的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 千锋扣丁学堂 如何学习android高级
- 下一篇: websocket python爬虫_p