Match-3游戏 - 匹配相关的声音

时间:2018-01-09 12:48:08

标签: python pygame

我希望得到一些我在pygame上工作的第三场比赛的帮助。我按照以下方式加载了图像和声音,以及“宝石”和“宝石”。将是空气,土,火和水的经典元素。如何播放相应的水声文件,例如,当匹配3个或更多水精灵时?不需要任何游戏代码的帮助,只是为了在图像和音频文件之间建立关联以及如何播放它们,而匹配元素!= []'。谢谢。

# Directions
UP = 'up'
DOWN = 'down'
LEFT = 'left'
RIGHT = 'right'

# Space to the sides of grid
XMARGIN = int((WIDTH - ELEMENTSIZE * GRIDWIDTH) / 2)
YMARGIN = int((HEIGHT - ELEMENTSIZE * GRIDHEIGHT) / 2)

EMPTY_SPACE = -1
ROWABOVEBOARD = 'row above board'

# Colours
AIR = pygame.Color(145, 129, 129)
FIRE = pygame.Color(255, 123, 0)
WATER = pygame.Color(93, 118, 245)
EARTH = pygame.Color(22, 136, 0)
ELECTRIC = pygame.Color(22, 204, 0)
SMOKE = pygame.Color(222, 222, 222)
ICE = pygame.Color(234, 231, 255)
METAL = pygame.Color(105, 105, 105)
BLOOD = pygame.Color(222, 7, 7)

# FPS controller
fpsController = pygame.time.Clock()

def main():
    global FPSCLOCK, BOARDRECTS, ELEMENTIMAGES, SOUNDS, PLAYSURF, BASICFONT

    # Basic set up
    pygame.init()
    FPSCLOCK = pygame.time.Clock()
    PLAYSURF = pygame.display.set_mode((WIDTH, HEIGHT))
    BASICFONT = pygame.font.Font('freesansbold.ttf', 36)

    # Load images
    ELEMENTIMAGES = []
    for i in range(1, NUMELEMENTS+1):
        elementImage = pygame.image.load('element%s.jpg' % i)
        if elementImage.get_size() != (ELEMENTSIZE, ELEMENTSIZE):
            elementImage = pygame.transform.smoothscale(elementImage, (ELEMENTSIZE, ELEMENTSIZE))
        ELEMENTIMAGES.append(elementImage)

    # Load sounds
    SOUNDS = {}
    SOUNDS['bad swap'] = pygame.mixer.Sound('badswap.wav')
    SOUNDS['match'] = []
    for i in range(NUMMATCHSOUNDS):
        SOUNDS['match'].append(pygame.mixer.Sound('elementsound%s.wav' % i))

    # Rect objects for board space conversions
    BOARDRECTS = []
    for x in range(GRIDWIDTH):
        BOARDRECTS.append([])
        for y in range(GRIDHEIGHT):
            r = pygame.Rect((XMARGIN + (x * ELEMENTSIZE),
                             YMARGIN + (y * ELEMENTSIZE),
                             ELEMENTSIZE, ELEMENTSIZE))
            BOARDRECTS[x].append(r)

    while True:
        runGame()

def runGame():
    # Board initialisation
    gameBoard = getBlankBoard()
    score = 0
    fillBoardAndAnimate(gameBoard, [], score) # Drop initial elements

    # Initialise new game variables
    firstSelectedElement = None
    lastMouseDownX = None
    lastMouseDownY = None
    gameIsOver = False
    lastScoreDeduction = time.time()
    clickContinueTextSurf = None

    # Main game loop
    while True:
        clickedSpace = None
        for event in pygame.event.get(): # Event handling
            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 # new game

            elif event.type == MOUSEBUTTONUP:
                if gameIsOver:
                    return # click to start new game

                if event.pos == (lastMouseDownX, lastMouseDownY):
                    clickedSpace = checkForElementClick(event.pos)
                else:
                    firstSelectedElement = checkForElementClick((lastMouseDownX, lastMouseDownY))
                    clickedSpace = checkForElementClick(event.pos)
                    if not firstSelectedElement or not clickedSpace:
                        firstSelectedElement = None
                        clickedSpace = None
            elif event.type == MOUSEBUTTONDOWN:
                lastMouseDownX, lastMouseDownY = event.pos

        if clickedSpace and not firstSelectedElement:
            firstSelectedElement = clickedSpace
        elif clickedSpace and firstSelectedElement:
            firstSwappingElement, secondSwappingElement = getSwappingElements(gameBoard, firstSelectedElement, clickedSpace)
            if firstSwappingElement == None and secondSwappingElement == None:
                # If both are None, elements are not adjacent
                firstSelectedElement = None
                continue

            # Swap animation
            boardCopy = getBoardCopyMinusElements(gameBoard, (firstSwappingElement, secondSwappingElement))
            animateMovingElements(boardCopy, [firstSwappingElement, secondSwappingElement], [], score)

            # Swap elements in the board
            gameBoard[firstSwappingElement['x']][firstSwappingElement['y']] = secondSwappingElement['imageNum']
            gameBoard[secondSwappingElement['x']][secondSwappingElement['y']] = firstSwappingElement['imageNum']

            # See if this is a match
            matchedElements = findMatchingElements(gameBoard)
            if matchedElements == []:
                # No match - swap back
                SOUNDS['bad swap'].play()
                animateMovingElements(boardCopy, [firstSwappingElement, secondSwappingElement], [], score)
                gameBoard[firstSwappingElement['x']][firstSwappingElement['y']] = firstSwappingElement['imageNum']
                gameBoard[secondSwappingElement['x']][secondSwappingElement['y']] = secondSwappingElement['imageNum']
            else:
                # A match
                scoreAdd = 0
                while matchedElements != []:
                    points = []
                    for elementSet in matchedElements:
                        scoreAdd += (10 + (len(elementSet) - 3) * 10)
                        for element in elementSet:
                            gameBoard[element[0]][element[1]] = EMPTY_SPACE
                        points.append({'points': scoreAdd,
                                       'x': element[0] * ELEMENTSIZE + XMARGIN,
                                       'y': element[1] * ELEMENTSIZE + YMARGIN})
                    score += scoreAdd

                    # Drop new elements
                    fillBoardAndAnimate(gameBoard, points, score)

                    # Check for new matches
                    matchedElements = findMatchingElements(gameBoard)
            firstSelectedElement = None

            if not canMakeMove(gameBoard):
                gameIsOver = True

        # Draw the board
        PLAYSURF.fill(BGCOLOUR)
        drawBoard(gameBoard)
        if firstSelectedElement != None:
            highlightSpace(firstSelectedElement['x'], firstSelectedElement['y'])
        if gameIsOver:
            if clickContinueTextSurf == None:
                clickContinueTextSurf = BASICFONT.render('Final Score: %s (Click to continue)' % (score), 1, GAMEOVERCOLOUR, GAMEOVERBGCOLOUR)
                clickContinueTextRect = clickContinueTextSurf.get_rect()
                clickContinueTextRect.center = int(WIDTH / 2), int(HEIGHT / 2)
            PLAYSURF.blit(clickContinueTextSurf, clickContinueTextRect)
        elif score > 0 and time.time() - lastScoreDeduction > DEDUCTSPEED:
            # score drops over time
            score -= 1
            lastScoreDeduction = time.time()
        drawScore(score)
        pygame.display.update()
        FPSCLOCK.tick(FPS)                

def getSwappingElements(board, firstXY, secondXY):
    # If the elements at the (X, Y) coordinates of the two elements are adjacent,
    # then their 'direction' keys are set to the appropriate direction
    # value to be swapped with each other.
    # Otherwise, (None, None) is returned.
    firstElement = {'imageNum': board[firstXY['x']][firstXY['y']],
                'x': firstXY['x'],
                'y': firstXY['y']}
    secondElement = {'imageNum': board[secondXY['x']][secondXY['y']],
                 'x': secondXY['x'],
                 'y': secondXY['y']}
    highlightedElement = None
    if firstElement['x'] == secondElement['x'] + 1 and firstElement['y'] == secondElement['y']:
        firstElement['direction'] = LEFT
        secondElement['direction'] = RIGHT
    elif firstElement['x'] == secondElement['x'] - 1 and firstElement['y'] == secondElement['y']:
        firstElement['direction'] = RIGHT
        secondElement['direction'] = LEFT
    elif firstElement['y'] == secondElement['y'] + 1 and firstElement['x'] == secondElement['x']:
        firstElement['direction'] = UP
        secondElement['direction'] = DOWN
    elif firstElement['y'] == secondElement['y'] - 1 and firstElement['x'] == secondElement['x']:
        firstElement['direction'] = DOWN
        secondElement['direction'] = UP
    else:
        # These elements are not adjacent and can't be swapped.
        return None, None
    return firstElement, secondElement

def getBlankBoard():
    # Create and return a blank board data structure.
    board = []
    for x in range(GRIDWIDTH):
        board.append([EMPTY_SPACE] * GRIDHEIGHT)
    return board

def canMakeMove(board):
    # Return True if the board is in a state where a matching
    # move can be made on it. Otherwise return False.

    # The patterns in oneOffPatterns represent elements that are configured
    # in a way where it only takes one move to make a triplet.
    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)))

    # The x and y variables iterate over each space on the board.
    # If we use + to represent the currently iterated space on the
    # board, then this pattern: ((0,1), (1,0), (2,0))refers to identical
    # elements being set up like this:
    #
    #     +A
    #     B
    #     C
    #
    # That is, element A is offset from the + by (0,1), element B is offset
    # by (1,0), and element C is offset by (2,0). In this case, element A can
    # be swapped to the left to form a vertical three-in-a-row triplet.
    #
    # There are eight possible ways for the elements to be one move
    # away from forming a triple, hence oneOffPattern has 8 patterns.

    for x in range(GRIDWIDTH):
        for y in range(GRIDHEIGHT):
            for pat in oneOffPatterns:
                # check each possible pattern of "match in next move" to
                # see if a possible move can be made.
                if (getElementAt(board, x+pat[0][0], y+pat[0][1]) == \
                    getElementAt(board, x+pat[1][0], y+pat[1][1]) == \
                    getElementAt(board, x+pat[2][0], y+pat[2][1]) != None) or \
                   (getElementAt(board, x+pat[0][1], y+pat[0][0]) == \
                    getElementAt(board, x+pat[1][1], y+pat[1][0]) == \
                    getElementAt(board, x+pat[2][1], y+pat[2][0]) != None):
                    return True # return True the first time you find a pattern
    return False

def drawMovingElement(element, progress):
    # Draw an element sliding in the direction that its 'direction' key
    # indicates. The progress parameter is a number from 0 (just
    # starting) to 100 (slide complete).
    movex = 0
    movey = 0
    progress *= 0.01

    if element['direction'] == UP:
        movey = -int(progress * ELEMENTSIZE)
    elif element['direction'] == DOWN:
        movey = int(progress * ELEMENTSIZE)
    elif element['direction'] == RIGHT:
        movex = int(progress * ELEMENTSIZE)
    elif element['direction'] == LEFT:
        movex = -int(progress * ELEMENTSIZE)

    basex = element['x']
    basey = element['y']
    if basey == ROWABOVEBOARD:
        basey = -1

    pixelx = XMARGIN + (basex * ELEMENTSIZE)
    pixely = YMARGIN + (basey * ELEMENTSIZE)
    r = pygame.Rect( (pixelx + movex, pixely + movey, ELEMENTSIZE, ELEMENTSIZE) )
    PLAYSURF.blit(ELEMENTIMAGES[element['imageNum']], r)

def pullDownAllElements(board):
    # pulls down elements on the board to the bottom to fill in any gaps
    for x in range(GRIDWIDTH):
        elementsInColumn = []
        for y in range(GRIDHEIGHT):
            if board[x][y] != EMPTY_SPACE:
                elementsInColumn.append(board[x][y])
        board[x] = ([EMPTY_SPACE] * (GRIDHEIGHT - len(elementsInColumn))) + elementsInColumn

def getElementAt(board, x, y):
    if x < 0 or y < 0 or x >= GRIDWIDTH or y >= GRIDHEIGHT:
        return None
    else:
        return board[x][y]

def getDropSlots(board):
    # Creates a "drop slot" for each column and fills the slot with a
    # number of elements that that column is lacking. This function assumes
    # that the elements have been gravity dropped already.
    boardCopy = copy.deepcopy(board)
    pullDownAllElements(boardCopy)

    dropSlots = []
    for i in range(GRIDWIDTH):
        dropSlots.append([])

    # count the number of empty spaces in each column on the board
    for x in range(GRIDWIDTH):
        for y in range(GRIDHEIGHT-1, -1, -1): # start from bottom, going up
            if boardCopy[x][y] == EMPTY_SPACE:
                possibleElements = list(range(len(ELEMENTIMAGES)))
                for offsetX, offsetY in ((0, -1), (1, 0), (0, 1), (-1, 0)):
                    # Narrow down the possible elements we should put in the
                    # blank space so we don't end up putting an two of
                    # the same elements next to each other when they drop.
                    neighborElement = getElementAt(boardCopy, x + offsetX, y + offsetY)
                    if neighborElement != None and neighborElement in possibleElements:
                        possibleElements.remove(neighborElement)

                newElement = random.choice(possibleElements)
                boardCopy[x][y] = newElement
                dropSlots[x].append(newElement)
    return dropSlots

1 个答案:

答案 0 :(得分:0)

这只是部分答案,以展示我在评论中建议的内容。我不确定你的gameBoard实际上是什么样的,所以你必须根据需要调整代码。

我在这个例子中使用了一个只填充字符串的电路板(你也可以使用常量WATER = 1FIRE = 2等或枚举。声音在字典中,元素作为键。如果你有一个匹配,找出它是哪个元素,然后使用它从dict中获取相关的声音并播放它。

ELEMENT_SOUNDS = {
    'water': WATER_SOUND,
    'fire': FIRE_SOUND,
    }

board = [
    ['water', 'fire', 'water'],
    ['fire', 'water', 'fire'],
    ['water', 'water', 'water'],
    ]

if match:
    # Figure out the kind of the matching element 'water' in this case.
    element_kind = 'water'
    ELEMENT_SOUNDS[element_kind].play()